- Home /
Character Controller continues moving upwards on slopes after horizontal movement has stopped
I'm one step away from getting the right feel for my character controller- I have an issue that kind of caused me to stop game development for a while but I really want to get it out of the way and move onto the cool stuff in my game.
I've included a video link that demonstrates the problem: https://youtu.be/_WNIqz6dbfQ
As you can see, the player ascends the slope as intended, but once the movement keys are released, the player does a little bit of a "bump" upwards, falls back down, and if you watch closely, you'll see that they also slowly ascend upwards for a short time before falling back down. If I can eliminate this bump and the little bit of levitation at the end I will be happy with what I have.
using UnityEngine;
public class moveTest : MonoBehaviour
{
//Essentials
[SerializeField] private GameObject playerObject;
[SerializeField] private GameObject playerModel;
[SerializeField] private Camera playerCamera;
private CharacterController playerController;
private Vector3 playerVelocity;
private Vector3 moveDirection;
private float minimumSpeed = 0.1f;
private float gravityForce = 25f;
private float terminalVelocity = -25f;
private bool grounded = true;
private float accelerationSpeed = 100f;
float frictionOffset = 94.42f;
LayerMask playerCollisionLayer = (1 << 6) | (1 << 7) | (1 << 0);
double mouseSensitivity = 1;
bool invertY = true;
private int fieldOfView = 90;
KeyCode moveForward = KeyCode.W;
KeyCode moveBack = KeyCode.S;
KeyCode moveLeft = KeyCode.A;
KeyCode moveRight = KeyCode.D;
KeyCode lookUp = KeyCode.UpArrow;
KeyCode lookDown = KeyCode.DownArrow;
KeyCode turnLeft = KeyCode.LeftArrow;
KeyCode turnRight = KeyCode.RightArrow;
KeyCode crouch = KeyCode.X;
KeyCode jump = KeyCode.Space;
KeyCode use = KeyCode.E;
KeyCode flashLight = KeyCode.L;
KeyCode primaryFire = KeyCode.Q;
KeyCode secondaryFire = KeyCode.Mouse1;
KeyCode ability = KeyCode.F;
KeyCode ability2 = KeyCode.V;
KeyCode ability3 = KeyCode.C;
KeyCode reload = KeyCode.R;
KeyCode console = KeyCode.Tilde;
KeyCode quickSave = KeyCode.F6;
KeyCode quickLoad = KeyCode.F9;
KeyCode openChat = KeyCode.Slash;
KeyCode levelView = KeyCode.Minus;
private void controlMouse()
{
float mouseX = Input.GetAxisRaw("Mouse Y");
float mouseY = Input.GetAxisRaw("Mouse X");
if (Input.GetKey(lookUp))
{
mouseX -= 90f * Time.deltaTime;
}
if (Input.GetKey(lookDown))
{
mouseX += 90f * Time.deltaTime;
}
if (Input.GetKey(turnLeft))
{
mouseY -= 90f * Time.deltaTime;
}
if (Input.GetKey(turnRight))
{
mouseY += 90f * Time.deltaTime;
}
playerModel.transform.eulerAngles += new Vector3(0, mouseY, 0);
playerCamera.transform.eulerAngles += new Vector3(mouseX, mouseY, 0);
}
private void handleInput()
{
moveDirection = Vector3.zero;
if (Input.GetKey(moveForward))
{
moveDirection += playerModel.transform.forward;
}
if (Input.GetKey(moveBack))
{
moveDirection -= playerModel.transform.forward;
}
if (Input.GetKey(moveLeft))
{
moveDirection -= playerModel.transform.right;
}
if (Input.GetKey(moveRight))
{
moveDirection += playerModel.transform.right;
}
if(Input.GetKey(jump) && isPlayerGrounded() && playerVelocity.y < 10f)
{
playerVelocity.y = 10f;
}
if (Input.GetKey(crouch))
{
//not yet implemented.
}
moveDirection = moveDirection.normalized;
playerVelocity += moveDirection * accelerationSpeed * Time.deltaTime;
if (Input.GetKey(use))
{
}
playerController.Move(playerVelocity * Time.deltaTime);
}
private void applyPhysics()
{
Vector3 tempVelocity = playerVelocity;
tempVelocity.y = 0;
tempVelocity *= Time.fixedDeltaTime * frictionOffset;
playerVelocity.x = tempVelocity.x;
playerVelocity.z = tempVelocity.z;
if (playerVelocity.y > terminalVelocity)
{
if(!isPlayerGrounded())
{
playerVelocity.y -= Time.fixedDeltaTime * gravityForce;
}
if(isPlayerGrounded())
{
//not sure what to do here- something could be placed here to eliminate the bump.
}
}
if (playerVelocity.z < minimumSpeed && playerVelocity.z > -minimumSpeed) { playerVelocity.z = 0; }
//if (Mathf.Abs(playerVelocity.z) < minimumSpeed ) { playerVelocity.z = 0; }
if (playerVelocity.x < minimumSpeed && playerVelocity.x > -minimumSpeed) { playerVelocity.x = 0; }
}
private bool isPlayerGrounded()
{
Vector3 center = new Vector3(this.transform.position.x, this.transform.position.y - 1f, this.transform.position.z);
Vector3 size = new Vector3(0.35f, 0.1f, 0.35f);
if (Physics.CheckBox(center, size, new Quaternion(), playerCollisionLayer))
{
return true;
}
else
{
return false;
}
}
private void OnControllerColliderHit(ControllerColliderHit collision)
{
Vector3 collisionDifference = collision.normal * Vector3.Dot(playerVelocity, collision.normal);
playerVelocity -= collisionDifference;
}
void Start()
{
//Application.targetFrameRate = 30;
playerObject = this.gameObject;
playerController = playerObject.GetComponent<CharacterController>();
playerCamera = playerObject.GetComponentInChildren<Camera>();
}
private void FixedUpdate()
{
applyPhysics();
}
void Update()
{
print(playerVelocity);
controlMouse();
handleInput();
}
}
I feel like I've tried everything there is to try- why is this happening and what can I change in my code in order to prevent it / fix it?
Answer by xthunderduckx · Jul 18, 2021 at 01:44 AM
Solved- tripled the force of gravity whilst the player is grounded- not only does this stop the vertical momentum from carrying the player upwards, but it also has the side effect of being a slope limiter- ie that the player can not climb ramps above a certain angle without sufficient speed.
Your answer
Follow this Question
Related Questions
Check if the normal of a collision is within a range of angles 2 Answers
Performance Physics.Checkbox/CheckSphere vs Collider/Trigger 1 Answer
Gun script using Physics.Raycast not working? 2 Answers
3D Hook With Swing Physics 0 Answers
CharacterController.Move uses gravity even though it shouldn't 1 Answer