How to know the velocity of two collision bodies when collided?

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

I have two RigidBody2D (and maybe there are more PhysicsBody2D around) that I want to:

  1. Check if they have collided.
  2. Know the collision velocity at contact point of each body.
  3. Based on both velocities (magnitude and direction) compared to the normal vector of collision, decide which body hit the other body.

I can use _integrate_forces(Physics2DDirectBodyState state ) and reading the state I can know the list of colliders (get_colliding_bodies), the collision contact position for each one of the colliders (state.get_contact_collider_pos), and the velocity of the body at the contact point (state.get_contact_collider_velocity_at_pos).

I even could now the Object of one of the colliders (state.get_contact_collider_object). Even I can imagine that I detect the object in the list of colliders and it is the other body that I want to check its velocity.

How can I know the velocity on contact point of the other collider? I guess I can’t directly call _integrate_forces so once I have detected the collider I’m interested in, how can I know its velocity at the colliding point?

:bust_in_silhouette: Reply From: mateusak

Using a test_motion() would result in a Physics2DTestMotionResult which may have what you want. See here.

:bust_in_silhouette: Reply From: Ethan Duggan

use a var called velocity_last_frame or something like that
at the end of _fixed_process() set velocity_last_frame = get_linear_velocity()
When 2 physics bodies collide their velocities are changed in the frame in which they collide, before any _fixed_process() runs, so using get_linear_velocity() when a collision happens will return the new, post-collision velocities. But if you always have the velocity from the last frame, you will have the velocities from right before the collision.

:bust_in_silhouette: Reply From: WarpedWarpDrive

To anyone from the future who is looking for how to designate a “hitter” and “hittee” and find the collision force after a collision as I was, here is the code that does that.

Firstly, in the physics process or integrate physics (Whichever you use) paste the following code:

previous_velocity = current_velocity
current_velocity = self.linear_velocity

Next, go to the physics object’s node and access its signals. Connect the node’s _on_body_entered signal to itself, and find the newly made function in its script, and set it to this:

func _on_Object_body_entered(body):
var hit_force = 0
var hitter = false
if body is RigidBody2D:
	if body.get_index()>self.get_index():
		if body.previous_velocity == Vector2.ZERO:
			hitter = true
			hit_force = self.previous_velocity.length()*body.mass
		elif self.previous_velocity == Vector2.ZERO:
			hitter = false
			hit_force = body.previous_velocity.length()*body.mass
		else:
			var hit_velocity = (body.previous_velocity - self.previous_velocity.project(body.previous_velocity)).length()
			var enemy_hit_priority
			var our_hit_priority
			var collision_angle = abs(sin(previous_velocity.angle_to(body.previous_velocity)*0.5))
			if collision_angle == 0:
				enemy_hit_priority = body.previous_velocity.length()
				our_hit_priority = self.previous_velocity.length()
			else:
				enemy_hit_priority = body.previous_velocity.length()*(body.mass*collision_angle)
				our_hit_priority = self.previous_velocity.length()*(self.mass*collision_angle)
			if enemy_hit_priority > our_hit_priority:
				hitter = false
			else:
				hitter = true
			hit_force = hit_velocity*body.mass
		on_hit(hit_force,hitter)
		body.on_hit(hit_force,not hitter)

Now just make the on_hit(hit_force, is_hitter) function referenced in the code and you’re done!

Is it gross? Sure. Is it uncommented because I’m lazy? Yup. Does it work after DAYS OF SEARCHING? Certainly.