- Home /
Player character 'jumps' or bounces off slope after leaving it instead of falling through the air
Here is a video example of the issue.
This is the code that handles descending a slope:
void DescendSlope(ref Vector2 amountMoved)
{
if (amountMoved.y < 0)
{
float moveDirection = (amountMoved.x < -0.01 || amountMoved.x > 0.01) ? Mathf.Sign(amountMoved.x) : 0;
Vector2 rayOrigin = (moveDirection == -1) ? rayOrigins.bottomRight : rayOrigins.bottomLeft;
RaycastHit2D hit = Physics2D.Raycast(rayOrigin, Vector2.down, Mathf.Infinity, collisionMask);
if (hit)
{
float slopeAngle = Vector2.Angle(hit.normal, Vector2.up);
if (slopeAngle != 0)
{
if (Mathf.Sign(hit.normal.x) == moveDirection)
{
if ((hit.distance - insetWidth) <= Mathf.Tan(slopeAngle * Mathf.Deg2Rad) * Mathf.Abs(amountMoved.x))
{
float moveDistance = Mathf.Abs(amountMoved.x);
float descentDistanceY = Mathf.Sin(slopeAngle * Mathf.Deg2Rad) * moveDistance;
amountMoved.x = Mathf.Cos(slopeAngle * Mathf.Deg2Rad) * moveDistance * Mathf.Sign(amountMoved.x);
amountMoved.y -= descentDistanceY;
collision.slopeAngle = slopeAngle;
collision.descendingSlope = true;
collision.below = true;
}
}
}
}
}
}
Everything works correctly with regards to speed and how the player sticks to the slope, except for the very end when he needs to fall off. Any reason as to why that would happen?
Answer by HappiiGamer · Oct 22, 2019 at 12:46 PM
Something is happening at the very tip of that slope. Not sure what. One thing I notice is you are comparing floats using != and ==, this is a no go. Floats are never equal due to how they are stored in memory; they always carry imprecision. Use Mathf.Approximately(...) instead. https://docs.unity3d.com/ScriptReference/Mathf.Approximately.html
Thank you for the suggestion regarding floats, I didn't know that was an option and I'll try to use it in the future.
I tried modifying everything handling movement on the x-axis in my scripts and modifying the corners to see if things would differ in the past 10-15 hours and sadly things remain the same.
One thing I found interesting is that this issue persists even if I disable the slope I'm on while the game is running, which suggests to me that the issue isn't so much about the corner as much as it's something that happens after the player character is off the surface.
Also the issue doesn't seem to happen if I disable the method I posted above. Descending the slope doesn't work smoothly of course but aside from that when the player is on the slope at the end of it I haven't been able to reproduce that bug.
Have you fixed the != and == operators for you floats using $$anonymous$$athf.Approx?
I tried many combinations changing the lines 5, 14 and 16, but the methodn't go all the way down beyond line 13 this way, still trying to figure out why.
Edit; not sure if it helps but since I wasn't getting that jump when the method wasn't running I thought it might be a good idea to try (as a dirty fix) to disable the method before the player was done being on it by adding this && (hit.collider.bounds.max.x - hit.point.x) > xAmountf to line 18 but the issue remains the same, and the character jumps off the platform before reaching end of it.
Answer by Canneverchooseaname · Oct 22, 2019 at 04:43 PM
I realize I rushed into this post and didn't give you all the info you might have needed, so I'll add some things that might help elucidate the nature of the problem.
I tried changing the collider for the incline to an edge collider and sadly it behaves the same way.
I also tried disabling the entire incline while the player was sliding off of it in real time and that also produces the same effect, as soon as the floor is disabled.
I tried making my box collider into a trigger (since I only use it to define where the raycasts will come from) and it behaves the same way.
I also tried changing all the values relating to x-axis movement in any script that handles movement and it's always the same story. I tried using the Aproximately method to change equivalencies on floats (in case the numbers were just slightly off), making positives into negatives, negatives into positives, I tried to apply a deceleration when the player leaves the slope on x and y, then acceleration on y, and I tried moving stuff around to see what would change. Sadly things only got broken even further so I went back to the original.
Interestingly, the last useful thing I was able to figure out is that if I don't run the DescendSlope method at all then I won't get this effect, but if I turn it off mid-slope the player will jump off immediately. Also since I'm not using any Unity physics I'm running everything from an update method, but when I move it all to FixedUpdate the effect is reduced ever so slightly (it's still there though).
Also I'm not sure if it counts, but if I reduce the time scale to .1 the player gets flung horizontally and loses most if not all of his gravity. Not sure if this is a side effect of slowing things down and Unity getting buggy or if it's a more accurate depiction of what is actually going on.
Could it be a matter of the math being wrong?
I changed these four lines
float moveDistance = $$anonymous$$athf.Abs(amount$$anonymous$$oved.x);
float descentDistanceY = $$anonymous$$athf.Sin(slopeAngle * $$anonymous$$athf.Deg2Rad) * moveDistance;
amount$$anonymous$$oved.x = $$anonymous$$athf.Cos(slopeAngle * $$anonymous$$athf.Deg2Rad) * moveDistance * $$anonymous$$athf.Sign(amount$$anonymous$$oved.x);
amount$$anonymous$$oved.y -= descentDistanceY;
into these ones
float moveDistance = $$anonymous$$athf.Abs(amount$$anonymous$$oved.x);
float descentDistanceY = $$anonymous$$athf.Sin(slopeAngle * $$anonymous$$athf.Deg2Rad) * moveDistance;
amount$$anonymous$$oved.y -= descentDistanceY;
amount$$anonymous$$oved.x = amount$$anonymous$$oved.y / ($$anonymous$$athf.Tan(slopeAngle * $$anonymous$$athf.Deg2Rad)) * $$anonymous$$athf.Sign(amount$$anonymous$$oved.x);
And the results vary wildly. Shouldn't the formulas for the x axis movement return the same value?
I don't think your math is wrong. I'm still trying to understand this method. So, correct me if I'm wrong. You are casting a ray from bottom of your unit when his y-delta is negative? If Ray hits a slope you change the direction of motion to match the slope. But, do you check the distance of the slope from the player to make sure he's touching the slope? Because, your ray length is infinitely long and pointing down, so even if player is far from the slope, his position will be affected by it.
I do, this line ensures that the player only starts following the slope once he's on it
if ((hit.distance - insetWidth) <= $$anonymous$$athf.Tan(slopeAngle * $$anonymous$$athf.Deg2Rad) * $$anonymous$$athf.Abs(amount$$anonymous$$oved.x))
I spent all day debugging today and I think I figured it out though. There are two issues at play, a doubling in speed for the Y axis, which lasts one frame, and the other is a doubling in speed for the X axis which lasts until it's reduced to 0. Since this script I'm working on is loosely based on another script by Sebastian Lague (this descending slope script is actually identical, and a lot of the basic overall structure is as well) and he never posted a solution for this issue I'll explain to the best of my ability what is going on, for everyone who also needs a fix to this issue.
I calculate the player's velocity on another script which then runs the values on this script (part of which I posted), and that value is then passed along a series of different methods which, depending on varying conditions, may affect these values and eventually end up moving the player.
Regarding the first issue, it happens because of line 24. After an initial rise in downward velocity (-descentDistanceY), I think that moveAmount.y is modified by the fact the game is detecting a collision with the slope, and on the very last frame of the descent the player is moved off of the slope, but at the same time the method handling vertical collisions isn't braking the speed anymore, since it's not detecting a collision below the player, and the value isn't reduced. The frame after that the DescendingSlope method isn't entered anymore, so the speed stops being augmented.
As for the extra movement on the X-axis, it's because of a similar issue. When the velocity is calculated that value is much faster than when the player's on a slope, which means that the slope is slowing down the movement on that axis. Once the player moves off of the slope and it's not getting accessed anymore, the amount$$anonymous$$oved.x value stops being reduced and goes back to what it was.
I'll mark this as answered if I can manage to fix the issues for good tomorrow, but I already made some crude changes earlier today and it seemed to work.
Your answer
Follow this Question
Related Questions
How to follow exactly a curve ? 2 Answers
Problem sliding down hills (WITH VIDEO) 1 Answer
Travel up and down slopes 0 Answers
Slope angle fix 0 Answers
Preserve horizontal speed on slopes 1 Answer