godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.11k stars 69 forks source link

Add a method to get the impact force when a RigidBody hits another body #487

Open Wapit1 opened 4 years ago

Wapit1 commented 4 years ago

Describe the project you are working on

I have been working with physic game where the player hits a lot of body with held rigidbody and can't get more progress on the physic side of thing because of the lack of a consistant lightweight way of getting the impact force

Describe the problem or limitation you are having in your project

getting the impact force requires to constantly calculate the previous velocity, else you can't tell how fast the object hit one a other: the force is already reduce before you receive the signal and you thus get a very small number which isn't representative of the linear velocity before impact (due note that it 2D you have still a bit more force during the impact tick, but it is not that consistant, has it already lost a bit force )

Describe the feature / enhancement and how it helps to overcome the problem or limitation

having a consistant Vector of the impact strength will allow programmer to create easily system like sound of impact, realistic breakable object, multiplied knockback on rigidbody and other

Describe how your proposal will work, with code, pseudocode, mockups, and/or diagrams

having a parameter with the signal on_body_entered would allow the user to use it easily and should be , too my understanding of physics engine, not too hard to get has the physics engine already calculates the force being transferred to the other object so the number would only need to be exposed (and while your at it why not expose a few more value like the force lost in friction, the average of point of impact and the force a joint is applying to the rigidbody)

If this enhancement will not be used often, can it be worked around with a few lines of script?

It would be used often and can get worked around with a few line of code (keeping in a var the linear_velocity every tick), but it is required to be put on every rigidbody (has you want the force difference on impact for realistic result) and its is not that consistant, has the body might go through the object and then get pulled back

Is there a reason why this should be core and not an add-on in the asset library?

because having it has an add-on would be harder to implement and most developer would like the idea of easily have the possibility to have different impact sound based on impact strength, have damage dealt based on the force of the swinging weapon and thus be allowed to create loads of physic based emergent gameplay

Zireael07 commented 4 years ago

I have yet to see the

the body might go through the object and then get pulled back

case, but having a built in function would definitely make having various impact related systems much easier (e.g. deforming a visual mesh on impact like I do in my little car game)

fire commented 4 years ago

Is this related to https://github.com/godotengine/godot/pull/36008 ?

Wapit1 commented 4 years ago

Is this related to godotengine/godot#36008 ?

no, but I am always happy to see more physics control (I am personally waiting for active ragdoll - currently working with joint and ragdoll)

fire commented 4 years ago

I linked the wrong pr. This is active ragdolls. https://github.com/godotengine/godot/pull/28909

Wapit1 commented 4 years ago

yes I am waiting for this PR (although it is a separate issue) my current project is so because of the lack of physics data and reliable active ragdoll having the player smash stuff with is floppy arms

briansemrau commented 4 years ago

Is this the same as #409? That feature request describes the ability to use RigidBody2D contact monitoring to get the collision impulse. *Edit: This FR appears to be for 3D, the one I linked is for 2D.

Jimmio92 commented 3 years ago

If anyone else encounters this, I worked around this limitation by keeping track of the previous velocity, and on body_entered signal, using the difference between the previous _physics_process' velocity and the current one as a way to determine "force" (at least well enough to make hit sounds work) as it seems to run the signal after taking account for the hit

MrMinimal commented 7 months ago

If anyone else encounters this, I worked around this limitation by keeping track of the previous velocity, and on body_entered signal, using the difference between the previous _physics_process' velocity and the current one as a way to determine "force" (at least well enough to make hit sounds work) as it seems to run the signal after taking account for the hit

That doesn't work for rotating objects. Their impace force can be multiple times the force of just the velocity difference. Still a very valdid proposal.

graphnode commented 4 months ago

That doesn't work for rotating objects. Their impace force can be multiple times the force of just the velocity difference. Still a very valdid proposal.

Could also keep track of angular velocity but...

I haven't tried but getting the body state and then do the dot product between collision normal and collision velocity multiplied by the other collider mass might give better results.

jitspoe commented 2 months ago

Here's how I approached it:

# On the rigid body:
func _integrate_forces(state : PhysicsDirectBodyState3D):
    for contact_index in state.get_contact_count():
        var object_hit := state.get_contact_collider_object(contact_index)
        if (is_instance_valid(object_hit)): # To fix a case where an object hits the player as player is deleted during level transition (intermission)
            Physics.handle_rigid_body_collision(self, object_hit, state.get_contact_collider_position(contact_index), state.get_contact_local_velocity_at_position(contact_index), state.get_contact_impulse(contact_index))

# And in my physics Autoload:
static func handle_rigid_body_collision(object : PhysicsProp, object_hit : Node3D, position : Vector3, velocity : Vector3, impulse : Vector3):
    # TODO: Sometimes impulse is 0, 0, 0, even though there is a solid impact.  Jolt bug?
    if (impulse.length_squared() > MIN_IMPULSE_RESPONSE_SQUARED):
        Combat.handle_rigid_body_hit(object, object_hit, velocity, impulse)
        var speed_change := impulse.length() / object.mass
        SoundSystem.play_physics_impact_sound(object, position, speed_change)

Still, it would be great to have a general purpose callback with the impulse whenever a collision happened so things like impact sounds and such could be implemented without having a ton of extra script in performance-critical areas like physics.