godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.17k stars 98 forks source link

Include 2D collision impulse in contact monitoring #409

Open briansemrau opened 4 years ago

briansemrau commented 4 years ago

Describe the project you are working on: 2D physics-based asteroids. Player avoids asteroids and uses incoming asteroids to collide with and destroy enemy spaceships in pursuit.

Describe the problem or limitation you are having in your project: RigidBody2D contact monitoring does not provide the collision impulse, which is needed to calculate player/enemy damage as a result of asteroid collisions.

Describe how this feature / enhancement will help you overcome this problem or limitation: Using this feature, I could use RigidBody2D contact monitoring within _integrate_forces to access collision impulse and apply damage to characters.

Show a mock up screenshots/video or a flow diagram explaining how your proposal will work: I presume diagrams not needed? Essentially identical to Unity's Collision.impulse.

Example of usage:

func _integrate_forces(state: Physics2DDirectBodyState):
    for idx in range(state.get_contact_count()):
        var impulse: Vector2 = state.get_contact_impulse(idx)
        # TODO: damage(impulse.length())

Describe implementation detail for your proposal (in code), if possible: Contacts are reported to the bodies in BodyPair2D setup, and the impulse is calculated and applied during the constraint solve. Solution 1: I think that recording the contact during the solve phase rather than the setup phase would allow recording the impulse used to solve the collision Solution 2: Add an impulse calculation to the setup phase so it can be recorded with the rest of the contact information without risking accidentally breaking contact monitor behavior.

If this enhancement will not be used often, can it be worked around with a few lines of script?: The only way to work around this that I could figure out is to use KinematicBody2D and rewrite collision handling. Recalculating impulse using RigidBody2D is not possible because contact monitoring within _integrate_forces with Physics2DDirectBodyState does not provide all necessary properties of the colliding body.

Is there a reason why this should be core and not an add-on in the asset library?: This is a slight modification to the physics engine that simply reveals values already being calculated.

Virusthe commented 3 years ago

I'm also looking for this feature.

Calinou commented 3 years ago

@Virusthe Please don't bump issues without contributing significant new information. Use the :+1: reaction button on the first post instead.

densevoid commented 2 years ago

I'm not sure if this solution is correct and will satisfy the request of the author of the post. But I solved a similar problem using the get_contact_local_normal() method. An example of my solution:

func _integrate_forces(state: Physics2DDirectBodyState):
    for i in range(state.get_contact_count()):
        var contact_normal = state.get_contact_local_normal(i)
        var contact_body = state.get_contact_collider_object(i)

        var speed_difference := linear_velocity

        if contact_body is RigidBody2D:
            speed_difference -= contact_body.linear_velocity

        var bump_vector = speed_difference * contact_normal
        var bump_power = bump_vector.length_squared()

        if bump_power >= 1000:
            destroy_ball()
        elif bump_power >= 100:
            var volume = lerp(-20, 0, min(bump_power, 1000) / 1000)
            play_bump_sound(volume)