-
-
Notifications
You must be signed in to change notification settings - Fork 97
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve the behaviour of move_and_slide()
when on moving platforms
#2315
Comments
I added some vertical moving platforms to the demo for testing: move_and_slide-improvement-0.2.zip. These aren't working for either approach. From what it looks like this happens because |
Since we are tracking the objects derivatives it's easy to tell when a discontinuity occurs, so we can take some steps to smooth out the motion:
I've updated the demo to include these techniques: demo. Press E to toggle them. |
move_and_slide()
when on moving platforms.move_and_slide()
when on moving platforms
Thanks for this proposal, it's an interesting take on solving moving platforms. I think porting |
If the issue with reported positions and velocities being out of sync is fixed, we probably wouldn't need Does |
Even if there's a change in the API to have access to updated velocities from the |
Just to clear something up, is
So if we can't use it with |
You can't use |
Ah okay, I think understand how the
This way I could use I think There's still some bugs with
Thanks for taking the time to answer all my questions. |
In case anyone stumbles upon this, I made another version of the demo that uses the node ordering approach here: https://github.com/e344fde6bf/godot-move-and-slide-fix/tree/node-order This approach doesn't suffer issues for non-smooth motion since it gets the exact distance/velocity that the platforms move each frame. |
Thanks for the practical use cases, I see what we're trying to solve more clearly now, and the different test scenes are very useful too. Concerning the two issues, yes some tickets on github would be great if you can isolate a test case in a minimal project (or with a simple reproduction case in the project you already made). |
Describe the project you are working on
3D platform
Describe the problem or limitation you are having in your project
The current implementation of
move_and_slide()
in KinematicBody handles moving platforms poorly if they are moving at a non-constant velocity (#36483, #961) or rotating (#35365, #16450).Issue with platform moving at a non-constant velocity:
Issue with rotating platform:
Describe the feature / enhancement and how it helps to overcome the problem or limitation
This proposal is to improve
move_and_slide()
by using numerical analysis to predict the platform's velocity (i.e. the value returned byget_floor_velocity()
).Using this proposal on a platform moving at a non-constant velocity:
Using this proposal on a rotating platform
Demo project implementation
Controls:
demo: demo repo
godot version: v3.2.3.stable
Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams
Improving estimate of velocity due to rotation
The way
move_and_slide()
current works is it calculates the instantaneous velocity v that the KinematicBody experiences at point p and assumes it remains constant for the given timestep. However to rotate around the origin at a fixed distance, the average velocity that the KinematicBody experiences over the whole timestep should be used. One way to calculate this is to take the start point p1 and use the angular velocity to rotate around the origin to point p2. Then the average velocity is simply the difference between the two. This diagram shows the difference between the two approaches:Estimating linear velocity
The current approach to estimate linear velocity is to take the two most recent position values and use the difference between them to compute an estimate for the linear velocity. If more data points are used, then a better approximation can be found.
So given a series of position
x[i]
values, we define a series ofv[i]
velocity values asv[i] = x[i+1] - x[i]
, a series of acceleration valuesa[i] = v[i+1] - v[i]
, a series of jerk valuesj[i]
etc. This process can be performed repeatedly for higher-order approximates. Then we assume that after we repeat this process enough, we'll find a series of values that is constant e.g.j[i] = j[i+1]
.Then to find
x[i+1]
, then we simply substitute:It might be easier to understand if we visualise it as a table:
This process is essentially using a Newton polynomial to estimate the next value in the sequence. From Newton polynomials we know that if we take n repeated differences of an nth degree polynomial, we will reach a constant value. For our example above, we assumed that the third series of differences
j[i]
are constant, so we have effectively used a third degree polynomial to estimatex4
.This implementation will still have noticeable issues when the platform does not move smoothly (discontinuities in position, velocity, etc.), however the current implementation also suffers from these same issues anyway.
Smoothing out discontinuities
While the above method works well and will keep the KinetmaticBody at a fixed point on the platform, discontinuities in the platforms velocity will result in overshoot and ringing as the algorithm rapidly tries to correct itself. To combat this we can look for large jumps in the derivatives and perform the error correction over several frames.
When we detect a discontinuity, we should:
error = (v[t] - v[t-1]) * h
Demo implementation notes/issues
The current implementation of
move_and_slide()
uses an out of date value forget_floor_velocity()
(probably a bug). When we callmove_and_slide()
at timet
, if it collides with a floor, then it creates a KinematicCollision and stores in it the floor velocity calculated between framest-h
andt-2h
. Then in the next framet+h
, calls toget_floor_velocity()
will use that velocity value stored in the KinematicCollision even though we should now have access to the velocity of the floor moving between framest-h
andt
. So we fix this in our demo by requesting the most up to date value of the floor from the PhysicsServer.To calculate the rotational velocity, we need to know the position of KinematicBody relative to the centre of the platform. However, the KinematicCollision object created by
move_and_slide
doesn't provide enough information to calculate this value. To compute this in GDScript, we need to know the position that the platform has at the start of the frame, but I'm not sure how to compute this easily in a way that is independent from the KinematicBody's location in the scene tree. To hack around this in the demo, I placed the player at the top of the scene tree.If this enhancement will not be used often, can it be worked around with a few lines of script?
Any project that uses
move_and_slide()
for character motion will benefit from this approach. There are other ways to solve this problem, for example:However from a users perspective, I think this approach is simpler, more beginner friendly and has basically no downsides compared to the current implementation of
move_and_slide()
.Is there a reason why this should be core and not an add-on in the asset library?
This proposal improves
move_and_slide()
so it should be in core.Edit: added vertical moving platforms to the demo for testing purposes
Edit2: added motion smoothing when we detect discontinuities
The text was updated successfully, but these errors were encountered: