godotengine / godot-proposals

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

Allow CharacterBody to snap when there is a vertical upwards force in Godot 4.0 #4259

Closed yosoyfreeman closed 1 year ago

yosoyfreeman commented 2 years ago

Describe the project you are working on

A half life like character controller.

Describe the problem or limitation you are having in your project

I has been working with the new CharacterBody node to learn about it. with the current behavior of not snapping the body to the floor when there is some upwards velocity is really limiting when trying to take into account the velocity changes resulting of the slide. If you set your motion_velocity to be your real velocity with get_real_velocity() to take into account the direction changes resulting of the sliding (Going towards a slope converts some of your horizontal velocity intro vertical velocity) you will lost the capacity to snap correctly to the ground when you go from going upwards the slope to go down.

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

For consistency and predictability always snap the body when the snap vector reach the floor. This allows for more control over the body and prevents issues.

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

The current behavior can be match just using

if motion_velocity.y > 0: set_floor_snap_length(0) else: set_floor_snap_length(0.1)

before calling move_and_slide() or adding the current behavior as an option.

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

No, the ways is done is not possible to work correctly with snapping when moving upwards along slopes.

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

Is a basic part of the system and cant be done outside.

Mickeon commented 2 years ago

I may be absolutely mistaken, but isn't the described behaviour exactly how the 3.x KinematicBody behaves with move_and_slide_with_snap()?

yosoyfreeman commented 2 years ago

No, in 3.x the snapping is always working unless you directly make it 0 using move_and_slide_with_snap()

fabriceci commented 2 years ago

If you set your motion_velocity to be your real velocity with get_real_velocity() to take into account the direction changes resulting of the sliding

I didn't quite understand what you were trying to do. Why do you need/want to do this? The slopes are handled by default without affecting/polluting your velocity (and if needed with get_real_velocity you can get the real one). By keeping your velocity untouched, we can tell if you are jumping or falling, we also keep the correct length of your velocity.

yosoyfreeman commented 2 years ago

If you set your motion_velocity to be your real velocity with get_real_velocity() to take into account the direction changes resulting of the sliding

I didn't quite understand what you were trying to do. Why do you need/want to do this? The slopes are handled by default without affecting/polluting your velocity (and if needed with get_real_velocity you can get the real one). By keeping your velocity untouched, we can tell if you are jumping or falling, we also keep the correct length of your velocity.

Cause there are many use cases in which you in fact want your 3D body to be affected by the collisions. Continuing with the same example I post before, a half life style character controller indeed needs to be affected by such things, in a way that if you move quickly up a slope you should jump at the end, not going horizontally after leaving it. (This should be controlled setting the snap vector to 0 if your y speed is more than x). There are many other examples (Mario like controllers, quake like controllers, apex legends, Overgrowth...). While there are cases in which you don't want to work with that things, this kind of advanced systems requires it. That's why I'm assigning the real velocity each frame. In fact, that works perfectly right now and gives the expected results.

Is the limitation of disabling snapping while there is vertical force that is causing the problem. The only reason i can think for that behavior is to not confuse new users when they try to jump, but that was correctly explained in the docs. That results in lots of problems if you are trying to use the character taking the collisions into account to change the direction and speed of the body as described previously.

Also, there are other cases while you would want to keep the character snapped even when there is vertical force, even while you do not pass real velocity. For example, if you want a body to follow the direction of another and that body is not on the floor, it would jump.

The point of snapping is to have control over when the body should leave the floor. Right now, is not usable while working with this time of controllers.

Also, i know lots of devs that works with quake style controllers need snapping with vertical velocity, in the Qodot community (A specific godot community around the work of Shifty to import quake maps) you could find lots of them.

I know is long, but i hope is better explained now.

fabriceci commented 2 years ago

Thanks for the explanation, I understand now :).

In your first case, I imagine the problem is that your player is no longer detected on the ground for certain frames so he can't jump anymore (not sure to understand the second one). Anyway, it's something we have to address.

If possible I would like to keep the current behavior, it allows the beginner to have an extremely simple controller and allows us to turn snapping on by default (which improves stability on the ground).

What options do we have:

If you have any other ideas, I need to think about that a bit more.

yosoyfreeman commented 2 years ago

The problem is not the ground detection itself, is the fact that the character is not able to snap doe to y velocity.

I understand that the smart snapping is good for beginners o even quick prototyping, so there are two things that could work as i see:

What do you think?

IncredibleMeh commented 1 year ago

I'm in favor of restoring the old functionality, or even better giving us a much greater degree of control over what it considers as going against up_direction.

Frankly as of current 4.0 alpha it is difficult to even tell under what circumstances the snapping is intended to work. It does not appear to keep characters snapped to downward slopes or prevent detachment from the top of upward slopes reliably regardless of settings, which I would generally assume are its most common use cases.

fabriceci commented 1 year ago

it is difficult to even tell under what circumstances the snapping

@IncredibleMeh it only snap when you are on the floor, meaning your velocity should point to the ground (inverse of up direction, to be precise, dot products <= 0), that's why it's named floor_snap. I think it should work very well as it was well tested, but feel free to open an issue if you found a problem.

This proposal is about snapping when you are not on the ground regarding the velocity, there is nothing blocking here, it can be solved very simply by applying a few lines of code but I would like to propose an easier way. For the moment, disabling the velocity check (the so-called smart snap) seems to be the simplest solution, but I was waiting for other ideas.

yosoyfreeman commented 1 year ago

This proposal is about snapping when you are not on the ground regarding the velocity

I think it was a mistake, but for clarity sake the thing is about snapping when you are grounded regarding the velocity.

As i see it, the smart snapping is mostly to not confuse new devs when they try to make the character jump and that does not happens, but this peculiarity, as other Godot ones, is a good one in terms of control.

Maybe, with the new Godot 4 and the CharacterBody node, the best solution would be to create a new official tutorial similar to this outdated one ( https://docs.godotengine.org/en/3.1/tutorials/3d/fps_tutorial/index.html ) but more focussed on movement.

Nice day!

yosoyfreeman commented 1 year ago

Hi, is there any updates on this? It would be extremely useful to have it working on Godot 4.0

Calinou commented 1 year ago

Hi, is there any updates on this? It would be extremely useful to have it working on Godot 4.0

This won't be worked on for 4.0, as it's currently in release candidate stage. New features will only be worked on for 4.1 at the earliest.

yosoyfreeman commented 1 year ago

Hi, is there any updates on this? It would be extremely useful to have it working on Godot 4.0

This won't be worked on for 4.0, as it's currently in release candidate stage. New features will only be worked on for 4.1 at the earliest.

This is not a new feature but a correction for an already implemented Godot 4 feature that causes mayor regressions.

The Fabriceci PR https://github.com/godotengine/godot/pull/73749 fixes multiple issues reported by multiple users that would prevent the new CharacterBody from working as expected without altering at all the already implemented system or making any feature change by just exposing a function.

The team already did a gigantic work going back to Godot physics, re designing characters and movement, fixing jitter, stutter, sliding and other kind of issues. This things were a dealbreaker for lots of people and now that Godot have probably the best solution of all i don't think is a good idea to have users waiting for 4.1 or 4.2 and hard coding workarounds for an already identified problem for which exist a solution already.

hsandt commented 1 year ago

I was hoping to find some clues on how it worked in the 2D platformer demo, but it turns out it only uses horizontal motion. So the problem doesn't occur:

So this really occurs when moving character along the slope. And I just noticed the OP mentioned Half-Life. but same reasoning should apply to 3D.