KinematicBody2D doesn't react on colliding properly

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By ezangillz
:warning: Old Version Published before Godot 3 was released.

Hey guys, I got two things on the scene: KinematicBody2D as a player and RigidBody2D as an enemy. Whenever player touches an enemy he should disappear and then appear in the beginning of the current level. I got this function in character’s script:

func hit():
	var PLAYER_SCENE = load("res://Assets/prefabs/dynamic/player.tscn")
	queue_free()
	var player = PLAYER_SCENE.instance()
	player.set_pos(Vector2(0,0))
	get_tree().get_root().add_child(player)

And it just loads scene with character, frees current character object and instantiates new character object in (0;0) position.

And enemy got this script:

extends RigidBody2D

var head

func _ready():
get_node(“Area2D”).connect(“body_enter”, self, “_collision”)

func _collision(body):
if (body.get_name() == “Player”):
body.hit()


And it checks whether enemy collides with player and if so, calls hit function which I described before.

So the thing is that it works first two times. After my character dies second time and appears in the beginning of the level it stops reacting on colliding with enemy object and doesn’t disappear, why is that?

:bust_in_silhouette: Reply From: jackmakesthings

Is it possible that things are being added/removed in such an order that the name of your player node isn’t always “Player”? IE, if you try to add a new instance of player before the existing one is freed, you might end up with a node called “Player 1” instead of “Player”. I’d recommend running the scene from the editor and taking a look at the Scene Tree (in the Output/Debugger area) to see if this is what’s happening.

If that is the case, one way you can avoid this is to change how you verify that a node is the player. Instead of this:

if body.get_name == 'Player':

you can reference the actual script that goes with the player (assuming it’s not a built-in one; if it is, this might be tricky, so I’d recommend saving it as a unique script file first.)

Anyway, if your player script is player.gd, you could replace the line above with this:

if body extends 'res://path/to/player.gd':

(substitute the actual path to your script, of course)

Or, if that doesn’t work (I’m not sure how well extends plays with the actual script on a node; usually I would define a script like player.gd and then have a script on the player node that just extends that), try this:

if body.get_script().get_path().find('player.gd'):

In either case, it doesn’t actually matter what the node is called. If it behaves like a Player, it’ll get handled as a Player.

Thanks for selecting this! Another option I just realized I forgot - if you’ve defined a custom method for your Player, let’s call it walk_to_NPC, you can check for the Player identity with if body.has_method('walk_to_NPC'). You can also check on properties (member vars).

jackmakesthings | 2016-08-15 13:16

Just wanted to thank you for the .has_method() function. Worked perfectly! I was suffering the same issues you were and that helped me define which of my bats (out of Left and Right) that I was interacting with.

Robster | 2017-03-23 23:42