- Home /
character controller slide down slope
Hi all, I am using the character controller and am attempting to have the character slide down slopes that are greater then the slope limit set in the character controller. I have tried numerous methods to get it to work consistently that usually involve spherecasts and raycasts to the surface and mathing out the vector with distance hits.
Is there a simpler way to detect the down slope angle of the surface the character controller is standing on so that it can slide down the correct direction? Depending on how the 'Slope Limit' option in the character controller works it is possible that it can be directly read from somewhere? Otherwise how does it know that it has hit that limit if it can't measure it?
I have seen a few similar questions but have not found a way that worked consistently.
Thanks
How does the character controller know if the character has hit the slope limit? Is there something simple I am missing? Just having access to the 'can they move' or not check that is somewhere in the character controller would help quite a bit.
Answer by AurimasBlazulionis · May 31, 2017 at 05:53 PM
This is something that is not available by default in the character controller. The problem with sliding off the slopes is that gravity pulls the player down, but to slide off the slope, the player has to be pulled sideways to the direction of the slope's normal and that simply does not happen. We will be replacing the default controller.isGrounded and controller.slopeLimit with our own stuff. So set controller's slope limit to something like 80 degrees because we will need that for out code to work.
From my Unet-Controller:
Get the ground normal using OnControllerColliderHit
void OnControllerColliderHit (ControllerColliderHit hit) {
hitNormal = hit.normal;
}
Then, after the controller.Move, determine if the controller should be grounded or not:
isGrounded = (Vector3.Angle (Vector3.up, hitNormal) <= slopeLimit);
Then, before calling controller.Move, add sideways speed to allow it go down:
//Character sliding of surfaces
if (!isGrounded) {
inpRes.speed.x += (1f - hitNormal.y) * hitNormal.x * (1f - slideFriction);
inpRes.speed.z += (1f - hitNormal.y) * hitNormal.z * (1f - slideFriction);
}
Experiment with the slideFriction value, 0.3 works rather well.
This should do the trick for you.
Thanks, it works almost perfectly, but I do have some odd speed changes when it gets to the bottom of the slope and some issues where I can keep going up in certain situations. The latter are most likely due to how my movement vector is initially calculated. The former is not bad, I will post video later if I can. Overall much simpler then my last solution with multiple sphere and raycasts!
Also: This method should work on any surface right? Regardless of the rotation of the game object? (On terrain, for example?)
Hi cool method, although there's two things that are happening for me: (1) when I begin to run into the slope, the character jitters as he runs into it (and is set back instantly), also (2) when he jumps into the slope, he bounces back sometimes. Do you know how to fix this by any chance?
Hello, I currently am facing the same issue as yaakovyitzchakbenmoshe, any wall just makes the character bounce off, and staircases that use the "step offset" will also often make the character bounce off the small "wall" there is.
I know this is an old post but i was trying to use this in my game, and repurposing it for general gravity stuff and am getting some weird results where isGrounded is returning true when Vector3.Angle (Vector3.up, hitNormal) is 0. Basically the only time it says the character is not grounded is when they are touching a slope. Is this the intended behavior and i need to make something completely separate for gravity? `` `` void FixedUpdate() {
hitAngle = Vector3.Angle(Vector3.up, hitNormal);
isGrounded = (hitAngle <= myController.slopeLimit);
if (!isGrounded)
{
velocity.y += gravity;
velocity.x += (1f - hitNormal.y) * hitNormal.x * (-gravity - slideFriction);
velocity.z += (1f - hitNormal.y) * hitNormal.z * (-gravity - slideFriction);
}
else
{
velocity.y = -2f;
velocity.x = 0f;
velocity.z = 0f;
}
myController.$$anonymous$$ove(velocity);
} `` `` also wondering if @marclar83 could help.
As far as I can gather indeed this just deter$$anonymous$$es whether or not the character is on a slope and should slide, and does nothing to deter$$anonymous$$e whether or not the character is "grounded", I have seperated them out into grounded
and sliding
, do all the standard grounded checks and then just add the sliding velocity if the character is on a slope greater than the limit.
Answer by marclar83 · Oct 07, 2017 at 08:33 PM
@AurimasBlazulionis' script worked very well, but I had to tweak it to work with the default FirstPersonController. To help newcommer to undate the actual Unity official script, I've made a few minor adjustments. Oppositly to the original slopeLimit, I've set a much lower value (like 40 instead of 80, for the script to work). First, we need to define the variables at the beginning of the scripts:
private bool isGrounded; // is on a slope or not
public float slideFriction = 0.3f; // ajusting the friction of the slope
private Vector3 hitNormal; //orientation of the slope.
Get the ground normal by adding this line in the void OnControllerColliderHit:
private void OnControllerColliderHit(ControllerColliderHit hit)
{
hitNormal = hit.normal;
...
Then, after the m_CharacterController.Move (in the FixedUpdate), determine if the controller should be grounded or not:
isGrounded = Vector3.Angle (Vector3.up, hitNormal) <= m_CharacterController.slopeLimit;
Then, before calling m_CharacterController.Move (in the FixedUpdate), add sideways speed to allow it go down:
if (!isGrounded) {
m_MoveDir.x += (1f - hitNormal.y) * hitNormal.x * (speed - slideFriction);
m_MoveDir.z += (1f - hitNormal.y) * hitNormal.z * (speed - slideFriction);
}
Thanks again @AurimasBlazulionis for your great help, all credit goes to that person !
Answer by chris_sarama · Aug 01, 2017 at 02:35 PM
To improve upon @AurimasBlazulionis answer I found it better to multiply a slide speed at the end of the formula. The problem with his friction method is it can only go so fast no matter how low you put the friction.
slideDirection.x = ((1f - hit.normal.y) * hit.normal.x) * slideSpeed;
slideDirection.z = ((1f - hit.normal.y) * hit.normal.z) * slideSpeed;
A slideSpeed of 6 works pretty well. This slides very fast and is much more realistic.
Answer by ChiliStudio · Dec 16, 2019 at 10:38 AM
// ON START() CREATE SLIDE TRANSFORM
slideGameObject = Instantiate(new GameObject(), transform);
slideGameObject.name = "UsedForSliding";
slideTransform = slideGameObject.transform;
// FIND THE POINT WE HIT void OnControllerColliderHit(ControllerColliderHit hit) { collisionPoint = hit.point; }
RaycastHit groundHit;
Ray groundRay;
// on Update:
groundRay.origin = collisionPoint + Vector3.up * .05f;
groundRay.direction = Vector3.down;
slideTransform.rotation = transform.rotation;
// IF WE ARE ON A SURFACE, DETERMINE IF WE SHOULD BE SLIDING
if (Physics.Raycast(groundRay, out groundHit, .6f)){
slopeAngle = Vector3.Angle(transform.up, groundHit.normal); // The angle of the slope is the angle between up and the normal of the slope
if(slopeAngle <= playerCC.slopeLimit) // if angles arent too high
{
sliding = false;
}
else if(slopeAngle > playerCC.slopeLimit) // if angles are too high
{
if (groundHit.transform.gameObject.tag.Contains("Sl") & playerCC.velocity.y <= 0)
{
sliding = true;
Vector3 groundCross = Vector3.Cross(groundHit.normal, Vector3.up);
slideTransform.rotation = Quaternion.FromToRotation(transform.up, Vector3.Cross(groundCross, groundHit.normal)); // collect the transform of the ground we need to slide down
}
}
}
else
{
sliding = false;
}
NOW WHEN WE CALL THE CHARACTER CONTROLLER MOVE:
// IF SLIDING, MOVE THE PLAYER ALONG SLIDE DIRECTION
if (!haveGottenVelY) // if this is the first frame we are sliding
{
slideVel = playerCC.velocity.y; // get our vertical velocity
slideVel = Mathf.Abs(slideVel);
haveGottenVelY = true; // tell computer to no longer get our vertical velocity so we can lerp it
}
slideVel = Mathf.Lerp(slideVel, 180, slideAcceleration); // accelerate the velocity of the slide from our previous Yveolcity to max fall speed which is around 180 (I reccomend slide acceleration of .005)
slideDirection = -slideTransform.up * slideVel; // set slide vector
// APPLY MOVEMENT
playerCC.Move(slideDirection * Time.deltaTime);
Lastly, make sure to include "Sl" in the tag of any game object you wish to allow sliding on. (Some objects like movable cubes you probably wouldn't need to slide down).
If anyone can help me modify the Oculus Integration package code for the OVRPlayerController to do this slope sliding thing, it would mean the world to me!
I'm not a programmer so doing this is a monumental task for me. I attached my current modified version of the OVRPlayerController.cs in txt format.link text
Answer by Paul_Hughes · Nov 23, 2021 at 05:08 PM
Having trouble altering the new starter assets ThirdPersonController to slide down slopes. The m_moveDir.x I am having trouble as I am swapping it for _input.move.x, but the player automatically moves along that axis, so it is calling it to move somehow in my code or I'm putting that code in the wrong place. It would be nice to see a full script as to how this is all put together instead of snippets and saying it goes above calling controller.Move etc, as there is a call for Move(); in the update and also in the Move function itself controller.Move, so does the code go above and below inside the Move() function or in the actual update method, or should I remove Move() to a fixedUpdate for physics performance? The old Motor script had that ability so why take it out? I have tried half a dozen solutions and YT videos to no avail. It seems my Mathematics and Physics for Unity needs an upgrade, being an indie dev time is not on my side. I keep getting my player bobbing up and down above the surface or no reaction to sliding down the hill at all on the terrain. 2 weeks later and still can not get it to work. I will come back to this in another couple of weeks as my head is on fire. Thank you for everyone's help so far!
Your answer
![](https://koobas.hobune.stream/wayback/20220612122902im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
How do I make my character fall off slopes grater than its slope limit? 0 Answers
Sliding game slope jittering. 0 Answers
Slide down up slope smoothly like Rasta Monkey on IPhone 0 Answers
CharacterController running downhills 1 Answer
CharacterController Slope Limit not working, character climbs onto everything 0 Answers