Loading Sprites from Resource Folder For Character Customizer

Hi,

I’m writing a small script that will allow the player to customize a 2d character. I’m having trouble with a specific aspect in my approach, but I’d also be interested in hearing if there is a better overall approach.

Here’s what I’m attempting:

  1. Create List<List>. This is a list of body part lists
    // I’m not really using this yet in my script, but I know I will later.
  2. Create List for each body part
  3. Set string with path to root folder where there is a folder for each body part
  4. Find a GameObject for each body part
  5. Call function to add body parts to body part list with body part list and string as arguments
  6. Append string argument to root folder to find appropriate body part folder
  7. Use Resources.LoadAll() with completed folder path and count length of returned object and store as an int
    //This is where it gets borked. When I log this to the console, it returns 0 even though I have the path correctly specified and there are 3 .png assets inside the folder. This causes the subsequent for loop to be skipped. Lines 69-86 are the problem areas.
  8. Unload Resources
  9. Foreach loop that uses Resources.Load() to load in sprite using file path and add it to the appropriate List
    //Probably borked too since I don’t think I’m appropriately addressing files, but logging out the string does show me the correct file path.
  10. Add the completed parts list to the list of parts list
  11. Repeat for each body part list
  12. Create starting sprite by getting sprite renderer component on each body part GameObject and setting it to render the first sprite in each of the body part lists
  13. Checking for key input on updates to increment the the sprite renders to look at the next body part variation in the respective body part list.

So it’s not super clean yet, but I’m pretty sure my approach on #7 and #9 are totally wrong. I would love any help in solving this problem. The ultimate intent is to have some folders that follow a naming structure so I can just drop new assets in it over time and increase the amount of options without further work.

Thanks!

George

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

public class KarlaCustomizer : MonoBehaviour
{

    public List<List<Sprite>>
        allPartsList = new List<List<Sprite>>();

    public List<Sprite>
        bodies = new List<Sprite>(),
        faces = new List<Sprite>(),
        hairs = new List<Sprite>(),
        legs = new List<Sprite>(),
        activeParts = new List<Sprite>();

    public GameObject
        body,
        face,
        hair,
        leg;

    public int
        activeBody,
        activeFace,
        activeHair,
        activeLeg;

    public Vector2
        bodyLocation,
        faceLocation,
        hairLocation,
        legLocation;

    private SpriteRenderer
        spriteRendererBody,
        spriteRendererFace,
        spriteRendererHair,
        spriteRendererLeg;


    public string rootFolder;


    void Start()

    {

        rootFolder = "Assets/Characters/Karla/KarlaParts/Resources/";
        body = GameObject.Find("body");
        face = GameObject.Find("face");
        hair = GameObject.Find("hair");
        leg = GameObject.Find("leg");
        BuildPartList();

    }


    void BuildPartList()
    {
        GetParts(bodies, "body");
        GetParts(faces, "face");
        GetParts(hairs, "hair");
        GetParts(legs, "leg");
        BuildStartingSprite();
    }

    void GetParts(List<Sprite> partList, string partName)

    {
        print(rootFolder + partName);
        var partCounter = Resources.LoadAll(rootFolder + partName);
        print(partCounter.Length);
        int partCount = partCounter.Length;
        Resources.UnloadUnusedAssets();

        for (int i = 0; i <= partCount; i++)
        {
            string number = i.ToString();
            Sprite newSprite = Resources.Load<Sprite>(rootFolder + partName + "/" + partName + number);
            print(rootFolder + partName + "/" + partName + number);
            partList.Add(newSprite);
        }

        allPartsList.Add(partList);

    }

    void BuildStartingSprite()
    {
        spriteRendererBody = body.GetComponent<SpriteRenderer>();
        activeBody = 0;
        spriteRendererBody.sprite = bodies[activeBody];

        spriteRendererFace = face.GetComponent<SpriteRenderer>();
        activeFace = 0;
        spriteRendererFace.sprite = faces[activeFace];

        spriteRendererHair = hair.GetComponent<SpriteRenderer>();
        activeHair = 0;
        spriteRendererHair.sprite = hairs[activeHair];

        spriteRendererLeg = leg.GetComponent<SpriteRenderer>();
        activeLeg = 0;
        spriteRendererLeg.sprite = legs[activeLeg];

    }


