godotengine / godotengine/godot
PhysicsDirectBodyState2D: Reported values of `get_contact_impulse` not as expected
- Dominant language
- C++
- Stars
- 117k
- Forks
- 26.8k
- PR merge metrics
- PR metrics pending
Description
### Tested versions
Tested in:
- v4.2.1.stable.official [b09f793f5]
- v4.0.4.stable.official [fc0b241c9]
### System information
Godot v4.2.1.stable - macOS 14.1.2 - Vulkan (Forward+) - integrated Apple M2 Pro - Apple M2 Pro (10 Threads)
### Issue description
#### Context:
I try to make breakable objects and wanted to use [get_contact_impulse](https://docs.godotengine.org/en/stable/classes/class_physicsdirectbodystate2d.html#class-physicsdirectbodystate2d-method-get-contact-impulse) for this case do detect "hits".
#### Problem:
How strong the impulses are seem almost random ... but is hard to test in a reproducible way
#### My physics lab setup 😂:
- All boxes are the same (mass, gravity scale, etc.)
- The top text shows the highest recorded accumulated impulse (sum of all impulses in one `_integrate_forces`-cycle)
- The lower text shows the highest recorded speed (length of linear-velocity)
- Distances setup:
- The first box has no distance to the ground
- The second has 1px distance
- The next three are arbitrary
- The last two have the same distance to the ground
#### Outcome:
- Velocity does not linearly correlate to impulse (but it should ... I think?):
- Box 1 has no speed but an impulse
- Box 2 has a impulse/speed ratio of 1.55
- Box 3 has a impulse/speed ratio of 1.19
- Box 6 and 7 don't have the same impulse but I guess they should as they have the same fall height and weight (since I sum impulses)
#### Note
I am not 100% sure if these are bugs or I am misunderstanding the concept of what `get_contact_impulse` is reporting.
### Steps to reproduce
I recommend making a similar physics setup and playing around. Make sure you turn on `contact_monitoring` and set a value for `max_contacts_reported`.
I used the following code to track values:
```
extends RigidBody2D
var highest_speed := 0.0
var highest_impulse := 0.0
func _physics_process(delta):
var speed = linear_velocity.length()
if speed > highest_speed:
highest_speed = speed
$Velocity.text = str(snapped(highest_speed, 0.1))
func _integrate_forces(state):
var total_impulse := 0.0
for i in range(state.get_contact_count()):
var collided_obj = state.get_contact_collider_object(i)
var impulse = state.get_contact_impulse(i).length()
total_impulse += impulse
if total_impulse > highest_impulse:
highest_impulse = total_impulse
$Impulse.text = str(snapped(highest_impulse, 0.1))
```
### Minimal reproduction project (MRP)
[bug-contact-impulse.zip](https://github.com/godotengine/godot/files/14763971/bug-contact-impulse.zip)
Contributor guide
Research direction
Start by running the linked bug-contact-impulse.zip minimal reproduction with contact_monitoring and max_contacts_reported enabled. Inspect the PhysicsDirectBodyState2D.get_contact_impulse behavior used from _integrate_forces, compare the reported impulses with the documented semantics, and determine whether the mismatch is an engine bug or an expected result. Done means the behavior is explained and, if incorrect, covered by an appropriate regression test and fix.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- game-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100