Search Unity

Achieve slower movement when strafing/walking backwards

Discussion in 'Scripting' started by Josiah_Ironclad, Jan 18, 2020.

  1. Josiah_Ironclad

    Josiah_Ironclad

    Joined:
    Sep 24, 2019
    Posts:
    156
    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:
    Code (CSharp):
    1.     CharacterController characterController;
    2.  
    3.     public float walkSpeed;
    4.     public float runSpeed;
    5.  
    6.     float xInput;
    7.     float yInput;
    8.     public Vector3 movement;
    9.  
    10.     public bool running;
    11.  
    12.     void Awake() {
    13.         characterController = GetComponent<CharacterController>();
    14.     }
    15.  
    16.     void Update() {
    17.  
    18.         xInput = Input.GetAxisRaw("Horizontal");
    19.         yInput = Input.GetAxisRaw("Vertical");
    20.  
    21.         if (Input.GetKey(KeyCode.LeftShift)) running = true;
    22.         else running = false;
    23.     }
    24.  
    25.     void FixedUpdate() {
    26.  
    27.         movement = transform.right * xInput + transform.forward * yInput;
    28.      
    29.         if (running == false) movement = movement.normalized * walkSpeed;
    30.         else movement = movement.normalized * runSpeed;
    31.  
    32.         characterController.SimpleMove(movement);
    33.     }
    34.  
    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.
     
    Last edited: Jan 18, 2020
  2. Yoreki

    Yoreki

    Joined:
    Apr 10, 2019
    Posts:
    2,605
    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 :)
     
  3. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,336
    Read the post before you give advice - they're not asking about what you're answering, and they're already normalizing the move input.

    @UnityGenericAnon, 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:

    Code (csharp):
    1. movement = transform.right * xInput + transform.forward * yInput
    2. movement = movement.normalized;
    3.  
    4. //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.
    5. var forwardsAmount = Vector3.Dot(transform.forwards, movement);
    6.  
    7. if (forwardsAmount < -.5f) {
    8.     isWalkingBackwards = true;
    9.     isStrafing = false;
    10. }
    11. else if (forwardsAmount < .5f) {
    12.     isWalkingBackwards = false;
    13.     isStrafing = true;
    14. }
    15. else {
    16.     isWalkingBackwards = false;
    17.     isStrafing = false;
    18. }
    19.  
    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.
     
    Yoreki and Josiah_Ironclad like this.
  4. Josiah_Ironclad

    Josiah_Ironclad

    Joined:
    Sep 24, 2019
    Posts:
    156
    Thank you! Got it working exactly how I want.

    Here's the code for others:

    Code (CSharp):
    1.     CharacterController characterController;
    2.  
    3.     public float currentSpeed;
    4.  
    5.     public float walkSpeed;
    6.     public float runSpeed;
    7.     public float strafeSpeed;
    8.     public float backwardsSpeed;
    9.  
    10.     float xInput;
    11.     float yInput;
    12.     public Vector3 movement;
    13.  
    14.     public bool running;
    15.     public bool isStrafing;
    16.     public bool isWalkingBackwards;
    17.  
    18.     void Awake() {
    19.         characterController = GetComponent<CharacterController>();
    20.     }
    21.  
    22.     void Update() {
    23.  
    24.         xInput = Input.GetAxisRaw("Horizontal");
    25.         yInput = Input.GetAxisRaw("Vertical");
    26.  
    27.         if (Input.GetKey(KeyCode.LeftShift)) running = true;
    28.         else running = false;
    29.  
    30.         float forwardsAmount = Vector3.Dot(transform.forward, movement);
    31.  
    32.         if (forwardsAmount < -.5f) {
    33.             isWalkingBackwards = true;
    34.             isStrafing = false;
    35.         }
    36.  
    37.         else if (forwardsAmount < .5f) {
    38.             isWalkingBackwards = false;
    39.             isStrafing = true;
    40.         }
    41.  
    42.         else {
    43.             isWalkingBackwards = false;
    44.             isStrafing = false;
    45.         }
    46.  
    47.         if (movement != Vector3.zero) {
    48.  
    49.             if (isStrafing == true) currentSpeed = strafeSpeed;
    50.             else if (isWalkingBackwards == true) currentSpeed = backwardsSpeed;
    51.             else currentSpeed = walkSpeed;
    52.            
    53.             if (running == true) currentSpeed *= 2;
    54.         }
    55.  
    56.         else currentSpeed = walkSpeed;
    57.     }
    58.  
    59.     void FixedUpdate() {
    60.  
    61.         movement = transform.right * xInput + transform.forward * yInput;
    62.  
    63.         movement = movement.normalized * currentSpeed;
    64.  
    65.         characterController.SimpleMove(movement);
    66.     }
    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.
     
    Last edited: Jan 19, 2020