Need help with this Face changing system

Hey there

I wanna make a system in my game where a ball that I have, will have a face on it which changes given what is found around it. So for example take this play through:

So the ball would probably be happy for a while until the last two explosions, where it’s just above spikes. I wanna detect what’s around the ball with Line Traces, though if you have a better idea, let me know.

Now, what I have issues with to start with, is that I want to have a dictionary of “faces” where the Key is an Enum for a face name, and the value is the Sprite that should be rendered on the ball. Faces like this:

But I can’t really find anything on how to do this, other than making a Prefab with an array of face sprites in it which doesn’t feel all that dynamic and easy to change. I’d be happier just having a component (FaceController.cs) that I can attach and then control it that way.

So what I thought I could do, would be to simply make Sprite Objects somewhere and then retrieve them at run-time so I can use them throughout the game. But this turned out to be harder than anticipated. I can’t seem to find anything that would suggest that you could create the 2DTextures a Sprite would need via Relative Paths to the raw PNG files and then create Sprites from that, which I could store in a Dictionary somewhere.

Any help would be appreciated!

You’re overthinking it. Just GetComponent<SpriteRenderer>(), and assign to the .sprite component.

1 Like

But I need something to assign to that sprite renderer…therein lies my issue. How do I make Sprite Objects that contain the 2D Texture that makes up what the SpriteRenderer should render?

You make them in the standard way, with the Sprite Editor. Why not?

It is possible to create Sprites dynamically from files, but I’m really not seeing why you would do that. Just create your sprites, add a Sprite[ ] array (or probably better, a bunch of explicitly named properties) to your script, and drag 'em in. I do this all the time, and have never felt like it was any big hardship.

Unless your game requires loading from files because they’re not available until runtime, or something like that?

No, the files are in a folder in the project. Sprites/BallFaces/

Yeah, just make an array of sprites in the inspector. Then drag and drop.

No need to get complex.

1 Like

Well I ended up making a “Resources” folder and then do this:

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

namespace Assets.Data
{
    public static class FaceSprites
    {
        public static Dictionary<FaceEnum, Sprite> Faces = new Dictionary<FaceEnum, Sprite>()
        {
            {FaceEnum.HAPPY, Resources.Load<Sprite>("Happy")},
            {FaceEnum.SURPRISED, Resources.Load<Sprite>("Surprised")},
            {FaceEnum.STRAINED, Resources.Load<Sprite>("Strained")},
            {FaceEnum.UNFACED, Resources.Load<Sprite>("Unfaced")},
            {FaceEnum.AMAZED, Resources.Load<Sprite>("Amazed")},
            {FaceEnum.SUNGLASSES, Resources.Load<Sprite>("Sunglasses")},
            {FaceEnum.TERRIFIED, Resources.Load<Sprite>("Terrified")}
        };
    }
}

Then I can do this:

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

public class FaceController : MonoBehaviour
{

    private SpriteRenderer spriteRender;
    private Dictionary<FaceEnum, Sprite> faces;
    private float waitTime = 0.2f;
    public float timer;
    private bool IsLevelPlaying;

    // Use this for initialization
    void Start()
    {
        faces = FaceSprites.Faces;
        spriteRender = gameObject.AddComponent<SpriteRenderer>();
        spriteRender.sprite = faces[FaceEnum.HAPPY];
        IsLevelPlaying = true;
    }

    public void Update()
    {
        if (IsLevelPlaying == true)
        {
            timer += Time.deltaTime;
            if (timer > waitTime)
            {
                RaycastHit2D[] hits = Physics2D.CircleCastAll(gameObject.transform.position, 1.75f, Vector2.zero, 10.0f);
                //Vector2 start = new Vector2(gameObject.transform.position.x, gameObject.transform.position.y);
                //DebugExtension.DebugCircle(start, Vector3.forward, Color.blue, 1.5f, 5.0f, false);
                bool ForceHappyReaction = true;
                hits = RemovePlayer(hits);
                if (hits.Length > 0)
                {
                    for (int i = 0; i < hits.Length; i++)
                    {
                        switch (hits[i].collider.tag)
                        {
                            case "Sun":
                            case "Spike":
                                spriteRender.sprite = faces[FaceEnum.STRAINED];
                                ForceHappyReaction = false;
                                i = hits.Length;
                                waitTime = 0.35f;
                                break;
                            case "Deadzone":
                                spriteRender.sprite = faces[FaceEnum.TERRIFIED];
                                ForceHappyReaction = false;
                                i = hits.Length;
                                waitTime = 0.35f;
                                break;
                            case "Cloud":
                                spriteRender.sprite = faces[FaceEnum.AMAZED];
                                ForceHappyReaction = false;
                                i = hits.Length;
                                waitTime = 0.35f;                           
                                break;
                            case "Sand":
                                spriteRender.sprite = faces[FaceEnum.UNFACED];
                                ForceHappyReaction = false;
                                i = hits.Length;
                                waitTime = 0.35f;
                                break;
                            case "Branch":
                                spriteRender.sprite = faces[FaceEnum.SURPRISED];
                                ForceHappyReaction = false;
                                i = hits.Length;
                                waitTime = 0.35f;
                                break;
                        }
                    }
                }
                else
                {
                    ForceHappyReaction = true;
                    waitTime = 0.2f;
                }

                if (ForceHappyReaction == true)
                {
                    spriteRender.sprite = faces[FaceEnum.HAPPY];
                }

                timer = 0f;
            }
        }
    }

    private RaycastHit2D[] RemovePlayer(RaycastHit2D[] array)
    {
        int index = -1;

        for (int i = 0; i < array.Length; i++)
        {
            if (array[i].collider.tag == "Player")
            {
                index = i;
                break;
            }
        }

        if (index == -1)
        {
            return array;
        }
        else
        {
            List<RaycastHit2D> list = array.ToList();
            list.RemoveAt(index);
            array = list.ToArray();
            return array;
        }
    }

    void OnEnable()
    {
        GameStateController.AttachOnLevelStart(WhenLevelLoads);
        GameStateController.AttachOnLevelPlay(WhenLevelPlays);
        GameStateController.AttachOnLevelEnds(WhenLevelEnds);
    }

    void OnDisable()
    {
        GameStateController.DetachOnLevelStart(WhenLevelLoads);
        GameStateController.DetachOnLevelPlay(WhenLevelPlays);
        GameStateController.DetachOnLevelEnds(WhenLevelEnds);
    }

    void WhenLevelLoads()
    {

    }

    void WhenLevelPlays()
    {
        IsLevelPlaying = true;
    }

    void WhenLevelEnds()
    {
        IsLevelPlaying = false;
        spriteRender.sprite = faces[FaceEnum.SUNGLASSES];
    }
}

Works very well! Thanks for the tips though :slight_smile:

1 Like

There’s always more than one way to relieve a feline of its fur. :slight_smile:

2 Likes

Not sure if that’s a compliment or not. First time I’ve heard that saying :')

It’s a play on ‘more then one way to skin a cat’.

For just about everything in Unity there are about five ways to get the job done. Yours will work reasonably well.

2 Likes

Yeah I had the idea that’s what he meant but, that can be both positive or negative :')

I meant it in a positive way, of course. Your approach looks just fine.

1 Like