Search Unity

Look rotation 2d equivalent

Discussion in '2D' started by Tempest74, Jan 11, 2019.

  1. Tempest74

    Tempest74

    Joined:
    May 17, 2017
    Posts:
    133
    Code (CSharp):
    1. Quaternion targetRotation = Quaternion.LookRotation(path.lookPoints[pathIndex] - transform.position);
    2.                     transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, turnSpeed);
    3.                     transform.Translate(Vector3.right * speed * Time.deltaTime,Space.Self)
    My piece of code is above. I am following a tutorial for a 3d pathfinding script, but I use it for a 2d game. Everything worked fine until now, but I got in some mathematical trouble, i think it is good to say. My gameobjects are places into a xy axis coordinate. I want to face them one toward another, so I tried using Quaternion.LookRotation, and it changed the rotation on x and y axis but apparently i need to rotate it on z axis (for no reason known to me). Any help?
     
  2. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    The Z axis is depth in a 2D game. It is known as the "forward" axis in Unity. In 2D games however, generally it is the object's X axis that represent its forward direction.

    2D objects are like pieces of paper on a table. To rotate the paper, you dont flip it over (rotate on x axis or y axis), you can only turn it while keeping it flat on the table (z axis rotation). You can observe this in the editor by rotating sprites on each axis. (exceptions being like, the paper mario turning effect)

    You can use LookRotation, but you have to understand what that function is asking you for, and what it does to your object in order to use it properly.

    https://docs.unity3d.com/ScriptReference/Quaternion.LookRotation.html

    The function wants you to tell it where the 3D forward axis (z) and the up axis (y) should be pointing, and it will give you a rotation with the axes pointing in those directions. It does not handle the X axis directly, it will set Z and Y, and the X will lie where it falls. (90 degrees away from both of those axes)

    Keep in mind that it's usually used to point a 3D object's "forward" axis (Z) at something, where the object's "up" axis is assumed to be (0,1,0), which in 3D is up towards the sky. If you don't pass an up vector, it will default to (0,1,0).

    Since you want your object to point its X axis towards another object, we have to supply the correct Z and Y axes to make that happen.

    3D "Forward" Z Axis:
    A 2D object is always flat on the XY plane, so the Z axis always points forward perfectly, so we know that we want the Z axis to end up as (0,0,1), or Vector3.forward for shorthand.

    3D "Up" Y Axis:

    We know that the Y axis is always 90 degrees away from the X axis (which is what we want to end up pointing at the target), so we can either point the Y axis at the target, then rotate 90 degrees counterclockwise afterwards, or rotate first and then pass in the rotated Y direction. I'm going to show you the second option.

    Code (CSharp):
    1. Vector3 myLocation = transform.position;
    2. Vector3 targetLocation = path.lookPoints[pathIndex];
    3. targetLocation.z = myLocation.z; // ensure there is no 3D rotation by aligning Z position
    4.  
    5. // vector from this object towards the target location
    6. Vector3 vectorToTarget = targetLocation - myLocation;
    7. // rotate that vector by 90 degrees around the Z axis
    8. Vector3 rotatedVectorToTarget = Quaternion.Euler(0, 0, 90) * vectorToTarget;
    9.  
    10. // get the rotation that points the Z axis forward, and the Y axis 90 degrees away from the target
    11. // (resulting in the X axis facing the target)
    12. Quaternion targetRotation = Quaternion.LookRotation(forward: Vector3.forward, upwards: rotatedVectorToTarget);
    13.  
    14. // changed this from a lerp to a RotateTowards because you were supplying a "speed" not an interpolation value
    15. transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, turnSpeed * Time.deltaTime);
    16. transform.Translate(Vector3.right * speed * Time.deltaTime, Space.Self);
    You just have to work with the function in the way it's meant to be used. There are other ways to avoid this function and just do the math, but I find it's easier to read & understand this way, using a very common function.

    I hope you managed to follow that, if you have more questions let me know.
     
    Last edited: Dec 20, 2019
  3. Adam-E

    Adam-E

    Joined:
    Jan 9, 2013
    Posts:
    4
    You, sir, are a legend.
     
  4. Nevelson

    Nevelson

    Joined:
    Jan 18, 2016
    Posts:
    2
    You really are a legend. I've never taken a piece of code and had it worked perfectly for my use case. Thank you
     
    ledshok and LiterallyJeff like this.
  5. NikoBay

    NikoBay

    Joined:
    Aug 15, 2018
    Posts:
    39
    you, sir, are truly a legend. I've still not read any of your explanation but copying your code and it worked like a charm. Definitely save this post for later learning. Tks again.
     
    Kronington, ledshok and LiterallyJeff like this.
  6. parssa

    parssa

    Joined:
    Dec 27, 2017
    Posts:
    2
    This is the greatest reply to a forum I have ever read. Insanely useful stuff thank you so much
     
    ledshok likes this.
  7. EL-soNK

    EL-soNK

    Joined:
    Jul 13, 2015
    Posts:
    28
    This is awesome!
    But I need some assistance, probably because of my limited mind... it works for me when the object (sprite etc) is facing right by default. If the object which should turn is facing downwards by default (in my case an approaching enemy plane, coming from the top of the screen) it's not facing in the right direction. How can I change this? (I could change the objects to "always look right" -- but I'd prefer to really understand the logic and how I can alter the direction correctly by script).
    Any help would be highly appreciated!
     
  8. lucassivolella

    lucassivolella

    Joined:
    Jul 14, 2020
    Posts:
    6
    I'm making a 2D top-down shooter and I did not work for me, plus the projectile started moving exclusively to the right.
    I tried changing:
    Code (CSharp):
    1. transform.Translate(Vector3.right * speed * Time.deltaTime, Space.Self);
    to:
    Code (CSharp):
    1. transform.Translate(targetLocation * speed * Time.deltaTime, Space.Self);
    and the projectile sort of went in the player direction, but moving with absurd speed.

    What am I missing from LiterallyJeff code?

    So far I'm sticking to my original code, which lets the projectile follows the player, but without the rotation:
    Code (CSharp):
    1.         targetPosition = GameObject.FindGameObjectWithTag("Player").transform;
    2.         projectileDirection = new Vector2(targetPosition.position.x, targetPosition.position.y);
    3.         transform.position = Vector2.MoveTowards(transform.position, projectileDirection, projectileSpeed * Time.deltaTime);[/code
     
  9. lucassivolella

    lucassivolella

    Joined:
    Jul 14, 2020
    Posts:
    6

    I found a topic at the Answers.Unity to did exactly what I needed:
    https://answers.unity.com/questions/1392629/2d-top-down-how-to-get-enemy-to-face-my-player-cor.html

    My projectile following the player and rotating accordingly is one of the coolest thing I ever made in Unity, so far! Simple and, yet, cool af.
     
  10. bdilloughery_mvla

    bdilloughery_mvla

    Joined:
    Sep 22, 2017
    Posts:
    39
    Fantastic explanation. We were doing it all manually with Eulers before, but the looping around zero and 360 was getting funky. Thank you! This works perfectly.
     
    LiterallyJeff likes this.