1
\$\begingroup\$

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?");

        SendMessage("OnFall", SendMessageOptions.DontRequireReceiver);
        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();

        SendMessage("OnLand", SendMessageOptions.DontRequireReceiver);
    }   
}

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

\$\endgroup\$
1
\$\begingroup\$

The computer is not aware of what type of object is moving around, whether it is a character walking/running (which you don't want to launch when it hits a ramp) or a car driving (which you would want to launch). Since you said that your character is moving at high velocity, that would explain why it is launching.

It is best to think of your character as a vehicle with wheels on the feet to help understand why the physics engine is launching your character when moving at high speed.

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.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.