Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Doom-like angle based sprite changing

So, i'm trying to make a first person game that used the same sprite mechanics as games like Doom, Duke Nukem and etc.

So far, i can identify the angle I'm at in relation to static objects, but not to rotating ones. I have some "enemies" that change rotation and start following me, but calculating the tangent angle (Mathf.Atan2) doesn't take the enemy's rotation in consideration.

Here's the code i'm using so far, which works perfectly for objects that dont rotate:

 int GetAngleIndex()
 {
    var dir = cam.transform.position - transform.parent.forward;
    var enemyAngle = Mathf.Atan2(dir.z, dir.x) * Mathf.Rad2Deg;

    if (enemyAngle < 0.0f)
        enemyAngle += 360;

    Debug.Log("Angle from the player is: " + enemyAngle);

    if (enemyAngle >= 292.5f && enemyAngle < 337.5f)
        return 8;
    else if (enemyAngle >= 22.5f && enemyAngle < 67.5f)
        return 2;
    else if (enemyAngle >= 67.5f && enemyAngle < 112.5f)
        return 3;
    else if (enemyAngle >= 112.5f && enemyAngle < 157.5f)
        return 4;
    else if (enemyAngle >= 157.5f && enemyAngle < 202.5f)
        return 5;
    else if (enemyAngle >= 202.5f && enemyAngle < 247.5f)
        return 6;
    else if (enemyAngle >= 247.5f && enemyAngle < 292.5f)
        return 7;
    else if (enemyAngle >= 337.5f || enemyAngle < 22.5f)
        return 1;
    else return 0;
}

I've searched for hours and I can't find a solution to this :(

like image 844
salgueiro157 Avatar asked Nov 10 '22 10:11

salgueiro157


1 Answers

You say your [only] problem is that it doesn't take their rotation into account - I'm guessing that means that you're not having trouble billboarding your sprites, and your rotation works when they're facing forward. To that end:

The dot product of vectors a and b is equal to cos(theta)*magnitude(a)*magnitude(b). So if a is the vector from the camera to the object:

var a = cam.transform.position - transform.parent.position

and b is the object's forward:

var b = transform.parent.forward

and we know that a and b both have magnitude 1

a.Normalize();
//b is already normalized

then we know that this is equal to cos(theta), where theta is the angle between them.

var theta = Mathf.Acos(Vector3.Dot(a, b)) * Mathf.Rad2Deg;

However. Theta is the shortest necessary angle - so it will be from 0 to 180. Given your switch table up there, we know that when we're hoping to go around the wrong way, we'll be in the wrong position. so to fix that:

if (a.x * a.z < 0)
    theta = 360.0f - theta;

then we just plug it in and go. Here's the full file in my project:

using UnityEngine;

public class spriteAngler : MonoBehaviour
{
    public Transform toFace;
    public SpriteRenderer toManipulate;
    public Sprite[] mySprites;
    private float theta;
    private Vector3 a;
    void Update()
    {
        toManipulate.sprite = mySprites[GetAngleIndex()];
    }
    int GetAngleIndex()
    {
        a = toFace.position - transform.position;

        a.Normalize();
        var b = transform.forward;

        theta = Mathf.Acos(Vector3.Dot(a, b)) * Mathf.Rad2Deg;

        if (a.x * a.z < 0)
            theta = 360.0f - theta;

        if (theta >= 292.5f && theta < 337.5f)
            return 7;
        else if (theta >= 22.5f && theta < 67.5f)
            return 1;
        else if (theta >= 67.5f && theta < 112.5f)
            return 2;
        else if (theta >= 112.5f && theta < 157.5f)
            return 3;
        else if (theta >= 157.5f && theta < 202.5f)
            return 4;
        else if (theta >= 202.5f && theta < 247.5f)
            return 5;
        else if (theta >= 247.5f && theta < 292.5f)
            return 6;
        else if (theta >= 337.5f || theta < 22.5f)
            return 0;
        else return 0;
    }

    private Rect guiPos = new Rect(0, 0, 720, 30);
    void OnGUI()
    {
        GUI.Label(guiPos, "Angle from the Player is: " + theta + " and forward=" + transform.forward + " and vectorToTarget=" + a);
    }
}

and if that needs a little more context, here's my project: https://github.com/AdamRGrey/22623013

I'd recommend hitting play but watching the scene window instead of the game window.

like image 59
Adam R. Grey Avatar answered Dec 03 '22 19:12

Adam R. Grey