8 Directional Sprites

Hello, new here. I would want to learn how to do 2.5D sprites like in Marathon. (Which isn’t a complete Doomlike)

This has been a huge interest for me and I want to learn to do it right. I’ve tried some script before, it did change the sprite to the wished direction but the character couldn’t rotate nor be animated. If you can’t give me a complete code then it’s okay. Just say what I need to learn to make a simple 2.5D script and I would be pleased.

EDIT: This is the current code for 8 directional sprites

public class SpriteAnimator : MonoBehaviour {

    public GameObject cameraToSee;
    public Transform player;
    public float playerAngle;
    Vector3 direction;

    public int locationInt, locationInt2;

    public Sprite[] sprites;
    SpriteRenderer spriteRenderer;

    void Awake () {
        spriteRenderer = gameObject.GetComponent<SpriteRenderer>();
        cameraToSee = Camera.main.gameObject;
    }
   
    void Update () {
        direction = player.transform.position - transform.position;
        playerAngle = Mathf.Atan2(direction.x,direction.z) * Mathf.Rad2Deg;
        ChangeSprite();
        Vector3 targetPosition = new Vector3(cameraToSee.transform.position.x,
                                             transform.position.y,
                                             cameraToSee.transform.position.z);
        transform.LookAt(targetPosition);
        locationInt = Mathf.RoundToInt(playerAngle);
        locationInt2 = Mathf.RoundToInt(playerAngle + 45);
    }

    public void ChangeSprite() {
        if (locationInt <= 0 && locationInt2 >= 45) spriteRenderer.sprite = sprites[0];
        else if (locationInt <= 45 && locationInt2 >= 90) spriteRenderer.sprite = sprites[1];
        else if (locationInt <= 90 && locationInt2 >= 135) spriteRenderer.sprite = sprites[2];
        else if (locationInt <= 135 && locationInt2 >= 180) spriteRenderer.sprite = sprites[3];
        else if (locationInt <= 180 && locationInt2 >= 225) spriteRenderer.sprite = sprites[4];
        else if (locationInt <= -135 && locationInt2 >= -135) spriteRenderer.sprite = sprites[5];
        else if (locationInt <= -90 && locationInt2 >= -90) spriteRenderer.sprite = sprites[6];
        else if (locationInt <= -45 && locationInt2 >= -45) spriteRenderer.sprite = sprites[7];
    }
}

It isn’t masterly crafted but it worked. However the character can’t rotate.

Here is the same script but more optimised. (Believably)

using UnityEngine;

public class SpriteAnimator : MonoBehaviour {

    public GameObject cameraToSee;
    public Transform player;
    public float playerAngle;
    public Vector3 direction;

    public GameObject spriteObject;

    public int locationInt, locationInt2;

    public string facingDir;

    void Awake () {
        cameraToSee = Camera.main.gameObject;
    }
  
    void Update () {
        direction = player.transform.position - transform.position;
        playerAngle = Mathf.Atan2(direction.x,direction.z) * Mathf.Rad2Deg;


        Vector3 targetPosition = new Vector3(cameraToSee.transform.position.x,
                                             transform.position.y,
                                             cameraToSee.transform.position.z);
        spriteObject.transform.LookAt(targetPosition);


        locationInt = Mathf.RoundToInt(playerAngle);
        locationInt2 = Mathf.RoundToInt(playerAngle + 45);

        InDirection();
    }

    public void InDirection() {
        if (locationInt <= 0 && locationInt2 >= 45) facingDir = "front";
        else if (locationInt <= 45 && locationInt2 >= 90) facingDir = "frontright";
        else if (locationInt <= 90 && locationInt2 >= 135) facingDir = "right";
        else if (locationInt <= 135 && locationInt2 >= 180) facingDir = "backright";
        else if (locationInt <= 180 && locationInt2 >= 225) facingDir = "back";
        else if (locationInt <= -135 && locationInt2 >= -180) facingDir = "backleft";
        else if (locationInt <= -90 && locationInt2 >= -135) facingDir = "left";
        else if (locationInt <= -45 && locationInt2 >= -90) facingDir = "frontleft";
    }
}

Here’s the current state of a character’s behaviour script. Jekivi.

using UnityEngine;

public class JekiviTest : MonoBehaviour {

    SpriteAnimator spriteAnimator;

    public Sprite[] sprites;
    public SpriteRenderer spriteRenderer;

    void Awake () {
        spriteAnimator = GetComponent<SpriteAnimator>();
    }
  
    void Update () {
        ChangeSprite();
    }

    public void ChangeSprite()
    {
        if (spriteAnimator.facingDir == "front") spriteRenderer.sprite = sprites[0];
        else if (spriteAnimator.facingDir == "frontright") spriteRenderer.sprite = sprites[1];
        else if (spriteAnimator.facingDir == "right") spriteRenderer.sprite = sprites[2];
        else if (spriteAnimator.facingDir == "backright") spriteRenderer.sprite = sprites[3];
        else if (spriteAnimator.facingDir == "back") spriteRenderer.sprite = sprites[4];
        else if (spriteAnimator.facingDir == "backleft") spriteRenderer.sprite = sprites[5];
        else if (spriteAnimator.facingDir == "left") spriteRenderer.sprite = sprites[6];
        else if (spriteAnimator.facingDir == "frontleft") spriteRenderer.sprite = sprites[7];
    }
}

Something is wrong. Can someone help me out?

The most important skill when programming is the ability to debug your own code. The usual process here is to ask yourself what you think should be happening on every line of code, and then investigate when that assumption breaks.

In your case, you assume that the playerAngle changes based on where the player is relative to the direction the SpriteAnimator is facing, and you assume that the correct locationInt is getting set from the angle. Those are easy to check - the most straightforward way is with Debug.Log:

