Achieve slower movement when strafing/walking backwards

I’ve got a first person script for walking relative to the camera, and I want the player to move considerably slower when strafing, and even slower when walking backwards.

Here’s my current script:

    CharacterController characterController;

    public float walkSpeed;
    public float runSpeed;

    float xInput;
    float yInput;
    public Vector3 movement;

    public bool running;

    void Awake() {
        characterController = GetComponent<CharacterController>();
    }

    void Update() {

        xInput = Input.GetAxisRaw("Horizontal");
        yInput = Input.GetAxisRaw("Vertical");

        if (Input.GetKey(KeyCode.LeftShift)) running = true;
        else running = false;
    }

    void FixedUpdate() {

        movement = transform.right * xInput + transform.forward * yInput;
     
        if (running == false) movement = movement.normalized * walkSpeed;
        else movement = movement.normalized * runSpeed;

        characterController.SimpleMove(movement);
    }

I’ve been up for a while, and currently I just don’t have the brain power to work with logic. I had attempts with multiplying the input in various ways, and completely changing the script so the data is processed in different ways, but so far nothing worked. Either all directions of movement get affected at once, or there’s some weird behaviours happening.

There’s definitely tutorials that cover strafing, but they will most likely use their own movement system, and I’d have to first inspect it then adapt their strafing mechanics into my code (once again, currently don’t have the brain power for this). And I don’t know of any tutorials that cover backwards movement speed separately.

Hello,
you are going faster since you are just adding inputs for the right and forward direction together. So if both are pressed, your effective speed is doubled. I can generally recommend you the tutorial series by Sebastian Lague on character controllers (involved moving, jumping, being controlled by the camera, playing the correct animation and more):

Your problem, however, is rather simple. Instead of having xInput and yInput, create a vector with these two values, then normalize it. This makes it have a length of 1, thus no matter if one or both (or in case of a joystick, both some amount) are pressed, the total length of the vector will be the same. You can now use this vector in your further calculations. For a more in depth example and explanation i can again recommend the series i linked above. If you dont care about animations, relevant parts start at ~6:30.

Hope this helps :slight_smile:

Read the post before you give advice - they’re not asking about what you’re answering, and they’re already normalizing the move input.

@Josiah_Ironclad , this kind of thing is where it’s useful to know the dot product. So if you dot your character’s forwards vector with the movement, you can figure out if you’re strafing or walking backwards or not.

Something like:

movement = transform.right * xInput + transform.forward * yInput
movement = movement.normalized;

//For normalized vectors Dot returns 1 if they point in exactly the same direction, -1 if they point in completely opposite directions and zero if the vectors are perpendicular.
var forwardsAmount = Vector3.Dot(transform.forwards, movement); 

if (forwardsAmount < -.5f) {
    isWalkingBackwards = true;
    isStrafing = false;
}
else if (forwardsAmount < .5f) {
    isWalkingBackwards = false;
    isStrafing = true;
}
else {
    isWalkingBackwards = false;
    isStrafing = false;
}

Then you use the isWalkingBackwards and isStrafing values to scale the speed down. You probably want to turn -.5 and .5 into fields you can edit in the inspector.

2 Likes

Thank you! Got it working exactly how I want.

Here’s the code for others:

    CharacterController characterController;

    public float currentSpeed;

    public float walkSpeed;
    public float runSpeed;
    public float strafeSpeed;
    public float backwardsSpeed;

    float xInput;
    float yInput;
    public Vector3 movement;

    public bool running;
    public bool isStrafing;
    public bool isWalkingBackwards;

    void Awake() {
        characterController = GetComponent<CharacterController>();
    }

    void Update() {

        xInput = Input.GetAxisRaw("Horizontal");
        yInput = Input.GetAxisRaw("Vertical");

        if (Input.GetKey(KeyCode.LeftShift)) running = true;
        else running = false;

        float forwardsAmount = Vector3.Dot(transform.forward, movement);

        if (forwardsAmount < -.5f) {
            isWalkingBackwards = true;
            isStrafing = false;
        }

        else if (forwardsAmount < .5f) {
            isWalkingBackwards = false;
            isStrafing = true;
        }
 
        else {
            isWalkingBackwards = false;
            isStrafing = false;
        }

        if (movement != Vector3.zero) {

            if (isStrafing == true) currentSpeed = strafeSpeed;
            else if (isWalkingBackwards == true) currentSpeed = backwardsSpeed;
            else currentSpeed = walkSpeed;
            
            if (running == true) currentSpeed *= 2;
        }

        else currentSpeed = walkSpeed;
    }

    void FixedUpdate() {

        movement = transform.right * xInput + transform.forward * yInput;
  
        movement = movement.normalized * currentSpeed;

        characterController.SimpleMove(movement);
    }

They way I set the if/else statements up, the backwards and forwards movements will override strafing speed. So if you’re walking diagonally backwards it will use backwards speed, and walk speed for moving diagonally forwards.