godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.15k stars 97 forks source link

Implement methods to get the velocity of a RigidBody in a given point #7480

Open yosoyfreeman opened 1 year ago

yosoyfreeman commented 1 year ago

Describe the project you are working on

Different kinds of RigidBody character controllers and interactions to test Godot physics and Godot Jolt.

Describe the problem or limitation you are having in your project

While implementing advanced mechanics with rigid bodies that need to apply custom forces(Often in relation with another bodies) you will find yourself needing to know what the velocity of a body is in a given point. Both local and global.

You can access the body state on integrate forces and use get_contact_collider_velocity_at_position() which, if the docs are accurate, is only in world space and needs to have a contact_idx as parameter, so is not helpful for arbitrary points. There is also get_velocity_at_local_position() But there is no equivalent for the global position, which is way more comfortable to work with when reading forces to make other bodies react. Also, this two methods can only be called insideintegrate_forces(), complicating the script and logic for a very basic function.

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

Implement get_velocity_at_position() and get_velocity_at_local_position() on RigidBody2D/3D.

This would make things like checking impacts, moving platforms and other really common behaviours while working with physics bodies easier, quicker and cleaner.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

For example, checking the velocity of the body at the point the character is standing on (With a RayCast for easier example) to retrieve the relative velocity of the character:

func _physics_process(delta):
    var RayCast = $RayCast3D
    if RayCast3D.is_colliding() != null:
        if RayCast3D.get_collider() is RigidBody3D:
        var relativeVelocity = character.velocity - RayCast3D.get_collider().get_velocity_at_position()

Edit: Here are the two functions i made for it, if someone want to give a try and implement this.

func get_velocity_at_position(body : RigidBody3D, position : Vector3):
    var bodyVel = body.linear_velocity
    var bodyAngVel = body.angular_velocity
    var centerOfMass = body.to_global(body.center_of_mass)
    var velocityAtPosition = bodyVel +bodyAngVel.cross(position - centerOfMass)
    return velocityAtPosition

Edit: I just thought that this one does not account for rotation.

func get_velocity_at_local_position(body : RigidBody3D, position : Vector3):
    var bodyVel = body.linear_velocity
    var bodyAngVel = body.angular_velocity
    var centerOfMass = body.center_of_mass
    var velocityAtLocalPosition =bodyVel + bodyAngVel.cross(position - centerOfMass)
    return velocityAtLocalPosition

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

You would need to implement your own custom functions for this, which does not make a lot of sense considering there is already a good API for applying forces or impacts at a custom point. Reading this values is as important as modifying them.

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

Is a core function that should be part of the engine.

p-planet commented 3 days ago

Absolutely agree.

There is a function for this in the PhysicsServer3D, but it's a bit complex and I'm not sure it works the way I want. I think if functions like this were as accessible as say get_linear_velocity they would get a lot of use.

it looks like this in my rigidbody controller that has a raycast for feet, my goal here is to get the character to move along with platforms without the reparenting method: if feet.get_collider() is RigidBody3D: var other_body = feet.get_collider() var state = PhysicsServer3D.body_get_direct_state(other_body.get_rid()) var other_point_velocity = state.get_velocity_at_local_position(other_body.global_position - feet.get_collision_point()) The resulting velocity seems weak. If I multiply it by 10 * mass and apply it as force it works to move the character along the moving platform somewhat accurately.