Posts
Search
Contact
Cookies
About
RSS

Godot - determining collision velocity

Added 14 Sep 2026, 9:02 p.m. edited 14 Sep 2026, 10:03 p.m.

I had a problem where I noticed that after you are informed of a collision, your linear velocity has already been effected by the collision, not so handy !

Initially I just tracked the previous frames velocity for the player, and for deltas past a limit I applied damage, this worked just fine, till I realised that it doesn't account for the velocity of other bodies...

As I was dealing with a decent number of RigidBody3D derived props, I didn't want to add the previous velocity tracking to each one, and what might happen if I forgot to add one to an existing or even new rigid body derivative....?

Then it hit me, if I tracked nodes being added to the "world" then I could track velocity for all rigid body derived classes, in one place.

As it happened I already had an autoload script which is responsible to destroying old levels and adding the next level to its scene tree etc, this would be a great place to add rigid body tracking.

If you don't have an autoload script, you can always add a dedicated autoload script just for the velocity tracking.

First we need some utility functions, on registering a body we add the body to an array, and also a dictionary of velocities indexed on the bodies instance id, we also connect to tree_exited passing an additional body parameter, the body exited signal allows us to remove bodies from the array and dictionary.

func _register_body(body: RigidBody3D) -> void:
if rigid_bodies.has(body):
return

rigid_bodies.append(body)
previous_velocities[body.get_instance_id()] = body.linear_velocity

body.tree_exited.connect(_on_body_exited.bind(body))

a function to register a node that is added is needed too

func _on_node_added(node: Node) -> void:
if node is RigidBody3D:
_register_body(node)

there is also a function to register any bodies that might exist as we kick off things, this is likely not needed but I put it at the end of the autoloads _ready function

In the _physics_process we update our tracked bodies

func _physics_process(_delta: float) -> void:

for body in rigid_bodies:
if is_instance_valid(body):
previous_velocities[body.get_instance_id()] = body.linear_velocity

and finally for our singleton a function to get previous velocity for bodies

func get_previous_velocity(body: RigidBody3D) -> Vector3:
if !is_instance_valid(body):
return Vector3.ZERO

return previous_velocities.get(
body.get_instance_id(),
Vector3.ZERO
)

Currently the only body I'm tracking damage for is the player, so lets look at the players code

Here MainScene is my autoload script (where the code above lives)

var was_colliding = false

func _integrate_forces(state: PhysicsDirectBodyState3D) -> void:
var contact_count = state.get_contact_count()
var is_colliding = contact_count > 0

if is_colliding and !was_colliding:
var my_previous_velocity:Vector3 = MainScene.get_previous_velocity(self)
var collision_speed:float = 0
for i in contact_count:
var other_body = state.get_contact_collider_object(i)

var other_previous_velocity = Vector3.ZERO

if other_body is RigidBody3D:
other_previous_velocity = \
MainScene.get_previous_velocity(other_body)

var relative_velocity = \
my_previous_velocity - other_previous_velocity
var relative_magnitue:float = relative_velocity.length()
if relative_magnitue > collision_speed:
collision_speed = relative_magnitue


# scale and clamp collision speed for damage and damage sound

Note that if the other collision object isn't a rigid body (like scenery) we still calculate collision speed just with a velocity of zero (it is static!)

I knew attempting to look at contact impulses was at best an indication of the collision speed, but this method is much more robust and provides consistent results.

Obviously we are paying a price for this convenience, each player collision there are a bunch of dictionary lookups, but generally each contact seems to give me usually in the order of 4-8 contacts so not terrible, as its only on the players collision, as for updating the previous velocities well that's a dictionary edit each rigid body every frame, actually really not that bad... 

I hope you found this useful.

Enjoy!