LookAt 2D Equivalent?
Asked Answered
B

16

1

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.

Bastion answered 7/1 at 15:55 Comment(5)

Thanks so much. You just solved a problem I've been having for days!

Ney

thx dude. that rly helped

Cutaneous

Just wanted to drop in and say this code solved my issues of having my projectile instantiate with the wrong rotation. This code works great. Thank you!

Lumbar

transform.LookAt(Vector3(target.position.x , target.position.y , fixedZ));

Exsert

I tried using this code to make a gameobject to "follow" my cursor [48529-code.jpg|48529] But I get this problem where it believe that the position of my gameobject is (0,0) so I have to move my mouse down in the left corner to get the gameobject to rotate. What am I doing wrong? (I have the Camera as a child under my "player" gameobject, does that have anything to do with this?) Please help <3

Asseverate
M
0

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:

Mithridatism answered 7/1 at 15:55 Comment(2)

this isn't working for me, the sprite i'm having turn is moving and the farther it gets from the center the more uncontrollable it is, and the rotations seem to be reversed, up and down at right, but left and right are flipped. the only difference is my diff is the target - transform.postion where target is a vector3 of the object i'm trying to chase

Hibbler

Do not forget to view the answer at the bottom provided by @abar, if you need a simpler way.

Condensate
C
0

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

Cytoplasm answered 27/11, 2013 at 19:35 Comment(2)

Na, No Luck, just tried... Vector2 LookAtPoint = new Vector2(Target.transform.position.x, Target.transform.position.y); transform.LookAt(LookAtPoint); Is This what you mean?

Bastion

@Bastion That works fine for me. Make sure to keep your plane in mind. If you're working with the XY plane then that should work fine, but if you're working on the ZY plane then you'll have to do Vector2 LookAtPoint = new Vector2(Target.transform.position.z, Target.transform.position.y); transform.LookAt(new Vector3(0,LookAtPoint.y,LookAtPoint.x);

Caddoan
T
0

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);
Tedmann answered 7/1 at 15:57 Comment(0)
E
0
// 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;
Eaglewood answered 7/1 at 15:56 Comment(2)

This solution worked for my relative aim assist script.

Skindeep

Thank You!!!!!!! I went crazy because of my enemies didn't follow the Player. They disappeared! Then I saw that Transform.LookAt (...) caused the bug and now I know how to fix it. Thanks!!

Scorbutic
H
0

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);
Henhouse answered 3/3 at 12:14 Comment(2)

I know it is a bit late, but is it possible to make sprite rotate for a certain degree? I am using OnMouseDrag(), and I don't want it to juse follow mouse, but to skip 15 degrees.

Gaucho

I like your solution for it's simplicity and in this way you don't have to use .Normalize. What I did to make this piece of code result in a sprite really pointing forward to the target was simply to increase the angle with 270f. So you get: Vector3 dir = target.position - transform.position; float angle = Mathf.Atan2(dir.y,dir.x) * Mathf.Rad2Deg + 270; transform.rotation = Quaternion.AngleAxis(angle, Vector3.forward);

Steiger
M
0

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:

Mithridatism answered 7/1 at 15:55 Comment(2)

this isn't working for me, the sprite i'm having turn is moving and the farther it gets from the center the more uncontrollable it is, and the rotations seem to be reversed, up and down at right, but left and right are flipped. the only difference is my diff is the target - transform.postion where target is a vector3 of the object i'm trying to chase

Hibbler

Do not forget to view the answer at the bottom provided by @abar, if you need a simpler way.

Condensate
S
0

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.
Shawannashawl answered 7/1 at 15:57 Comment(0)
R
0

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);
	}
}
Rivy answered 7/1 at 15:58 Comment(0)
C
0

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)
);
Capitate answered 7/1 at 16:1 Comment(0)
E
0

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 ) );
Exsert answered 7/1 at 16:2 Comment(0)
L
0

@Bastion
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));
	}
}
Limousine answered 7/1 at 16:3 Comment(0)
A
0

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.

Americaamerican answered 8/1 at 9:52 Comment(5)

This IS genius. And it SHOULD be the accepted answer. I had to use transform.up for my solution but all the same, there's no need math functions. Bedurbedur

Mecklenburg

This made my day, why isn´t this the accepted answer??? Thank you so much!

Sprage

this code helped me half way. this code make the gameobject rotation to the target. but how can i make it move to the target?

Martinsen

I had an issue when using Camera.ScreenToWorldPoint(Input.mousePosition) as the target. Turns out that ScreenToWorld point returns -10 as the Z, so one simply needs to add (0, 0, 10).

Footway

It is too genius that I have to login my account and give you a vote!! This is really easy to understand and it makes me able to teach my students the 2DLookAt function on my lesson!! Thanks a lot!!

Tolbert
O
0

@Asseverate
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.

Overspill answered 7/1 at 16:9 Comment(0)
B
0
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]

Bel answered 7/1 at 16:3 Comment(0)
R
0

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));
}
Recompense answered 7/1 at 16:5 Comment(0)
P
0
Vector3 flip = Player.transform.position - transform.position;
if(flip.x > 0)
{
  GetComponent<SpriteRenderer>().flipX = false;
}
if (flip.x < 0)
{
  GetComponent<SpriteRenderer>().flipX = true;
}
Presence answered 7/1 at 16:6 Comment(0)
R
0

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;
}
Relapse answered 7/1 at 16:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.