godotengine / godot-proposals

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

Split Engine defined and User defined Velocities in Godot Physics #8853

Open mrjustaguy opened 8 months ago

mrjustaguy commented 8 months ago

Describe the project you are working on

2D Space Sim

Describe the problem or limitation you are having in your project

Unable to integrate Responsive controls without killing all physics effects, because the only way to make the controls act the way they should is to directly set velocities, however that also overrides the velocities the Physics engine outputs

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

Add Physics Linear/Angular velocities, that are accumulated results of all physics interactions that happen, and doesn't get affected by the velocities set by the user. This would allow combining user's controls with physics seamlessly like so: linear_velocity = physics_linear_velocity + user_linear_velocity

where say the physics velocity is the gravity, and the user velocity is forward motion, and the result would be the combination of the two vectors resulting in both the desired user control, without ignoring physics like would be the case in: linear_velocity = user_linear_velocity

and doesn't accumulate the user's inputs (which makes the thing feel much less responsive) while keeping the physics: linear_velocity += user_linear_velocity

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

Add these Properties to Rigid Bodies 1) Physics_Linear_Velocity 2) Physics_Angular_Velocity

and Move the physics results to affect these properties instead of the respective non physics-prefixed velocities, and warn the user in the documentation to not change them by hand unless they wish to nullify physical results for whatever reason and to instead keep using the non-prefixed variants for very precise, simple (arcade-like) control, or by using forces for more physically based control

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

Only by writing over the whole logic from scratch with a custom solver

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

This is about Improving Physics Control

NeoWordire commented 2 months ago

Would this snippet cover what this story was intending to do? you can track all velocities physics ever applied to the object in a class var and slap the user velocity on top. by calling the default integrator in the custom integration and apply the results of just the last frame into the tracked physics only var. The user_velocity applied last frame could even be removed before running the builtin integrate if you don't want it to be in the drag calculation.

func _ready():
    set_use_custom_integrator(true)

var physics_linear_velocity = Vector3.ZERO  # tracking  physics velocity regardless of user velocities
func _integrate_forces(state) -> void:
        # run the default physics code but undo the result and save to apply later
    var old_linear_velocity = state.linear_velocity
    state.integrate_forces()
    physics_linear_velocity += state.linear_velocity - old_linear_velocity
    state.linear_velocity = old_linear_velocity #undo base intergrate forces

       # generate whatever user velocities you want
    var input_dir = Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
    var direction = Vector3(input_dir.x, 0, input_dir.y).normalized()
    var user_linear_velocity = Vector3.ZERO
    if direction:
        user_linear_velocity = state.inverse_mass * direction * 10

    state.linear_velocity =  user_linear_velocity + physics_linear_velocity
NeoWordire commented 2 months ago

I believe my above snippet is able to cover what was proposed or at least prove it is possible with existing interfaces.

While this control scheme is responsive, it runs into issues if constant forces are applied. When moving against gravity the user input does nothing to reduce the separate and ever accelerating physics speed which will overwhelm user control authority. Additional logic need to dampen or cancel out when velocities oppose.

EDIT: the state.integrate_forces and the _integrate_forces() do have a few more differences than I thought. Which currently applies to all custom integrators, I believe this is due solely to execution order if you are only changing the velocities instead of actually moving the bodies.

In the non-custom path the forces are integrated, saved to the velocities, collision island calculated, then the the velocities are applied. while with any custom force integrator the save to velocity step is skipped and this custom _integrate_forces is instead a delayed call scheduled by sync. so setting a velocity in custom force integrator will only have it apply on the next physics step.