// after this:
direction = player.transform.position - transform.position;
playerAngle = Mathf.Atan2(direction.x,direction.z) * Mathf.Rad2Deg;
// add:
Debug.Log("The direction is " + direction + ", and the angle is " + playerAngle);

// after this:
locationInt = Mathf.RoundToInt(playerAngle);
locationInt2 = Mathf.RoundToInt(playerAngle + 45);
// add:
Debug.Log("Set location int 1 to " + locationInt + " and location int 2 to " + locationInt2);

I did this instead.

if (playerAngle >= 0f && playerAngle < 45f) facing = FACINGDIR.front;
        else if (playerAngle >= 45f && playerAngle < 90f) facing = FACINGDIR.frontright;
        else if (playerAngle >= 90f && playerAngle < 135f) facing = FACINGDIR.right;
        else if (playerAngle >= 135f && playerAngle < 180f) facing = FACINGDIR.backright;
        else if (playerAngle >= -180f && playerAngle < -135f) facing = FACINGDIR.back;
        else if (playerAngle >= -135f && playerAngle < -90f) facing = FACINGDIR.backleft;
        else if (playerAngle >= -90f && playerAngle < -45f) facing = FACINGDIR.left;
        else if (playerAngle >= -45f && playerAngle < 0f) facing = FACINGDIR.frontleft;

And it worked! But I’m not done yet. I still need to make the character’s own rotation change the sprite and figure out how to make animations work. Any help is appreciated. Until then I’ll try to figure it out myself.

I am stuck and there’s better ways to do this. Any help with getting the character’s rotation cause I am clueless.

i was testing similar thing here using shader, but its not really complete or flexible…

for animation i used texture sheet, and then played each row separately…

you might want to check how they do it in this,
https://github.com/Interkarma/daggerfall-unity

Came back to try again. This is the current codes.

SpriteAnimator

public class SpriteAnimator : MonoBehaviour {

    public GameObject cameraToSee;
    public Transform player;
    public float playerAngle;
    Vector3 direction;
    public float charaRot;

    public GameObject spriteObject;

    public enum FACINGDIR{front, frontright, right, backright, back, backleft, left, frontleft};
    public FACINGDIR facing;

    void Awake () {
        cameraToSee = Camera.main.gameObject;
    }
   
    void Update () {
        direction = player.transform.position - transform.position;
        playerAngle = Mathf.Atan2(direction.x,direction.z) * Mathf.Rad2Deg;
        playerAngle += charaRot;

        Vector3 targetPosition = new Vector3(cameraToSee.transform.position.x,
                                             transform.position.y,
                                             cameraToSee.transform.position.z);
        spriteObject.transform.LookAt(targetPosition);
        if(charaRot > 180){
            charaRot = 0;
        }

        if (charaRot < 0)
        {
            charaRot = 180;
        }

        if (playerAngle >= 0f && playerAngle < 45f) facing = FACINGDIR.front;
        else if (playerAngle >= 45f && playerAngle < 90f) facing = FACINGDIR.frontright;
        else if (playerAngle >= 90f && playerAngle < 135f) facing = FACINGDIR.right;
        else if (playerAngle >= 135f && playerAngle < 180f) facing = FACINGDIR.backright;
        else if (playerAngle >= -180f && playerAngle < -135f) facing = FACINGDIR.back;
        else if (playerAngle >= -135f && playerAngle < -90f) facing = FACINGDIR.backleft;
        else if (playerAngle >= -90f && playerAngle < -45f) facing = FACINGDIR.left;
        else if (playerAngle >= -45f && playerAngle < 0f) facing = FACINGDIR.frontleft;
    }
}

Jekivi Script

public class JekiviTest : MonoBehaviour {

    SpriteAnimator spriteAnimator;

    public Sprite[] sprites;
    public SpriteRenderer spriteRenderer;

    SpriteAnimator.FACINGDIR spriteFacing;

    void Awake () {
        spriteAnimator = GetComponent<SpriteAnimator>();
    }

    void Update()
    {
        spriteFacing = spriteAnimator.facing;
        switch (spriteFacing)
        {
            case SpriteAnimator.FACINGDIR.front:
                spriteRenderer.sprite = sprites[0];
                break;
            case SpriteAnimator.FACINGDIR.frontright:
                spriteRenderer.sprite = sprites[1];
                break;
            case SpriteAnimator.FACINGDIR.right:
                spriteRenderer.sprite = sprites[2];
                break;
            case SpriteAnimator.FACINGDIR.backright:
                spriteRenderer.sprite = sprites[3];
                break;
            case SpriteAnimator.FACINGDIR.back:
                spriteRenderer.sprite = sprites[4];
                break;
            case SpriteAnimator.FACINGDIR.backleft:
                spriteRenderer.sprite = sprites[5];
                break;
            case SpriteAnimator.FACINGDIR.left:
                spriteRenderer.sprite = sprites[6];
                break;
            case SpriteAnimator.FACINGDIR.frontleft:
                spriteRenderer.sprite = sprites[7];
                break;
        }
    }
}
1 Like

Hey Nails-of-Scream this is a very old post so i dont even know if youll see this but im trying to create a 8 way directional system (doom-like) and your script here as gotten me closer than anything else ive seen, i just want to know if over the years youve figured out a way to take the rotation of the object into account with the rotation and position of the player. ive been trying to figure this out for a while now and this is a long shot.

Hello Scorpion777. Yes this is an old thread you’re right. And to be more informative. I’ve actually succeeded on making a custom 8 dir system that is more optimized than what’s shown here. Don’t remember when I succeeded but it was awhile ago.