    void Update()
    {
        if (Input.GetKeyDown(KeyCode.A))
        {
            SpriteUpdater("body");
        }
        if (Input.GetKeyDown(KeyCode.S))
        {
            SpriteUpdater("face");
        }
        if (Input.GetKeyDown(KeyCode.D))
        {
            SpriteUpdater("hair");
        }
        if (Input.GetKeyDown(KeyCode.F))
        {
            SpriteUpdater("leg");
        }
    }

    void SpriteUpdater(string bodyPart)
    {
        if (bodyPart == "body")
        {
            if (activeBody < bodies.Count)
            {
                activeBody++;
            }

            else activeBody = 0;
            spriteRendererBody.sprite = bodies[activeBody];
            print("bodyUpdate");
        }
        if (bodyPart == "face")
        {
            if (activeFace < faces.Count)
            {
                activeFace++;
            }

            else activeFace = 0;
            spriteRendererFace.sprite = faces[activeFace];
            print("faceUpdate");
        }
        if(bodyPart == "hair")
        {
            if (activeHair < hairs.Count)
            {
                activeHair++;
            }

            else activeHair = 0;
            spriteRendererHair.sprite = hairs[activeHair];
            print("hairUpdate");
        }
        if(bodyPart == "leg")
        {
            if (activeLeg < legs.Count)
            {
                activeLeg ++;
            }

            else activeLeg = 0;
            spriteRendererLeg.sprite = legs[activeLeg];
            print("legUpdate");
        }
    }

}

For posterity, I solved this.

Resources.Load() starts at the Resources folder which SHOULD NOT be specified in the file path. So, ultimately, I ended up moving my resources folder just under assets and then my file path string I fed it was /KarlaParts/Bodypart where body part was dynamic.

As an aside, I also updated my approach. I was passing around all kinds of objects and repeating a lot of stuff. So instead, I created a string list of body parts, created a set of dictionaries, and then used some foreach loops and just passed the strings through all my functions and used the dictionaries for various purposes. I still feel like there is a better pattern than this, but hey, it works. I also have the notion of an offset for the parts, but thats now irrelevant because of the way I’m bringing my sprites in now. Just left in in case it becomes useful in the future and its not really hurting anything.

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

public class KarlaCustomizer : MonoBehaviour
{

    public List<Sprite>
        bodies = new List<Sprite>(),
        faces = new List<Sprite>(),
        hairs = new List<Sprite>(),
        legs = new List<Sprite>(),
        activeParts = new List<Sprite>();

    public GameObject
        body,
        face,
        hair,
        leg;

    private Vector3
        bodyLocationDefault = new Vector3(0,0,0),
        faceLocationDefault = new Vector3(0,0,0),
        hairLocationDefault = new Vector3(0,0,0),
        legLocationDefault = new Vector3(0,0,0);

    public List<string> bodyPartStringList = new List<string>();
    public Dictionary<string, List<Sprite>> bodyPartSpriteList = new Dictionary<string, List<Sprite>>();
    public Dictionary<string, SpriteRenderer> bodyPartSpriteRenderers = new Dictionary<string, SpriteRenderer>();
    public Dictionary<string, GameObject> bodyPartGameObjects = new Dictionary<string, GameObject>();
    public Dictionary<string, int> activeBodyPart = new Dictionary<string, int>();
    public Dictionary<string, Vector2> bodyPartDefaultLocation = new Dictionary<string, Vector2>();
    public Dictionary<string, Vector2> bodyPartOffsets = new Dictionary<string, Vector2>();

    private Vector3
        face2offset = new Vector3 (0f,0f,0f);

    private SpriteRenderer
        spriteRendererBody,
        spriteRendererFace,
        spriteRendererHair,
        spriteRendererLeg;

    public string rootFolder;


    void Start()

