How to get the impulse vector at collision of two RigidBody2D's

Godot 4.2.1

Question

In my game, I want enemies to take damage scaled by how hard they were hit, ie the impulse vector that the weapon applied to the enemy. Both the enemies and the weapons are RigidBody2D’s.

I thought the value I needed would be the return of `get_contact_impulse()`, based on the method’s desscription. I wrote this code in the enemy’s script:

``````func _integrate_forces(state):
for i in range(state.get_contact_count()):
var weapon = state.get_contact_collider_object(i)
if weapon is Weapon:
var damage = clamp(remap(state.get_contact_impulse(i).length(), damage_min_speed, damage_max_speed, 0, weapon.damage), 0, weapon.damage)
\$HealthComponent.take_damage(damage, weapon.faction)
``````

However, `state.get_contact_impulse(i)` returns a zero vector. How do I get the impulse vector of the collision?

I believe this is this bug: PhysicsDirectBodyState3D.get_contact_impulse() returns zero vector on first frame of collision · Issue #73541 · godotengine/godot · GitHub
Good news is it appears it’ll be fixed in 4.3
Edit: sorry, you said 2d, not 3d… from that issue link, though, it looks like the bug affects both

2 Likes

is there a workaround while I’m waiting for 4.3?

I found a workaround.

In `_physics_process` of enemy:

``````func _physics_process(delta):
_prev_velocity = _this_velocity
``````

in `_integrate_forces` of enemy:

``````func _integrate_forces(state):
_this_velocity = linear_velocity

if _take_damage:
var impulse = mass * (linear_velocity - _prev_velocity)
var damage_taken = clamp(remap(impulse.length(), damage_min_speed, damage_max_speed, 0, _take_damage_amount), 0, _take_damage_amount)
health_component.take_damage(damage_taken, _take_damage_faction)

_take_damage = false
``````

By storing the previous velocity, I can subtract the current velocity from the previous velocity to get the acceleration, then multiply by mass to get force. This must be done in `_integrate_forces`, because `linear_velocity` will not have updated in `physics_process` or on collision.

Side note, I moved the detection of collision to the weapon, which calls a `take_damage` function of enemy, which sets `_take_damage`, `_take_damage_amount` and `_take_damage_faction`, each of which are member variables. This allows `_integrate_forces` to know the damage information and when to take damage. This is pretty inelegant, I wish there was a signal for when physics has finished calculating so I could just use `await physics_processed` in `take_damage`.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.