# Player launches into air when hitting steep slopes

I've been debugging an issue where when my player is moving forward at high speeds (I have configurable movement modes for an overview/overwatch mode) if they are in walk mode and hit a steep slope the player gets launched into the air as though they've bounced or jumped. So far I've narrowed it to something in this portion of the code (called from Update() with a conditional flag):

CharacterMotor.js (SNIPPET)

private function UpdateFunction () {
// We copy the actual velocity into a temporary variable that we can manipulate.
var velocity : Vector3 = movement.velocity;

// Update velocity based on input
velocity = ApplyInputVelocityChange(velocity);

// Apply gravity and jumping force
velocity = ApplyGravityAndJumping (velocity);

// Moving platform support
var moveDistance : Vector3 = Vector3.zero;

// Save lastPosition for velocity calculation.
var lastPosition : Vector3 = tr.position;

// We always want the movement to be framerate independent.  Multiplying by Time.deltaTime does this.
var currentMovementOffset : Vector3 = velocity * Time.deltaTime;

// Find out how much we need to push towards the ground to avoid loosing grouning
// when walking down a step or over a sharp change in slope.
var pushDownOffset : float = Mathf.Max(controller.stepOffset, Vector3(currentMovementOffset.x, 0, currentMovementOffset.z).magnitude);
if (grounded){
Debug.Log(currentMovementOffset);
currentMovementOffset -= pushDownOffset * Vector3.up;
}
// Reset variables that will be set by collision function
movingPlatform.hitPlatform = null;
groundNormal = Vector3.zero;

// Move our character!
movement.collisionFlags = controller.Move (currentMovementOffset);

movement.lastHitPoint = movement.hitPoint;
lastGroundNormal = groundNormal;

// Calculate the velocity based on the current and previous position.
// This means our velocity will only be the amount the character actually moved as a result of collisions.
var oldHVelocity : Vector3 = new Vector3(velocity.x, 0, velocity.z);
movement.velocity = (tr.position - lastPosition) / Time.deltaTime;
var newHVelocity : Vector3 = new Vector3(movement.velocity.x, 0, movement.velocity.z);

// The CharacterController can be moved in unwanted directions when colliding with things.
// We want to prevent this from influencing the recorded velocity.
if (oldHVelocity == Vector3.zero) {
movement.velocity = new Vector3(0, movement.velocity.y, 0);
}
else {
var projectedNewVelocity : float = Vector3.Dot(newHVelocity, oldHVelocity) / oldHVelocity.sqrMagnitude;
movement.velocity = oldHVelocity * Mathf.Clamp01(projectedNewVelocity) + movement.velocity.y * Vector3.up;
}

if (movement.velocity.y < velocity.y - 0.001) {
if (movement.velocity.y < 0) {
// Something is forcing the CharacterController down faster than it should.
// Ignore this
movement.velocity.y = velocity.y;
}
else {
// The upwards movement of the CharacterController has been blocked.
// This is treated like a ceiling collision - stop further jumping here.
jumping.holdingJumpButton = false;
}
}
Debug.Log("Before the bounce test: " + tr.position);
// We were grounded but just loosed grounding
if (grounded && !IsGroundedTest()) {
grounded = false;
Debug.Log("Before bounce?");

Debug.Log("1. Lost grounding, maybe bounced?");
// We pushed the character down to ensure it would stay on the ground if there was any.
// But there wasn't so now we cancel the downwards offset to make the fall smoother.
Debug.Log(tr.position);
tr.position += pushDownOffset * Vector3.up;
// MIGUET

// END MIGUET
Debug.Log(tr.position);
//      Debug.Break();
}
// We were not grounded but just landed on something
else if (!grounded && IsGroundedTest()) {
Debug.Log("3. Found my grounding");
grounded = true;
jumping.jumping = false;
SubtractNewPlatformVelocity();

}
}


Specifically if we look at the line "if (grounded && !IsGroundedTest()) {" is where I can capture the bounce as it happens. When putting in break points my first debug message fires "Before Bounce" just before launch. On landing we get the Debug message "3. found my grounding".

Unfortunately I'm not experienced enough with character movement to determine exactly why it's launching the player up, any advice on debugging and tracking the issue more closely is appreciated

EDIT Most recent debug results:

• Before the bounce test (5655.7, 65.1, 6032.1)
• IsGroundedTestResults: False
• Before bounce?
1. Lost grounding, maybe bounced?
• (56.557, 65.1, 6032.1) [NOTE this is the first Debug.Log(tr.position)]
• (56.557, 65.1, 6032.1) [NOTE this is the second Debug.Log(tr.position)]

Then we are back to normal

I haven't done it in Unity but I think the fix would be to restrict velocity.y to only move in the downward direction if the player is not grounded and not jumping. This should allow your player to fall off cliffs or walk downhill with normal gravity but would prevent it from launching into the air when it hits some type of ramp. As long as the player is grounded, running uphill shouldn't be affected.
If the player is explicitly jumping, then don't restrict velocity.y.
If you want to allow for a little bit of bounce, you might try scaling down velocity.y, rather than limiting it to downward motion or some small positive value. Otherwise if you just limit it, your character will look like it's hitting a ceiling when it launches too fast.