I am developing a game which focusses mainly on outdoor movement, therefore I want the character controls to feel as good as possible.
The issue I am currently working on is slope behaviour: The character should not slide down when standing on a slope that is not very steep, and slide down on slopes that are too steep.
I implemented this by activating and deactivating rigidbody constraints depending on the current angle of the ground under the player.
private const RigidbodyConstraints DefaultConstraints = RigidbodyConstraints.FreezeRotation;
private const RigidbodyConstraints StayOnSlope = RigidbodyConstraints.FreezePositionX | RigidbodyConstraints.FreezePositionZ | DefaultConstraints;
private const RigidbodyConstraints SlideDownSlope = DefaultConstraints;
The angle of the ground is calculated in a seperate method, returning the angle between the up vector and the ground normal in degrees.
private float GetGroundAngle()
{
RaycastHit hit;
if (Physics.Raycast(transform.position, Vector3.down, out hit, 0.5f))
{
return Vector3.Angle(Vector3.up, hit.normal);
}
return 0;
}
The actual activation and deactivation of the constraints is implemented inside the FixedUpdate
method. Additionally, the player movement is being slowed down the steeper the slope is.
private void FixedUpdate()
{
const float MAX_SLOPE_ANGLE = 45;
// If the player is grounded, check the ground angle and prevent slope sliding
float angle = GetGroundAngle();
// Apply the constraints
m_rigidbody.constraints = (m_movementVector.magnitude < Vector3.kEpsilon) && angle <= MAX_SLOPE_ANGLE ? StayOnSlope : SlideDownSlope;
// Calculate the movement coefficient to ensure the player cannot run up slopes
float slopeCoefficient = Mathf.Cos(angle * Mathf.Deg2Rad);
// Calculate and apply the movement vector
Vector3 movement = m_movementVector * slopeCoefficient * Time.fixedDeltaTime;
m_rigidbody.MovePosition(m_rigidbody.position + movement);
// ...
}
The issues with this functionality are the following:
Is there a better way to make slope movement behaviour?
The character should not slide down when standing on a slope that is not very steep, and slide down on slopes that are too steep.
I believe the CharacterController component may be of use for you.
Notice that it has an adjustable Slope Limit variable.
https://docs.unity3d.com/Manual/class-CharacterController.html
There is a First Person controller implementing this in the Unity Standard Assets which can be found inside Unity under Assets -> Import Package -> Characters.