Character Selection with Prefabs and ScriptableObjects

Hello there.
I’m a Unity beginner and currently learning how to C# properly using Unity and its functions.
I’ve hit a little wall and thus I’m kindly asking for assistance :slight_smile:

The problem:
Loop through the Prefabs Characters and set them to isActive(true) while turning the previous character off.

The scene:
https://ibb.co/S5PRm85

The code I use to store all my character infos, works like a charm!

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


[CreateAssetMenu(fileName = "New CharacterData", menuName = "CharacterData", order = 51)]
public class CharacterData : ScriptableObject
{
    [SerializeField]
    private string charName;
    [SerializeField]
    private string charDescription;
    [SerializeField]
    private int charNumber;
    [SerializeField]
    private GameObject charGO;


    public string CharName
    {
        get
        {
            return charName;
        }
    }
    public string CharDescription
    {
        get
        {
            return charDescription;
        }
    }   
    public int CharNumber
    {
        get
        {
            return charNumber;
        }
    }

    public GameObject CharGO
    {
        get
        {
            return charGO;
        }
    }
}

In this code lies my problem:

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

public class SelectionHandler : MonoBehaviour
{

    [SerializeField]
    private CharacterData Cdata1;
    [SerializeField]
    private CharacterData Cdata2;

//useless for now
    //private int index;
    //private ArrayList[] charAmount;


    private void Start()
    {
        GameObject.Instantiate(Cdata1.CharGO);
        GameObject.Instantiate(Cdata2.CharGO).SetActive(false);
                  
    }
//press "Next" button, do this
    public void Next()
    {
        //If pressed, switch Cdata1 off and Cdata2 on. Preferably automated like
        //foreach(character in SelectionHandler)
        //if 1 is active, turn off and turn 1+i on, ...
    }

}

Like you see in my commented lines, I’d like to switch characters[i++] on and off and as soon as I hit the last array spot, return back to the first character.

I cannot wrap my head around how I can call, set or browse through SelectionHandler Inspector (picture) and count how many characters I added there and cycle them on and off.

Any help would be really appreciated!
I hope I described the problem good enough, if not, feel free to yell at me :smile:

Kind regards!

using System.Collections.Generic;
using UnityEngine;

public class Test : MonoBehaviour
{
    public List<GameObject> characterList = new List<GameObject>();
    private int currentIndex = 0;

    public void Next()
    {
        characterList[currentIndex].SetActive(false);
        currentIndex += 1;
        if (currentIndex >= characterList.Count)
        {
            currentIndex = 0;
        }

        characterList[currentIndex].SetActive(true);
    }
}

EDIT:
Got it to work properly now.

The solution was to instantiate the character GameObjetcs and after that store that (clone) information in an empty list to get life access to it.

Here’s how it works:

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

public class SelectionHandler : MonoBehaviour
{
//using my prefabs here with ALL character Infos
    public CharacterData[] characterData;

    private int currentIndex = 0;
//this list will basically get filled AFTER the charsGO are created
    public List<GameObject> characterList = new List<GameObject>();


    private void Start()
    {
        foreach( var characterData in characterData)
        {
            GameObject go = Instantiate(characterData.CharGO); //instantiate
            go.SetActive(false); //turn off
            characterList.Add(go); //store the clone!
        }

        characterList[0].SetActive(true); //basically show the first char on the selection screen
        
    }
//NEXT works like a charm now!
    private void Next()
    {
        characterList[currentIndex].SetActive(false);
        currentIndex++;
        if (currentIndex >= characterList.Count)
        {
            currentIndex = 0;
        }
        characterList[currentIndex].SetActive(true);
    }

}
using System.Collections.Generic;
using UnityEngine;

public class Test : MonoBehaviour
{
    private readonly List<GameObject> characterList = new List<GameObject>();

    private int currentIndex = 0;

    // Create a "Characters" folder in "Resources" folder, then put all your character prefab into "Characters" Folder
    private void Start()
    {
        // 1 load all character prefabs
        var characterPrefabs = Resources.LoadAll<GameObject>("Characters");
        // 2 create them and set active false, and put into list
        foreach (var characterPrefab in characterPrefabs)
        {
            var instance = Object.Instantiate(characterPrefab);
            instance.SetActive(false);
            characterList.Add(instance);
        }

        // 3 set 0 active
        characterList[0].SetActive(true);
    }

    public void Next()
    {
        characterList[currentIndex].SetActive(false);
        currentIndex += 1;
        if (currentIndex >= characterList.Count)
        {
            currentIndex = 0;
        }

        characterList[currentIndex].SetActive(true);
    }
}

Nice, there are two things to do next, one is to separate the code that creates the role, because they do not belong to the SelectionHandler, and the other is to put the resources in the Resources folder and use them through the absolute path, because when the resources increase, It is not a good practice to drag the prefab to the component

Seems like i ran into some new problems.

If I want to load Prefabs, which are ScriptableObjects, am I able to do that?
I used the LoadAll function with a corresponding Resources/Characters Folder but the script doesnt add them to the scene as GameObjects now. No errors, just nothing appearing

Thats the script im using now:

public class SelectionHandler : MonoBehaviour
{

    //public CharacterData[] characterData;

    private int currentIndex = 0;
    private readonly List<GameObject> characterList = new List<GameObject>();


    private void Start()
    {
        var characterPrefabs = Resources.LoadAll<GameObject>("Characters");
        foreach( var characterPrefab in characterPrefabs)
        {
            var go = Object.Instantiate(characterPrefab);
            go.SetActive(false);
            characterList.Add(go);
        }

        characterList[0].SetActive(true);
        
    }

those are my SO character models with all the data:
https://ibb.co/4PGSCNh

You need to modify Resource.LoadAll to your type like Resources.LoadAll, I haven’t used Scriptobject, so I’m not sure how to use it

Another way is to store the data in a .csv file, which is a file that excel can open, and then read the data from it, which is a better practice in my opinion. If the data is not a lot, I am used to writing them in constants or static variables