Player rapidly accelerating instead of stopping

I am creating a 2D platformer and right now I have just the basics. I am relying on the built-in physics engine to move my player, but I’ve encountered a problem. Basically, you use the arrow keys to move left and right and Shift to run, and that works fine if you stop running before you stop moving. However if you let go of the arrow key before letting go of shift, the player will rapidly accelerate toward whichever direction you’d been moving in. Why is this happening?

Here’s my code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour {

    // declare variables
    public float walkSpeed, maxRunMultiplier, accelerationSpeed, deccelerationSpeed, jumpPower, wallJumpPower; // speed and stuff of things
    ...
    public float runMultiplier = 1; // for running
    bool running;

    Transform groundCheck, faceCheck, ceilingCheck;
    Animator anim;
    Rigidbody2D rig;
    Vector2 movementInput;

    void Start()
    {
        ...
    }

    void Update()
    {
        // get input
        GetInput();

        ...

        // assign new velocity
        Vector2 newVelocity = Vector2.zero;
        Vector2 curVelocity = rig.velocity; // for shorthand

        // left and right movement
        if (movementInput.x > 0.1f)
        {
            if (curVelocity.x <= walkSpeed)
            {
                newVelocity.x = curVelocity.x + accelerationSpeed;
            }
            else
            {
                newVelocity.x = walkSpeed;
            }
        }
        else if (movementInput.x < -0.1f)
        {
            if(curVelocity.x >= -walkSpeed)
            {
                newVelocity.x = curVelocity.x - accelerationSpeed;
            }
            else
            {
                newVelocity.x = -walkSpeed;
            }
        }
        else
        {
            if(curVelocity.x >= deccelerationSpeed)
            {
                newVelocity.x = curVelocity.x - deccelerationSpeed;
            }
            else if (curVelocity.x <= -deccelerationSpeed)
            {
                newVelocity.x = curVelocity.x + deccelerationSpeed;
            }
            else
            {
                newVelocity.x = 0;
            }
        }

        newVelocity.x *= runMultiplier;

    ...

    // get input
    void GetInput()
    {
        // horizontal
        if(Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow))
        {
            if(!Input.GetKey(KeyCode.D) && !Input.GetKey(KeyCode.RightArrow))
            {
                movementInput.x = -1;
            }
            else
            {
                movementInput.x = 0;
            }
        }
        else if(Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow))
        {
            if (!Input.GetKey(KeyCode.A) && !Input.GetKey(KeyCode.LeftArrow))
            {
                movementInput.x = 1;
            }
            else
            {
                movementInput.x = 0;
            }
        }
        else
        {
            movementInput.x = 0;
        }

        // run test
        if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift))
        {
            runMultiplier = maxRunMultiplier;
        }
        else
        {
            runMultiplier = 1;
        }
    }
}

What’s wrong with it? I’m guessing it has something to do with multiplying by the runVelocity, but I don’t know.


UPDATE 1: I made it only multiply if the movementInput.x wasn’t zero, and that sort of worked, but now if you hold shift, run in one direction, and run in the other as you let go of the first direction it still happens, accelerating you in the direction of the first direction. The code above changed from:

newVelocity.x *= runMultiplier;

To this:

if (movementInput.x < -0.5f || movementInput.x > 0.5f)
{
    newVelocity.x *= runMultiplier;
}

i think you should use newVelocity.x = runMultiplier. What you are doing is multiplying the newVelocity with multiplier EVERY frame.

If newvelocity = 1 and run multiplier = 2. Eachframe it is going to do:

f1 - newvelocity = 1 * 2 = 2

f2 - newvelocity = 2 * 2 = 4

f3 - newvelocity = 4 * 2 = 8

Its accelerating because its exponential, you are forgetting the fact that everything on that function runs on every frame, So each frame the multiplication happens with the value of the product of the last frame.

The most simple solution is to no use multipliers in my opinion. Just assign values, so it assigns the same value all frames and it is only dependant of your bools. You can use differente values and do something like newVelocity = multiplier * baseVelocity, that would also keep it the same everyframe. It depends on what you need in the future on how to handle it, but is simple. Hope it helps.