|
|
|
|
Reply From: |
mafious |
Hello, and welcome to Godot Q&A
CollisionShape2D (and children) are editor helper nodes, meaning that it does not actually exist at runtime (or didn’t), therefore changing it via script does nothing after the Physics body has used it.
The one way I found to work around this was by defining a prototypical shape, saving it it as a .res, preloading it. Then you have to duplicate and scale it at runtime, and call set_shape on your PhysicsBody2D, as such:
var protoshape = preload("res://shape.res");
var shape = protoshape.duplicate();
shape.set_radius(shape.get_radius()*factor);
self.set_shape(0,shape);
There may be a simpler way, but I can confirm this works.
Hi, thank you for the answer, but I can not get it to work. When I load the shape from a resource it still falls through the ground. Any ideas why this is happening?
Eyeball Monkey Media | 2016-06-07 11:19
In the code you wrote here you are adding the shape to the Collisions Hape, you should try adding it to the (kinematic) body, see if that works
mafious | 2016-06-07 11:43
I believe I am adding it to the KinematicBody2D. The edited script is below. The script is called by a ViewportSprite which is the root node of the scene.
extends ViewportSprite
var factor = 1
func _ready():
createPlayer()
func createPlayer():
var playerBody = KinematicBody2D.new()
var playerSprite = Sprite.new()
var gameCamera = Camera2D.new()
var protoshape = preload("res://shape.res");
playerSprite.set_texture(load("res://Textures/Game/blue_circle.tex"))
playerBody.add_child(playerSprite)
var shape = protoshape.duplicate();
shape.set_radius(shape.get_radius()*factor);
playerBody.set_shape(0,shape);
playerBody.set_name("Player")
playerBody.set_pos(Vector2(96, 512))
playerBody.add_child(gameCamera)
playerBody.set_script(load("res://Scripts/Game/player.gd"))
self.add_child(playerBody)
gameCamera.make_current()
Eyeball Monkey Media | 2016-06-07 18:40
It looks like it should work as it is, I would scrutinize the values of the variables both inside the shape.res and the ground you’re trying to collide with.
Try to set can_sleep to false (set_can_sleep(false)) on both bodies, if nothing (i.e. Gravity) is moving the bodies they may have slept.
mafious | 2016-06-08 18:26
The ground is a TileMap, and the player is a KinameticBody2D. The player falls, but it falls through the ground and that does not happen when I create the player in the GUI using the same script to move the player.
Eyeball Monkey Media | 2016-06-08 18:33
!!!UPDATE I didn’t realize that you’re using a KinematicBody2D, physics don’t work on them
like other bodies, head over to http://docs.godotengine.org/en/latest/tutorials/2d/kinematic_character_2d.html?highlight=kinematic%20character and see if it helps you at all
Other than that, I would scrutinize the values of the variables both inside the shape.res and the ground you’re trying to collide with. Try to set can_sleep to false (set_can_sleep(false)) on both bodies, if nothing (i.e. Gravity) is moving the bodies they may have slept.
mafious | 2016-06-08 18:35
It could be that creating through the GUI sets some variables that we forget to set via code, as well.
mafious | 2016-06-08 18:37
I can not find cansleep in the kinematic body. The function ‘set_can_sleep’ does not appear to exist. The link above is where I built my player script from. I added it below. Thanks again for all of your help.
extends KinematicBody2D
const GRAVITY = 750.0
const FAST_SPEED = 400
const NORMAL_SPEED = 200
var WALK_SPEED = 200
const JUMP_SPEED = 325
var velocity = Vector2()
var onGround = true
var hasEnded = false
var running = false
var left
var right
var jump
var fast
var gcp
var gp
var killed = false
var killJumped = false
var levelsFilePath = "user://levels.config"
func _fixed_process(delta):
if !hasEnded:
if fast.get_toggle_pressed() or Input.is_key_pressed(KEY_CONTROL):
WALK_SPEED = FAST_SPEED
else:
WALK_SPEED = NORMAL_SPEED
velocity.y += delta * GRAVITY
if (Input.is_key_pressed(KEY_LEFT) or left.is_pressed()):
velocity.x = -WALK_SPEED
elif (Input.is_key_pressed(KEY_RIGHT) or right.is_pressed()):
velocity.x = WALK_SPEED
else:
velocity.x = 0
if onGround and (Input.is_key_pressed(KEY_SPACE) or jump.is_pressed()):
velocity.y -= JUMP_SPEED
var motion = velocity * delta
motion = move(motion)
onGround = false
var collider = get_collider()
if (is_colliding()):
if collider == get_parent().get_node("House/StaticBody2D"):
complete()
var p = get_pos()
var cp = get_collision_pos()
gcp = cp
gp = p
var n = get_collision_normal()
motion = n.slide(motion)
velocity = n.slide(velocity)
move(motion)
if abs(cp.y - p.y) >= (abs(cp.x - p.x) - 5) and cp.y > p.y: #5 is buffer for how far off the middle it can be
if !running:
print("Start timer")
get_node("Timer").start()
running = true
elif killed:
if killJumped:
var collisionShape = get_node("PlayerShape")
collisionShape.set_trigger(true)
velocity.y += delta * GRAVITY
var motion = velocity * delta
motion = move(motion)
onGround = false
if (is_colliding()):
var p = get_pos()
var cp = get_collision_pos()
var n = get_collision_normal()
motion = n.slide(motion)
velocity = n.slide(velocity)
move(motion)
else:
velocity.y -= JUMP_SPEED
velocity.y += delta * GRAVITY
var motion = velocity * delta
motion = move(motion)
onGround = false
if (is_colliding()):
var p = get_pos()
var cp = get_collision_pos()
var n = get_collision_normal()
motion = n.slide(motion)
velocity = n.slide(velocity)
move(motion)
killJumped = true
elif !killed and hasEnded:
var flag = get_parent().get_node("House/Flag")
if flag.get_pos().y > -128:
flag.set_pos(Vector2(flag.get_pos().x, flag.get_pos().y - 4))
func complete():
hasEnded = true
get_parent().get_node("Player").hide()
get_parent().get_node("House/Flag").show()
get_node("Timer").start()
func kill():
hasEnded = true
killed = true
velocity.x = 0
get_node("Camera2D").clear_current()
get_node("Timer").start()
func _ready():
left = get_parent().get_node("gui/Left")
right = get_parent().get_node("gui/Right")
jump = get_parent().get_node("gui/Jump")
fast = get_parent().get_node("gui/Fast")
if Globals.has("TSButtons"):
if !Globals.get("TSButtons"):
left.hide()
right.hide()
jump.hide()
fast.hide()
set_fixed_process(true)
func _on_Timer_timeout():
var levelsFile = ConfigFile.new()
levelsFile.load(levelsFilePath)
levelsFile.set_value(Globals.get("WorldNum"), Globals.get("LevelNum"), true)
if levelsFile.has_section_key(Globals.get("WorldNum"), "Latest"):
var num = int(levelsFile.get_value(Globals.get("WorldNum"), "Latest"))
if num < int(Globals.get("LevelNum")):
levelsFile.set_value(Globals.get("WorldNum"), "Latest", int(Globals.get("LevelNum")))
else:
levelsFile.set_value(Globals.get("WorldNum"), "Latest", int(Globals.get("LevelNum")))
levelsFile.save(levelsFilePath)
get_node("Camera2D").make_current() #Make camera switch to default when scene is switched
get_node("/root/globals").setScene("res://Scenes/Game/menu/w1.scn")
func timer():
running = false
var p = gp
var cp = gcp
if abs(cp.y - p.y) >= (abs(cp.x - p.x) - 5) and cp.y > p.y: #5 is buffer for how far off the middle it can be
onGround = true
print(onGround)
Eyeball Monkey Media | 2016-06-08 21:58
I’ll try recreating this, getting to something that works and will try to report back in a bit
mafious | 2016-06-09 21:45