_on_body_entered fires again after respawn

Godot Version

4.2

Question

(first time on the forum, can post some code in follow up messages)

Working through the “How to make Asteroids in Godot 4” video tutorial of Kaan Alpar, I run into issues with the “body_entered” event firing twice sometimes.
Current logic in the “body_entered” (_on_body_entered function on the asteroid) is to call “body:die(self)” (passing in the asteroid that killed it; body is a Player)

The Player.die() function flips the “alive” boolean to false (if it is currently true), signals “died”, and sets "process_mode = Node.PROCESS_MODE_DISABLED.

The “died” signal is picked up by the main scene, which calls Player.respawn() if there’s lives left, or does the game-over handling.

Player.respawn sets the new position of the player and sets process_mode = Node.PROCESS_MODE_INHERIT

I have added some logging to show the actual distance between the asteroid and the player, and the second time it fires the distance is way bigger than the collision distance (as expected, because the player respawns at the starting location, which is far away from the global_position where the collision happened)

Is the change of process_mode reason to cause additional “body_entered” signals, or is there another cause for these unexpected multiple signals?

(I’d hate to have to add my own distance calculations inside the “body_entered” to validate/verify if there’s a true collision - that would defeat the whole purpose of these signals would it not?)

Some more background info: I tried with 2D physics engine “DEFAULT” and “GodotPhysics2D”, no difference.

Log output that I generated:

Godot Engine v4.2.2.stable.official.15073afe3 - https://godotengine.org
Vulkan API 1.3.224 - Forward+ - Using Vulkan Device #0: NVIDIA - NVIDIA GeForce RTX 4060 Ti
 
start
3
1716968961.44229 Player hit Asteroid4
I am at (1049, 131.7971), player is at (1020.587, 55.59958)distance is 81.9739151000977 collisionSize is 82.0191993713379
1716968961.44248 die
Death by Asteroid4
dying
2
1716968963.44311 respawn
resurrected
1716968963.47565 Player hit Asteroid4
I am at (1049, 49.01567), player is at (617.4174, 375.2361)distance is 535.998962402344 collisionSize is 82.0191993713379
Too far, won't kill player
--- Debugging process stopped ---

Asteroid._on_bodu_entered function:


func _on_body_entered(body: Player):
	if body:
		print(Time.get_unix_time_from_system(), " ", body.name," hit " + self.name)
		var dist = global_position.distance_to(body.global_position)
		var collisionDist = cshape.shape.radius + body.cshape.shape.radius
		print("I am at ", cshape.global_position, ", player is at ", body.cshape.global_position, "distance is ", dist, " collisionSize is ", collisionDist)
		if body.alive:
			if dist <= collisionDist + 2:
				body.die(self)
			else:
				print("Too far, won't kill player")
		else:
			print("I see it's already dead")
	else:
		print("was not a player")

Player.die function:

func die(sourceOfDeath: Asteroid):
	print(Time.get_unix_time_from_system(), " die")
	if alive:
		print("Death by " + sourceOfDeath.name)
		alive = false
		# move off screen to prevent additional hit during respawn
		global_position = Vector2(-1000,-1000)
		print("dying")
		emit_signal("died")
		process_mode = Node.PROCESS_MODE_DISABLED
	else:
		print("Death by " + sourceOfDeath.name)
		print("already dead")

Player.respawn function:


func respawn(pos):
	print(Time.get_unix_time_from_system(), " respawn")
	if !alive:
		alive = true
		global_position = pos
		velocity = Vector2.ZERO
		angular_speed = 0
		print("resurrected")
		process_mode = Node.PROCESS_MODE_INHERIT
	else:
		print("already alive")

I have also tried changing the process_mode at different places in the functions (i.e. as the very first or the very last statement), but the double-fire of “body_entered” occurs in any combination (but it does not occur all the times, sometimes it takes a few lives before a double-fire occurs).

:man_facepalming:
I should have waited until I finished the whole video. The solution is in there (around 1:40:00) - https://www.youtube.com/watch?v=FmIo8iBV1W8

Basically, when the player dies, it’s position has to be set to a “safe” place, preventing it being hit again by the same asteroid at it’s old location.

1 Like