- Home /
Rotating a 2D sprite to face a target on a single axis.
Yes, yet another one of THESE questions. I know this has been asked numerous times before, but after scouring the board for days I can't find a solution.
My game is a top-down space shooter, I'm working in the 2D mode in unity (on the XY plane).
Basically when the player comes within a certain range of an enemy I'd like the enemy to turn and face the player. I'm using a circle collider w/trigger to do the detection and capture the target transform (the player's transform). That part works.
The issue (as always) is that the enemy will not turn around the Z-axis only when it turns. It rotates on all axis and usually ends up with the underside of the enemy sprite "facing" the player. When looking at it in 2D mode you end up looking at the edge of the sprite and it disappears.
Here is the code i'm using:
targetTransform = the player's transform
transform = the enemy's transform
Vector3 vectorToTarget = targetTransform.position - transform.position;
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(vectorToTarget,Vector3.forward), 1 * Time.deltaTime);
Here is the log output in a typical run.
TARGETPOS:(1.1, 1.4, 0.0) SELFPOS:(5.0, 5.0, 0.0) VECTOR:(-3.9, -3.6, 0.0)
All those look correct to me. I have a feeling the issue lies in how the rotation is being done.
Some solutions I have seen involve modifying the x or y components of the Quaternion that returns from Quaternion.LookRotation. While that does sort of work, I've also read numerous things that say to never modify the components on a Quaternion in that way.
example: http://forum.unity3d.com/threads/36377-transform-LookAt-or-Quaternion-LookRotation-on-1-axis-only
I am sort of lost here. Should I not be using Quaternions to do rotation in 2D? I'm also wondering if this could be caused by the game object being rotated. I'm thinking that possibly LookRotation is not sure what the front of the ship is. In the documentation for LookRotation there is this section:
Returns the computed quaternion. If used to orient a Transform, the Z axis will be aligned with forward and the Y axis with upwards if these vectors are orthogonal.
I'm not quite sure what they are saying here. Does this mean that LookRotation always assumes that Z is forward? How would that ever work in 2D mode?
Any suggestions/help would be appreciated.
http://i.imgur.com/cr3nBuH.png
http://i.imgur.com/b8lIz6u.png
EDIT: I can use :
transform.LookAt(transform.position + new Vector3(0,0,1), vectorToTarget);
to get it to work, but the rotation is immediate instead of a nice fluid turn over time that Slerp will provide.
Answer by robertbu · Feb 27, 2014 at 02:16 PM
Try this:
Vector3 vectorToTarget = targetTransform.position - transform.position;
float angle = Mathf.Atan2(vectorToTarget.y, vectorToTarget.x) * Mathf.Rad2Deg;
Quaternion q = Quaternion.AngleAxis(angle, Vector3.forward);
transform.rotation = Quaternion.Slerp(transform.rotation, q, Time.deltaTime * speed);
You will have to define a 'speed' variable or replace it with a constant. If you don't want the rotation eased, replace 'Slerp' with RotateTowards, and adjust 'speed'.
Thanks for the response, but that doesn't quite work. Although it does rotate around the z-axis, it doesn't end up pointing in the correct direction. It's not consistent in the direction it points either.
This code depends on the 'forward' of your sprite being the right side of your sprite. If you are using the top of your sprite, then you can rotate your texture in Photoshop, or you need to adjust the 'angle' before passing it to AngleAxis(). AS for not consistent, you will have to explain. Sometimes this happens because the pivot point you want to rotation around is not the same a the pivot point of the object. With sprites, you can usually fix this by selecting the texture and changing the Anchor in the Inspector.
Cool, I got it working by subtracting 90 from the angle like so:
float angle = ($$anonymous$$athf.Atan2(vectorToTarget.y, vectorToTarget.x) * $$anonymous$$athf.Rad2Deg) - 90;
Better then modifying all my textures. Thanks for the help!
As a follow-up, I guess that Quaternion.LookRotation doesn't work unless the object and axis are in very specific orientations?
Did the job for me too. Thanks @blernsball and @robertbu.
Correct. For LookAt() or LookRotation() to work without extra steps, the 'forward' of the object has to be facing positive 'z' when the rotation is (0,0,0).
Oh my god, thank you so much, I've been trying this for hours today! THAN$$anonymous$$ YOU!
Answer by servival · Jun 27, 2015 at 01:33 PM
This is a tank turret code that I've created and i hope it helps:
using UnityEngine;
using System.Collections;
public class AISmoothLookAT : MonoBehaviour {
public Transform target;
public Transform looker;
public Transform Xsmoothlooker;
public Transform Ysmoothlooker;
public float Xspeed = 2f;
public float Yspeed = 2f;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
looker.LookAt (target);
float YRotation = looker.eulerAngles.y;
float XRotation = looker.eulerAngles.x;
Xsmoothlooker.rotation = Quaternion.Slerp(Xsmoothlooker.rotation , Quaternion.Euler(0 , YRotation, 0), Time.deltaTime * Xspeed);
Ysmoothlooker.rotation = Quaternion.Slerp(Ysmoothlooker.rotation , Quaternion.Euler(XRotation , YRotation, 0), Time.deltaTime * Yspeed);
}
}
One more thing: Don't make the X rotating turret a child of Y rotating turret.
Answer by Frizack400 · Jul 04, 2017 at 10:06 AM
Hey I have had the same problem and think I have found a way to do this quite simply. I would love your imput as its both a question and an answer. http://answers.unity3d.com/questions/1373642/using-quaternions-in-2d-to-follow-a-rotation-both.html