Unity2D LookAt?!

Hello,

I have this method:

public static Quaternion FaceObject(Vector2 myPos, Vector2 targetPos)
    {
        Vector2 direction = targetPos - myPos;
        float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
        return Quaternion.AngleAxis(angle, Vector3.forward);
    }

This method gets called every second with the nearest enemy position as targetPos, and the position of the object for myPos.

Now the problem is, I first used transform.LookAt (didn’t work), then I searched for LookAt in 2D and tried different solutions, no of them worked. Does anyone know the solution?

Whole script:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;

public class BotScript : MonoBehaviour {

    public float health = 100f;
    public float framesUntilNextShoot = 90f;
    public GameObject shootPrefab = null;


    public static Quaternion FaceObject(Vector2 myPos, Vector2 targetPos)
    {
        Vector2 direction = targetPos - myPos;
        float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
        return Quaternion.AngleAxis(angle, Vector3.forward);
    }

    // Initalize player
    void Start()
    {
        float x = Random.Range(-4.1f, 4.1f);
        float y = Random.Range(-4, 3.8f);
        health = 100f;

        gameObject.transform.position = new Vector2(x, y);

    }

    void FixedUpdate()
    {
        framesUntilNextShoot -= 1;

        //if (DistanceToClosestEnemy() < 300f)
        //{
            GameObject go = FindClosestEnemy();

            this.transform.rotation = FaceObject((Vector2)transform.position, (Vector2)go.transform.position);

            if(framesUntilNextShoot == 0f)
            {
                framesUntilNextShoot = 90f;
                GameObject inst = Instantiate(shootPrefab, gameObject.transform.position, gameObject.transform.rotation);
                inst.transform.parent = this.transform;
                //print("Shoot pos: " + inst.transform.position.x + " " + inst.transform.position.y + " Script pos: " + this.transform.position.x + " " + this.transform.position.y + " GameObject pos: " + this.gameObject.transform.position.x + " " + this.gameObject.transform.position.y);
                inst.GetComponent<ProjectileScript>().StartShoot(go);
            }

            Vector2 movement = (1f * (this.transform.rotation * Vector2.up))*Time.deltaTime;
            this.transform.position = new Vector2(this.transform.position.x, this.transform.position.y) + movement;

        //}
    }

    // Update is called once per frame
    void Update () {
        if(health < 1)
        {
            Destroy(this.gameObject);
        }
    }

    private void LookAt(Transform go)
    {
        Vector2 direction = new Vector2(go.position.x - this.transform.position.x, go.transform.position.y - this.transform.position.y);
        float rotation = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
        this.transform.eulerAngles = new Vector3(0, 0, rotation);
    }

    public GameObject FindClosestEnemy()
    {
        GameObject[] gos;
        gos = GameObject.FindGameObjectsWithTag("Enemy").Concat(GameObject.FindGameObjectsWithTag("Player")).ToArray();
        GameObject closest = null;
        float distance = Mathf.Infinity;
        Vector3 position = transform.position;
        foreach (GameObject go in gos)
        {
            Vector3 diff = go.transform.position - position;
            float curDistance = diff.sqrMagnitude;
            if (curDistance < distance)
            {
                closest = go;
                distance = curDistance;
            }
        }
        return closest;
    }

    public float DistanceToClosestEnemy()
    {
        GameObject[] gos;
        gos = GameObject.FindGameObjectsWithTag("Enemy");
        GameObject closest = null;
        float distance = Mathf.Infinity;
        Vector3 position = transform.position;
        foreach (GameObject go in gos)
        {
            Vector3 diff = go.transform.position - position;
            float curDistance = diff.sqrMagnitude;
            if (curDistance < distance)
            {
                closest = go;
                distance = curDistance;
            }
        }
        return distance;
    }
}

You can use LookAt but you have to understand what it does, and what parameters it expects in order to get the result you want.

All the “Look” functions will be assuming that your object’s “forward” is the Z axis, as is the standard for 3D objects in Unity. Given a position, they will orient your object with the Z axis facing it.

For 2D objects, the “forward” axis is usually the X axis. The Z axis is pointing forward along the World Space Z axis so it appears flat to the camera as the sprite moves around on the XY plane. We don’t want that to change.

So instead we can use Quaternion.LookRotation, which accepts the Z and Y axis. We can tell it exactly which direction the Z and Y axis should face, which will result in the X axis pointing where we want.

public void LookAt2D(Vector3 lookTarget)
{
    // the direction we want the X axis to face (from this object, towards the target)
    Vector3 xDirection = (lookTarget - transform.position).normalized;

    // Y axis is 90 degrees away from the X axis
    Vector3 yDirection = Quaternion.Euler(0, 0, 90) * xDirection;

    // Z should stay facing forward for 2D objects
    Vector3 zDirection = Vector3.forward;
 
    // apply the rotation to this object
    transform.rotation = Quaternion.LookRotation(zDirection, yDirection);
}
2 Likes

I am using transform.up (right, -up, -right) as the lookAt in the 2d

Vector2 direction = targetPos - myPos;
transform.right = direction;
1 Like

Still not working (arrows show, where the top of their sprite should face)
4808684--460229--upload_2019-8-1_1-11-59.png

Not working… Is it may be just the prefab?
4808879--460244--upload_2019-8-1_2-35-31.png

Okay, fixed it.
The problem was the nearest entity was itself, so it tried to rotate to itself.