RigidBody2D collision position moves unexpectedly away from collision point

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

I have a small Rigidbody2D icon that shoots Rigidbody2D bullets at a large Rigidbody2D icon. All rigidbodies have scale (1,1). Upon collision, the bullet spawns two sprites: a red burst to show the position of RigidBody2D.body_enter signal, and a green burst to show the position of state.get_contact_local_pos() method of the _integrate_forces function. So far no problem:

gif of explanation

The large icon is initially situated at origin (0,0), and the bullets slowly push it across the screen as intended. However, as the large icon moves, the collision bursts unexpectedly move in the same direction away from the collision point:

gif of linear movement

And things get strange when the large icon is rotated:

gif of rotational movement

The bullets are fired with the apply_impulse method as follows:

func _fire_bullet():
	var bullet = bullet_res.instance()
	bullet.set_pos(self.get_global_pos())
	bullet.set_z(1)
	self.get_parent().add_child(bullet)
	bullet.apply_impulse(Vector2(),Vector2(-1,0) * 500)

The red burst is created in the body_enter signal as follows:

func _body_enter(body):
	var red_burst = red_burst_res.instance()
	red_burst.set_pos(body.get_global_pos())
	self.add_child(red_burst)
	body._remove_bullet()

The green burst is created in the _integrate_forces function as follows:

func _integrate_forces(state):
	if (state.get_contact_count() > 0):
		var green_burst = green_burst_res.instance()
		green_burst.set_pos(state.get_contact_local_pos(0))
		self.add_child(green_burst)

Why are the collision positions moving away from the collision point?

Download link to example project: https://drive.google.com/file/d/0BwnfZQAEnciAek1oNW5NbG5rcEE/view?usp=sharing

:bust_in_silhouette: Reply From: Bojidar Marinov

You are actually hitting two problems here…

The first problem is that physics run behind logic (_fixed_process) for performance issues, as explained here: Collision detection at startup issue · Issue #4959 · godotengine/godot · GitHub

The second problem is that you are giving local coordinates (relative to their parent) to the bursts, while the engine gives you global coordinates – that’s why the appear to move.

Thank you for the link and for the tip regarding local & global coordinates. I am posting the solution as an answer for better visibility.

As for the issue of physics running one frame behind logic, it is totally understandable and is actually welcomed if it improves performance.

ericdl | 2016-06-02 20:12

:bust_in_silhouette: Reply From: ericdl

This was solved based on Bojidar Marinov’s tip regarding local vs. global coordinates. Actually it feels like more of a workaround, but the solution was to simply parent the bursts to the base node of the scene instead of the large icon. So instead of instancing a burst with self.add_child(green_burst), it should be self.get_parent().add_child(green_burst) as long as get_parent() points to the base node of the scene. And it works as expected:

gif solved

I suspect there may be a way of instancing a burst without parenting it to the scene root, by using transform/xform math… But that is beyond my skillset at this time.