BUG: Pausing breaks move_and_collide collision detection

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By gameaddict24

I have two KinematicBody2D nodes with circle collision shapes. Body1 stays in one spot calling move_and_collide(Vector2.ZERO) every _physics_process. Body2 is initially colliding with Body1 and then every _physics_process calls move_and_collide to move away from Body1.

If Body1 detects a collision it calls get_tree().set_deferred("paused", true), waits one second, then unpauses. It then enters an infinite loop, detecting a collision on every physics step, even as you can see Body2 moving farther and farther from Body1.
If I comment out the line that pauses the scene tree, only 1 collision is detected and the scene works as expected.

Am I missing something or is this a bug? Any workaround?

Below is the code for Body1:

extends KinematicBody2D

func freezeFrame(duration):
	get_tree().set_deferred("paused", true)
	yield(get_tree().create_timer(duration), "timeout")
	get_tree().paused = false

func _physics_process(delta):
	if move_and_collide(Vector2.ZERO):

EDIT: Here’s a link to the example project. Please enable Visible Collision Shapes in the Debug menu. If you run the project you’ll see the infinite loop I’m talking about. If you comment out the line that paused the tree it runs perfectly.

Created a new Issue on this: https://github.com/godotengine/godot/issues/60577

gameaddict24 | 2022-04-28 16:47

:bust_in_silhouette: Reply From: Inces

I am not sure if I understand, but is it that You want to pause only one node ?
Setting Tree.paused pauses whole tree and mutliple functionality of built-in servers. Whole PhysicsServer also becomes paused, and collision detection along with it. Collision shapes will not work because of this, even if they are set to ignore pause. The only thing, that doesn’t get paused are actually dynamic timers, which is rarely beneficial. If You want to pause just one body, You will have to do it manually, design what is supposed to be frozen among this body functions.

Thanks for responding, no I’m not trying to pause only one node, I’m trying to pause the entire screen for a short period, then resume as normal.

For context, I want to freeze the frame on collision to produce a hit-stop kind of effect.
What should happen in my eyes is

  1. A collision is detected
  2. The physics frame finishes, resolving the collision
  3. The tree is paused (from the deferred set call earlier)
  4. One second passes
  5. The tree is unpaused
  6. The collision is no longer detected (as the 2nd body has been moved)

What I’m seeing is that on step 6 above, the collision is still detected on every subsequent _physics_process call after unpausing.

gameaddict24 | 2022-04-27 13:55

I see
You are calling yield in subroutine coming from physics process. I suspect freezeframe() receives a large chunk of calls before deferred frame, so it repeats pausing and unpausing in duration intervals for quite some time. But not infinitely. Did You try to pause without deferring ? If this doesn’t work or You can’t, try to fit whole code in physics_process, without subroutine.

Inces | 2022-04-27 15:01

No dice, if I set the paused = true immediately, the physics process is cut off and the 2nd body never gets to move, so the collision is always happening.

I tried moving the code out of the subroutine and into the _physics_process but it has the same exact result. I don’t think the issue is a large number of buffered pauses because if I add print to the function I see the prints happening once per _physics_process
Also I see the 2nd body continuously moving away with each pause/unpause cycle.

gameaddict24 | 2022-04-27 15:22