godotengine / godotengine/godot

PhysicsDirectBodyState2D: Reported values of `get_contact_impulse` not as expected

Open
#89,921 3 comments 3 reactions 0 assignees View on GitHub
bug confirmed topic:2d topic:physics
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

Screenshot 2024-03-26 at 20 37 37

#### 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)
Screenshot 2024-03-26 at 20 38 15

#### 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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.