2D Rotate towards GameObject acting odd.

Hey, I am having a problem with a 2d (air)plane I am working on. It is a side scrolling game, and I want the plane to follow the player. To move I am using the rigidbody2D and to rotate I am using Quaternion LookAt. The problem is, when the aircraft exceeds the X position of the player, it goes in the opposite direction, so it’s moving away from the player instead of towards it. When it gets behind the player again ( X<=player X), it follows the player normally.

void FixedUpdate () 
{
    	Rotate ();
    	Move ();
}
    
void Rotate()
{	
	Quaternion newRotation = Quaternion.LookRotation (player.transform.position - transform.position);
	Quaternion newRot = Quaternion.Slerp(transform.rotation, newRotation, rotateSpeed * Time.deltaTime);
	transform.rotation = new Quaternion(0, 0, newRot.z, newRot.w);
}
    
void Move()
{
	rigidbody2D.AddForce (transform.right * flySpeed*8 * Time.deltaTime, ForceMode2D.Impulse);
    
	if(rigidbody2D.velocity.magnitude > flySpeed)
	{
		rigidbody2D.velocity = rigidbody2D.velocity.normalized * flySpeed;
	}
}

I want the aircraft to rotate with a rotatespeed, so it won’t instantly face the player, and has to make a nice loop when it needs to.
Can anyone help me with this? I’ve looked into multiple solutions, but haven’t found anything.

You should perform your calculations in local space not in world space.

You can rewrite your Rotate() method like this:

    void Rotate()
    {
        Vector2 dir = transform.InverseTransformPoint(player.transform.position);

        float angle = Vector2.Angle(Vector2.right, dir);

        angle = dir.y < 0 ? -angle : angle;

        transform.Rotate(Vector3.forward, rotateSpeed * Time.deltaTime * angle);
    }

This way you have a very simple but solid implementation of a follow script.

To prevent the follower to increase its angular velocity with the size of the angle you could
do the following:

    const float Threshold = 1e-3f;
    void Rotate()
    {
        Vector2 dir = transform.InverseTransformPoint(player.transform.position);

        float angle = Vector2.Angle(Vector2.right, dir);

        angle = dir.y < 0 ? -angle : angle;

        if (Mathf.Abs(angle) > Threshold)
        {
            transform.Rotate(Vector3.forward, rotateSpeed * Time.deltaTime * Mathf.Sign(angle));
        }
    }

Okay, so this is a little ‘hacky’ in that I create a new parent so that I can separate the rotation around z and the local rotation around x (to make the plane upright). There would be a way of doing this without the extra parent, but I should be wrapping presents and not spending hours on Quaternion rotations! :smiley:

The following should be attached to the highest object in your plane object hierarchy:

public float forwardSpeed = 5;
public float turnSpeed = 90;
public float twistSpeed = 180;
public Transform target;
Vector3 targetPos;
Transform this_transform;
Vector3 dir;
Transform parentT;
GameObject parentGO;

void Start(){
	this_transform = transform;
	parentGO = new GameObject("rotationControl");
	parentT = parentGO.transform;
	parentT.position = this_transform.position;
	this_transform.parent = parentT;
}

void FixedUpdate(){
	dir = new Vector3(target.position.x - parentT.position.x, target.position.y - parentT.position.y, 0);
	
	//Look rotation (around Z axis)
	Quaternion q = Quaternion.FromToRotation(Vector3.right, dir);
	parentT.rotation = Quaternion.RotateTowards(parentT.rotation, q, turnSpeed*Time.deltaTime);
	
	//Twist rotation (around local X axis)
	Quaternion q2 = Quaternion.identity;
	if(Mathf.Sign(dir.x) < 0){
		q2 = Quaternion.Euler(180, 0, 0);
	}
	this_transform.localRotation = Quaternion.RotateTowards(this_transform.localRotation, q2, twistSpeed*Time.deltaTime);
	
	//Movement (you can use your forces here, this was mainly for testing)
	parentT.position += parentT.right*Time.deltaTime*forwardSpeed;
}

This should turn the plane to face the target over time and upright the plane when it becomes upside-down, hopefully without causing any movement in the z axis (you may want to clamp the z value just to be safe)!

Merry Christmas/Happy Holidays!

Scribe