Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

[Solved] Diagonal movement speed issue

Discussion in 'Scripting' started by Comafly, Feb 4, 2016.

  1. Comafly

    Comafly

    Joined:
    May 30, 2014
    Posts:
    87
    Hello. I am attempting to move my player up, down, left, and right on a 2d plane. However, I was getting what is apparently a common issue where diagonal movement was compounded by 2 different vectors equalling more than 1. The solution, apparently, is to normalize the vectors and then use those normalized vectors to move the object at the end of the function.

    The problem I am having now is that I can no longer move up or down, it only allows me to move left or right, and I can't figure out why. I had some Debug.Logs in each if statement, and two directions were always returned, never one. Always Up+Left/Right or Down+Left/Right. I am very confused. I guess it's something to do with how I have ordered the code, but I am at a loss

    Any help is greatly appreciated.

    Code (csharp):
    1. public void playerMovement()
    2.     {
    3.         //Stop the player from rotating from the effects of RigidBody2D
    4.         rb.freezeRotation = true;
    5.        
    6.         //Up and down
    7.         if (player.GetAxis("Move Vertical") > 0f){
    8.             dir = "up";
    9.             vec = Vector2.up;
    10.             sp = playerRunUp;
    11.         }else if (player.GetAxis("Move Vertical") < 0f){
    12.             dir = "down";
    13.             vec = Vector2.down;
    14.             sp = playerRunDown;
    15.         }
    16.         //Left and right
    17.         if (player.GetAxis("Move Horizontal") < 0f){
    18.             dir = "left";
    19.             vec = Vector2.left;
    20.             sp = playerRunLeft;
    21.         }else if (player.GetAxis("Move Horizontal") > 0f){
    22.             dir = "right";
    23.             vec = Vector2.right;
    24.             sp = playerRunRight;
    25.         }
    26.         if (player.GetAxis ("Move Horizontal") != 0 || player.GetAxis ("Move Vertical") != 0) {
    27.             rb.AddForce (vec.normalized * accel);
    28.         }
    29.  
    30.     }
     
  2. A.Killingbeck

    A.Killingbeck

    Joined:
    Feb 21, 2014
    Posts:
    483
    Just so I understand correctly, you do want to be able to move diagonally?
     
  3. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    what is "player" in that script? GetAxis(...) is a static function on the Input class... looks very odd o_O

    you're not combining the up/down and left/right vectors, you're simply overwritting the "vec" each time. So if there is any form of horizontal input it'll overwrite "vec" with a horizontal vector
     
    Comafly likes this.
  4. Comafly

    Comafly

    Joined:
    May 30, 2014
    Posts:
    87
    Woops, sorry. Should have mentioned I am using Rewired for joystick input. player.GetAxis is essentially the same as Input.GetAxis.

    AKillingbeck. I was able to move diagonally fine, before I attempted to normalize the vectors and remove the AddForce from the individual Axis checks.

    For instance, this code, where I have moved the AddForce back in to the axis checks, moves my player diagonally just fine, but it faces the issue of compounding Vectors that make diagonal movement FASTER than either horizontal or vertical movement.

    Code (csharp):
    1. public void playerMovement()
    2.     {
    3.  
    4.         //Stop the player from rotating from the effects of RigidBody2D
    5.         rb.freezeRotation = true;
    6.      
    7.         //Directional Inputs
    8.         if (player.GetAxis("Move Vertical") > 0f){
    9.             dir = "up";
    10.             vec = Vector2.up;
    11.             sp = playerRunUp;
    12.             rb.AddForce (vec.normalized * accel);
    13.         }else if (player.GetAxis("Move Vertical") < 0f){
    14.             dir = "down";
    15.             vec = Vector2.down;
    16.             sp = playerRunDown;
    17.             rb.AddForce (vec.normalized * accel);
    18.         }
    19.         if (player.GetAxis("Move Horizontal") < 0f){
    20.             dir = "left";
    21.             vec = Vector2.left;
    22.             sp = playerRunLeft;
    23.             rb.AddForce (vec.normalized * accel);
    24.         }else if (player.GetAxis("Move Horizontal") > 0f){
    25.             dir = "right";
    26.             vec = Vector2.right;
    27.             sp = playerRunRight;
    28.             rb.AddForce (vec.normalized * accel);
    29.         }
    30.     }
    That makes sense, LeftyRighty! I'll have a look at how I can change the code to take in all directional input. It is very late here, though, so maybe I should just sleep x__x
     
  5. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    you've skipped over the second part of my post.

    In this second lot of code you are updating and then using "vec" to apply a force of the rigidbody in each part of the if/else. So this is effectively "adding" the vertical vector to the rigidbody then, later on, "adding" the horizontal vector.

    In the first lot of code you update "vec" to be a new value in each if/else and only actually apply anything to the rigidbody at the end, as such the vertical vector is ignored if there is a horizontal vector as "vec" is overwritten.

    Given that you're using an input addin this might not be directly applicable, but basic movement would be achieve with something such as:

    Code (csharp):
    1.  
    2. // you're setting the vec to "up""down" etc. so you might as well just use "Raw" input
    3. float h = Input.GetAxisRaw("Horizontal");
    4. float v = Input.GetAxisRaw("Vertical");
    5.  
    6. // combine the horizontal and vertical inputs to build a vector
    7. Vector3 inputVector = new Vector3(h, 0, v);
    8.  
    9. // check we actually need to do something
    10. if(h != 0 || v != 0)
    11. {
    12. // apply the normalized vector as a force
    13.     rb.AddForce(inputVector.normalized * accel);
    14. }
    15.  
    (can't check the code, my unity is updating :confused: )
     
    Comafly likes this.
  6. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    for ease of reference, this is Pythagoras' Theorem at work. An input of 1 up and 1 across is sqrt(2) diagonally, which is roughly 1.4.
     
    flashframe and Comafly like this.
  7. Comafly

    Comafly

    Joined:
    May 30, 2014
    Posts:
    87
    Thanks for your help! That is far better than what I have written, however I am still getting the issue where I can only move horizontal and not vertical.

    Code (csharp):
    1. public void playerMovement()
    2.     {
    3.  
    4.         //Stop the player from rotating from the effects of RigidBody2D
    5.         rb.freezeRotation = true;
    6.  
    7.         h = player.GetAxis("Move Horizontal");
    8.         v = player.GetAxis("Move Vertical");
    9.  
    10.         inputVector = new Vector3(h, 0, v);
    11.  
    12.         Debug.Log ("H: "+h);
    13.         Debug.Log ("W: "+v);
    14.  
    15.         if(h != 0 || v != 0)
    16.         {
    17.             rb.AddForce(inputVector.normalized * accel);
    18.         }
    19.  
    20.     }
    I added a couple of logs in there to capture the h/v values. And it seems like they're constantly being set to zero as I move the joystick...



    Perhaps this is an issue with Rewired?

    Again, thanks so much for taking the time to help me out!
     
  8. flashframe

    flashframe

    Joined:
    Feb 10, 2015
    Posts:
    730
    Is your rigidbody 2D? Might want to use a Vector2 instead?

    eg.
    Vector2.normalized(h,v);

    (or if not, change it to Vector3(h, v, 0)?)
     
    LeftyRighty and Comafly like this.
  9. Comafly

    Comafly

    Joined:
    May 30, 2014
    Posts:
    87
    flashframe, you are a diamond! That was the issue. I think the fact that I can't pick up on the difference between Vector2 and Vector3 is a clear sign I should be sleeping instead of programming hahah.

    LeftyRighty your code suggestion works a treat now : D

    Thanks very much to both you and flashframe! Absolute legends.

    So for anyone that comes across this thread looking for help. This was the code that solved the issue (All credit to LeftyRighty):

    Code (csharp):
    1.  
    2. public void playerMovement()
    3.     {
    4.  
    5.         //Stop the player from rotating from the effects of RigidBody2D
    6.         rb.freezeRotation = true;
    7.  
    8.         //Get the current joystick positions
    9.         h = player.GetAxis("Move Horizontal");
    10.         v = player.GetAxis("Move Vertical");
    11.  
    12.         //Take the v/h position of the joystick and place them in to a new vector2 (or 3 if you are using vector3s)
    13.         inputVector = new Vector2(h, v); //(h, 0, v) for vector 3
    14.  
    15.         //If the joystick is being moved, apply the addforce to the normalized vector
    16.         if(h != 0 || v != 0)
    17.         {
    18.             rb.AddForce(inputVector.normalized * accel);
    19.         }
    20.  
    21.     }
     
    Last edited: Feb 4, 2016
    psanatovs, LeftyRighty and flashframe like this.