Movement issue, the player accelerates but does not reduce in speed when hitting a wall or object

Hi there,

I’m working on some first person movement code which is based on the Quake 3 source code, which was ported by ‘Zinglish’ here: quake3-movement-unity3d/CPMPlayer.cs at master · WiggleWizard/quake3-movement-unity3d · GitHub

The issue I’m having with my script, is that the player accelerates whilst in the air but if the player hits a wall or object and slows down even so they are not moving except jumping, the previous speed they were travelling before hitting the object is retained, which is unwanted. I want the player to slow down when hitting objects.

Here is the relevant code:
void Update()
{
/* Movement */
QueueJump();
if (characterController.isGrounded)
GroundMove();

        if (!characterController.isGrounded)
            AirMove();

        // Move the player
        characterController.Move(playerVelocity * Time.deltaTime);
    }

/* Sets the direction based on player input */
    private void SetMovementDirection()                                                         
    {
        commands.forwardMove = Input.GetAxisRaw("Vertical");
        commands.sideMove = Input.GetAxisRaw("Horizontal");
    }

    /* If the jump key is pressed while in the air, the player will jump instantly when they hit the ground */
    private void QueueJump()                                                                    
    {
        if (Input.GetButton("Jump") && !queueJump)
            queueJump = true;

        if (Input.GetButtonUp("Jump"))
            queueJump = false;
    }

    /* Returns the scale factor to apply to the movement direction */
    private float MovementScale()
    {
        int Maximum;
        float Total;
        float Scale;

        Maximum = (int)Mathf.Abs(commands.forwardMove);
        if (Mathf.Abs(commands.sideMove) > Maximum)
            Maximum = (int)Mathf.Abs(commands.sideMove);
        if (Maximum <= 0)
            return 0;

        Total = Mathf.Sqrt(commands.forwardMove * commands.forwardMove + commands.sideMove * commands.sideMove);
        Scale = movementSpeed * Maximum / (moveScale * Total);

        return Scale;
    }

    private void Accelerate(Vector3 Direction, float Speed, float Acceleration)
    {
        float AddSpeed;
        float AccelerationSpeed;
        float CurrentSpeed;

        // Stop the player exceeding the speed cap
        if (Speed >= playerVelocityCap)
            return;

        CurrentSpeed = Vector3.Dot(playerVelocity, Direction);
        AddSpeed = Speed - CurrentSpeed;
        if (AddSpeed <= 0)
            return;

        AccelerationSpeed = Acceleration * Time.deltaTime * Speed;
        if (AccelerationSpeed > AddSpeed)
            AccelerationSpeed = AddSpeed;

        playerVelocity.x += AccelerationSpeed * Direction.x;
        playerVelocity.z += AccelerationSpeed * Direction.z;
    }

// This function is called when the player is the on the ground
    private void GroundMove()                                                                   
    {
        Vector3 Direction;

        // If a jump is queued, don't apply friction 
        if (!queueJump)                                                                        
            ApplyFriction(1f);
        else
            ApplyFriction(0);

        Direction = new Vector3(commands.sideMove, 0, commands.forwardMove);
        Direction = transform.TransformDirection(Direction);
        moveDirectionNorm = Direction;

        var Speed = Direction.magnitude;
        Speed *= movementSpeed;

        Accelerate(Direction, Speed, runAcceleration);

        // Reset gravity velocity
        playerVelocity.y = 0;                                                                  

        if (queueJump)
        {
            playerVelocity.y = jumpSpeed;
            PlayJumpSound();
            queueJump = false;
            landSoundPlayed = false;
        }
    }

    private void AirMove()
    {
        Vector3 Direction;
        float Acceleration;
        float Scale = MovementScale();

        SetMovementDirection();

        // Multiplier applied to the sidemove command to serverly reduce strafing while in the air
        Direction = new Vector3(commands.sideMove * airStrafeSpeed, 0, commands.forwardMove);            
        Direction = transform.TransformDirection(Direction);

        float Speed = Direction.magnitude;
        Speed *= movementSpeed;

        Direction.Normalize();
        moveDirectionNorm = Direction;
        Speed *= Scale;

        /* Air control */
        float AirSpeed = Speed;
        if (Vector3.Dot(playerVelocity, Direction) < 0f)
            Acceleration = airDecceleration;
        else
            Acceleration = airAcceleration;

        // If the player is ONLY strafing left or right
        if (commands.forwardMove == 0 && commands.sideMove != 0)                              
        {
            if (Speed > airStrafeSpeedGen)
                Speed = airStrafeSpeedGen;
            Acceleration = airStrafeAcceleration;
        }

        Accelerate(Direction, Speed, Acceleration);

        if (airControlPresicion > 0)
            AirControl(Direction, AirSpeed);

        // Apply gravity
        playerVelocity.y -= gravity * Time.deltaTime;

        // If the player jumps or they are falling, the landing sound will play when they hit the ground
        if (playerVelocity.y > 1 || playerVelocity.y < -1)
            landSoundPlayed = false;
    }

    private void AirControl(Vector3 Direction, float AirSpeed)
    {
        float ZSpeed;
        float Speed;
        float Dot;
        float K;

        // Air control only works when moving forward or backwards
        if (Mathf.Abs(commands.forwardMove) < 0.001 || Mathf.Abs(AirSpeed) < 0.001)            
            return;

        // Air control stops working if a strafe key is pressed
        if (Mathf.Abs(commands.sideMove) > 0)
            return;

        ZSpeed = playerVelocity.y;
        playerVelocity.y = 0;
        Speed = playerVelocity.magnitude;

        playerVelocity.Normalize();

        Dot = Vector3.Dot(playerVelocity, Direction);
        K = 32;
        K *= airControlPresicion * Dot * Dot * Time.deltaTime;

        // Change direction while slowing down
        if (Dot > 0)                                                                            
        {
            playerVelocity.x = playerVelocity.x * Speed + Direction.x * K;
            playerVelocity.y = playerVelocity.y * Speed + Direction.y * K;
            playerVelocity.z = playerVelocity.z * Speed + Direction.z * K;

            playerVelocity.Normalize();
            moveDirectionNorm = playerVelocity;
        }

        playerVelocity.x *= Speed;
        playerVelocity.y = ZSpeed;
        playerVelocity.z *= Speed;
    }

There must be some issue in the code which is making the player retain their speed even after slowing down, but I have tried for days to fix this issue with no results, I’m quite desperate now! Please help. Thanks in advance!

try this

    protected void OnControllerColliderHit( ControllerColliderHit hit ) {
        if( !Player.instance.Controller.isGrounded ) {
            if( Vector3.Dot ( hit.normal, moveDirection ) < 0 ) {
                moveDirection -= hit.normal * Vector3.Dot ( hit.normal, moveDirection );
            }
        }
    }

make sure the script is on the same object as the characterController.
feel free to add me on steam