    {
        //Create body part string list

        bodyPartStringList.Add("body");
        bodyPartStringList.Add("face");
        bodyPartStringList.Add("hair");
        bodyPartStringList.Add("leg");


        //Dictionaries

        bodyPartSpriteList.Add("body", bodies);
        bodyPartSpriteList.Add("face", faces);
        bodyPartSpriteList.Add("hair", hairs);
        bodyPartSpriteList.Add("leg", legs);

        bodyPartGameObjects.Add("body", body);
        bodyPartGameObjects.Add("face", face);
        bodyPartGameObjects.Add("hair", hair);
        bodyPartGameObjects.Add("leg", leg);

        bodyPartSpriteRenderers.Add("body", spriteRendererBody);
        bodyPartSpriteRenderers.Add("face", spriteRendererFace);
        bodyPartSpriteRenderers.Add("hair", spriteRendererHair);
        bodyPartSpriteRenderers.Add("leg", spriteRendererLeg);

        activeBodyPart.Add("body", 0);
        activeBodyPart.Add("face", 0);
        activeBodyPart.Add("hair", 0);
        activeBodyPart.Add("leg", 0);

        bodyPartDefaultLocation.Add("body", bodyLocationDefault);
        bodyPartDefaultLocation.Add("face", faceLocationDefault);
        bodyPartDefaultLocation.Add("hair", hairLocationDefault);
        bodyPartDefaultLocation.Add("leg", legLocationDefault);

        bodyPartOffsets.Add("face2", face2offset);


        //Find gameobjects & Sprite Renderers

        foreach (string bodyPart in bodyPartStringList)
        {
            bodyPartGameObjects[bodyPart] = GameObject.Find(bodyPart);
            bodyPartSpriteRenderers[bodyPart] = bodyPartGameObjects[bodyPart].GetComponent<SpriteRenderer>();
        }


        //Create all Sprite Lists. Set sorting layer to stack appropriately

        rootFolder = "KarlaParts/";
        foreach (string bodyPart in bodyPartStringList)
        {
            CreateAllPartLists(bodyPart);
            bodyPartSpriteRenderers[bodyPart].sortingLayerName = bodyPart;
        }


        //Create the starting Sprite

        foreach (string bodyPart in bodyPartStringList)
        {
            UpdateSprite(bodyPart);
        }

    }


    void CreateAllPartLists(string partName)

    {
        var partCounter = Resources.LoadAll(rootFolder + partName, typeof(Sprite));
        int partCount = partCounter.Length;
        Resources.UnloadUnusedAssets();

        for (int i = 0; i < partCount; i++)
        {
            string number = i.ToString();
            Sprite newSprite = Resources.Load<Sprite>(rootFolder + partName + "/" + partName + number);
            bodyPartSpriteList[partName].Add(newSprite);
        }
    }


    void UpdateSprite(string bodyPart)

    {
        int activePart = activeBodyPart[bodyPart];
        Vector3 newPosition = GetPosition(bodyPart, activePart);
        bodyPartGameObjects[bodyPart].transform.position = newPosition;
        bodyPartSpriteRenderers[bodyPart].sprite = bodyPartSpriteList[bodyPart][activePart];
    }


    Vector3 GetPosition(string bodyPart, int activeBodyPart)

    {
        string partName = bodyPart + activeBodyPart.ToString();
        if (bodyPartOffsets.ContainsKey(partName))
        {
            Vector3 offset = bodyPartOffsets[partName];
            float newXPos = bodyPartGameObjects[bodyPart].transform.position[0] + offset[0];
            float newYPos = bodyPartGameObjects[bodyPart].transform.position[1] + offset[1];
            return new Vector3 (newXPos,newYPos, bodyPartGameObjects[bodyPart].transform.position[2]);
        }

        return bodyPartDefaultLocation[bodyPart];
    }


    void Update()
    {

        if (Input.GetKeyDown(KeyCode.A))
        {
            if (activeBodyPart["body"] < bodies.Count - 1)

            {
                activeBodyPart["body"]++;
                UpdateSprite("body");
            }

            else
            {
                activeBodyPart["body"] = 0;
                UpdateSprite("body");
            }
        }

        if (Input.GetKeyDown(KeyCode.S))
        {
            if (activeBodyPart["face"] < faces.Count - 1)

            {
                activeBodyPart["face"]++;
                UpdateSprite("face");
            }

            else
            {
                activeBodyPart["face"] = 0;
                UpdateSprite("face");
            }
        }

        if (Input.GetKeyDown(KeyCode.D))
        {
            if (activeBodyPart["hair"] < hairs.Count - 1)

            {
                activeBodyPart["hair"]++;
                UpdateSprite("hair");
            }

            else activeBodyPart["hair"] = 0;
            UpdateSprite("hair");
        }

        if (Input.GetKeyDown(KeyCode.F))
        {
            if (activeBodyPart["leg"] < legs.Count - 1)

            {
                activeBodyPart["leg"]++;
                UpdateSprite("leg");
            }

            else activeBodyPart["leg"] = 0;
            UpdateSprite("leg");
        }

    }


}