LookAt 2D Equivalent?

Is there a Transform.LookAt() equivalent that will work for 2D?
Without turning the gameobject on it’s side that is…
Or alternatively does anyone have a workaround using Eulers or something ?
Thanks in advance :slight_smile:

Edit: Solution

Quaternion rotation = Quaternion.LookRotation(
    Target.transform.position - transform.position ,
    transform.TransformDirection(Vector3.up)
);
transform.rotation = new Quaternion( 0 , 0 , rotation.z , rotation.w );

Seams to work for what i am trying to achieve but please if anyone comes up with a better solution let me know.

3 Likes

Surely the simplest solution is:

transform.right = target.position - transform.position;

Maybe that hasn’t always been possible, but it sure beats messing about with Atan2.

Hi guys, I have same problem and this is work very nice for me :slight_smile:

Vector3 diff = Camera.main.ScreenToWorldPoint(Input.mousePosition) - transform.position;
diff.Normalize();  
float rot_z = Mathf.Atan2(diff.y, diff.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.Euler(0f, 0f, rot_z - 90);

I hope this work for you :slight_smile:

Given the right side of your sprite as the forward, and having a target as a Transform (your code has it as a game object), you can do it this way:

Vector3 dir = target.position - transform.position;
float angle = Mathf.Atan2(dir.y,dir.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.AngleAxis(angle, Vector3.forward);
// LookAt 2D
Vector3 target;

// get the angle
Vector3 norTar = (target-transform.position).normalized;
float angle = Mathf.Atan2(norTar.y,norTar.x)*Mathf.Rad2Deg;

// rotate to angle
Quaternion rotation = new Quaternion ();
rotation.eulerAngles = new Vector3(0,0,angle-90);
transform.rotation = rotation;

You could use vector2, it have only x and y coordinates.

Not sure if this is the most efficient way but works for me. I’m using it to keep my player facing my mouse.

Vector3 mousePos = new Vector3(Input.mousePosition.x, Input.mousePosition.y, 0);
myTrans.LookAt(Camera.main.ScreenToWorldPoint(mousePos), Vector3.forward);

Here’s what I do:

  • Create empty game object
  • Make sprite child of game object
  • Rotate 90 degrees on y-axis (your rotation may differ) so front of sprite is facing parent’s Z-axis
  • When LookAt() called on parent, previously empty gameobject, Z-axis is front. Since child is rotated locally so its front is facing the parent gameobject’s Z-axis, LookAt() works fine.

Try this:

using UnityEngine;
using System.Collections;

public class JumpScript : MonoBehaviour
{
	public int playerSpeed = 5;
	private float rotationx;
	private float rotationy;
	private Vector3 touchcoordinates;
	private Transform myTrans;
	private bool RestartButton_Bool;
	public Transform background_map;
	public Touch touch1;
	public GameObject GameoverText;
		
	void Start ()
	{
		//Caching of the variables
		myTrans = this.transform;
	}
		
	// Update is called once per frame
	void Update () 
	{
		//Keep the character without any rotation
		myTrans.rotation = Quaternion.Euler(0,0,0);
		//Check to see if the app is running over iOS or Android Devices
		if (Application.platform == RuntimePlatform.IPhonePlayer || Application.platform == RuntimePlatform.Android)
		{
			//Get touch data
			foreach (Touch touch in Input.touches) 
			{
				touch1 = touch;
				touchcoordinates = touch.position;
				//Coverting touch coordinates in accordance with game use.
				Ray ray = Camera.main.ScreenPointToRay(touchcoordinates); 
				transform.LookAt(ray.GetPoint(-1000),Vector3.forward);
		
			}
			touchcoordinates = touch1.position;
		}
		
		//Check if the app is ruuning anywhere other than Mobile devices
		else 
		{
			//Coverting touch coordinates in accordance with game use.
			Ray ray1 = Camera.main.ScreenPointToRay(Input.mousePosition);
			transform.LookAt(ray1.GetPoint(-1000),Vector3.forward);
		}
		//Moving the character forward
		transform.Translate(Vector2.up * Time.deltaTime * 5);
	}
}

There are several solutions explained at dph blog:

https://web.archive.org/web/20160324171304/https://www.dphsw.co.uk/blog/?p=172

I think the simplest is:

transform.LookAt(
    Vector3.forward ,
    Vector3.Cross(Vector3.forward,direction)
);

This might be most efficient imho:

fixedZ = -90;// Or whatever value is needed to set correct facing of your object. Play with this.
transform.LookAt( new Vector3( target.position.x , target.position.y , fixedZ ) );

@LEDWORKS
While i realize that this is an old question, i wanted to share my easy to use solution.
Just stick this in an empty C# file somewhere in your project. a LookAt2D will magically appear :slight_smile:
I just whipped this up after spending some time trying all of your solutions, none of which quite worked for me.

/** copyright Leroy Ketelaars, 2015. 
 * I hereby license the entire human race to use this code as they see fit, 
 * provided they maintain this license in their source code as-is. 
 * A credit mention in your resulting work would be appreciated. */

using UnityEngine;
using System.Collections;
  
public static class TransformExtensions {
	public static void LookAt2D(this Transform t, Vector3 worldPosition) {
		t.rotation = Quaternion.identity;
		t.Rotate(Vector3.forward, (Mathf.Atan2(t.position.y - worldPosition.y, t.position.x - worldPosition.x) * 180 / Mathf.PI) - 180f);
	}
	public static void LookAt2D(this Transform t, Transform target) {
		t.rotation = Quaternion.identity;
		t.Rotate(Vector3.forward, (Mathf.Atan2(t.position.y - target.position.y, t.position.x - target.position.x) * 180 / Mathf.PI) - 180f);
	}
	public static void LookAwayFrom2D(this Transform t, Vector3 worldPosition) {
		t.rotation = Quaternion.identity;
		t.Rotate(Vector3.forward, (Mathf.Atan2(t.position.y - worldPosition.y, t.position.x - worldPosition.x) * 180 / Mathf.PI));
	}
	public static void LookAwayFrom2D(this Transform t, Transform target) {
		t.rotation = Quaternion.identity;
		t.Rotate(Vector3.forward, (Mathf.Atan2(t.position.y - target.position.y, t.position.x - target.position.x) * 180 / Mathf.PI));
	}
}

@Cladnic
You need to draw a raycast through the camera itself into the worldspace to accurately put the cursor on screen. You completely have to for 3D and I use it in my 2D games as well, it seems to work better when you don’t want to worry about screen resolution come build time. My example code is in 3D but for 2D you just don’t lock the y axis.

Implementing this method also gives you the ability to restrict the movement of the cursor to a designated area using the layerMask parameter. For making it follow your cursor you just use Vector3.MoveTowards and feed it a movement speed like this:

Physics.Raycast(cameraMain.ScreenPointToRay(Input.mousePosition), out rayCasthit, maxDistanceToRaycast, groundLayer);  
float movementSpeed = 30f;
float stepTowardsPointer = MovementSpeed * Time.deltaTime;
Vector3 newPosition = Vector3.MoveTowards(transform.position, rayCasthit.point, stepTowardsPointer);
transform.position = newPosition;

I’d also recommend going a step further and making sure your mouse is in an area it should be able to move to, and making sure if the target trails too far behind the cursor it catches up. Here’s an example from an async-multiplayer game where the second player used the mouse to control a reticle while the first player controlled the primary location of the screen.

[SerializeField]
LayerMask groundLayer; 
[SerializeField]
Transform player1Transform;
[SerializeField]
float maxDistanceBetweenPlayers = 50f;
[SerializeField]
float maxCursorUpPercent = .66f;
[SerializeField]
float movementSpeed;
[SerializeField]
float followSpeedIncreaseRange = 20f;
private void Move()
{
    RaycastHit rayCasthit;
    float maxDistanceToRaycast = 500f;
    //raycast from the cursor location on screen
    bool isCollidingWithGround = Physics.Raycast(cameraMain.ScreenPointToRay(Input.mousePosition), out rayCasthit, maxDistanceToRaycast, groundLayer);
    bool isPlayerWithinMaxDistanceBetweenCharacters = Mathf.Abs(Vector3.Distance(player1Transform.position, transform.position)) <= maxDistanceBetweenPlayers;
    bool isCursorCloserToOtherPlayer = Vector3.Distance(player1Transform.position, transform.position) > Vector3.Distance(rayCasthit.point, player1Transform.position);
    bool mouseIsInAllowableArea = Input.mousePosition.y <= (maxCursorUpPercent * Screen.height);
    bool PlayerCanMove = isCollidingWithGround && (isPlayerWithinMaxDistanceBetweenCharacters || isCursorCloserToOtherPlayer) && mouseIsInAllowableArea;
    if (PlayerCanMove)
    {
        bool isInFollowRange = (Vector3.Distance(transform.position, rayCasthit.point) <= followSpeedIncreaseRange);
        float tempMovementSpeed = movementSpeed;
  
        if (!isInFollowRange)
            tempMovementSpeed *= 5f;
  
        float stepTowardsPointer = tempMovementSpeed * Time.deltaTime;
  
        Vector3 newPosition = Vector3.MoveTowards(transform.position, rayCasthit.point, stepTowardsPointer);
        transform.position = new Vector3(newPosition.x, 0.0f, newPosition.z);
        
    }
}

Hope this helps. I tried commenting where your comment was but I seem to be having some browser issues with the submit button.

public static void LookAt2D(Transform me, Vector2 eye, Vector2 target)
{
    Vector2 look = target - (Vector2)me.position;
    float angle = Vector2.Angle(eye, look);
    Vector2 right = Vector3.Cross(Vector3.forward, look);
    int dir = 1;
    if (Vector2.Angle(right, eye) < 90)
    {
        dir = -1;
    }
    me.rotation *= Quaternion.AngleAxis(angle * dir, Vector3.forward);
}

[101895-безымянныи.png|101895]

I think this is the best one. Insert the tag of the object that u want to look at
and play with the offset

public string Tag;
public float offset;
private Transform target;
private Vector3 targetPos;
private Vector3 thisPos;
private float angle;

void Start ()
{
    target = GameObject.FindGameObjectWithTag(Tag).GetComponent<Transform>();
}

void LateUpdate ()
{
    targetPos = target.position;
    thisPos = transform.position;
    targetPos.x = targetPos.x - thisPos.x;
    targetPos.y = targetPos.y - thisPos.y;
    angle = Mathf.Atan2(targetPos.y, targetPos.x) * Mathf.Rad2Deg;
    transform.rotation = Quaternion.Euler(new Vector3(0, 0, angle + offset));
}
Vector3 flip = Player.transform.position - transform.position;
if(flip.x > 0)
{
  GetComponent<SpriteRenderer>().flipX = false;
}
if (flip.x < 0)
{
  GetComponent<SpriteRenderer>().flipX = true;
}

This works, but sucks:

void LookAt ( Vector3 target )
{
    Vector3 moveDirection = target - transform.position;
    float angle = Angle(moveDirection);
    angle = (angle >= 90.0f) ? angle - 90.0f : 270.0f + angle;
    transform.rotation = Quaternion.AngleAxis(angle, Vector3.forward);
}	
// Return the angle in degrees of vector v relative to the x-axis. 
// Angles are towards the positive y-axis (typically counter-clockwise) and between 0 and 360.
public float Angle ( Vector2 v )
{
    float angle = (float)Mathf.Atan2(v.y, v.x) * Mathf.Rad2Deg;
    if (angle < 0) angle += 360;
    return angle;
}