Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Resolved Character Selection with Prefabs and ScriptableObjects

Discussion in 'Scripting' started by Bieri, Feb 25, 2021.

  1. Bieri

    Bieri

    Joined:
    Feb 21, 2021
    Posts:
    3
    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 :)

    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!

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5.  
    6. [CreateAssetMenu(fileName = "New CharacterData", menuName = "CharacterData", order = 51)]
    7. public class CharacterData : ScriptableObject
    8. {
    9.     [SerializeField]
    10.     private string charName;
    11.     [SerializeField]
    12.     private string charDescription;
    13.     [SerializeField]
    14.     private int charNumber;
    15.     [SerializeField]
    16.     private GameObject charGO;
    17.  
    18.  
    19.     public string CharName
    20.     {
    21.         get
    22.         {
    23.             return charName;
    24.         }
    25.     }
    26.     public string CharDescription
    27.     {
    28.         get
    29.         {
    30.             return charDescription;
    31.         }
    32.     }  
    33.     public int CharNumber
    34.     {
    35.         get
    36.         {
    37.             return charNumber;
    38.         }
    39.     }
    40.  
    41.     public GameObject CharGO
    42.     {
    43.         get
    44.         {
    45.             return charGO;
    46.         }
    47.     }
    48. }
    49.  

    In this code lies my problem:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class SelectionHandler : MonoBehaviour
    6. {
    7.  
    8.     [SerializeField]
    9.     private CharacterData Cdata1;
    10.     [SerializeField]
    11.     private CharacterData Cdata2;
    12.  
    13. //useless for now
    14.     //private int index;
    15.     //private ArrayList[] charAmount;
    16.  
    17.  
    18.     private void Start()
    19.     {
    20.         GameObject.Instantiate(Cdata1.CharGO);
    21.         GameObject.Instantiate(Cdata2.CharGO).SetActive(false);
    22.                  
    23.     }
    24. //press "Next" button, do this
    25.     public void Next()
    26.     {
    27.         //If pressed, switch Cdata1 off and Cdata2 on. Preferably automated like
    28.         //foreach(character in SelectionHandler)
    29.         //if 1 is active, turn off and turn 1+i on, ...
    30.     }
    31.  
    32. }
    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 :D

    Kind regards!
     
  2. chengwang2077

    chengwang2077

    Joined:
    Nov 23, 2019
    Posts:
    131
    Code (CSharp):
    1. using System.Collections.Generic;
    2. using UnityEngine;
    3.  
    4. public class Test : MonoBehaviour
    5. {
    6.     public List<GameObject> characterList = new List<GameObject>();
    7.     private int currentIndex = 0;
    8.  
    9.     public void Next()
    10.     {
    11.         characterList[currentIndex].SetActive(false);
    12.         currentIndex += 1;
    13.         if (currentIndex >= characterList.Count)
    14.         {
    15.             currentIndex = 0;
    16.         }
    17.  
    18.         characterList[currentIndex].SetActive(true);
    19.     }
    20. }
     
  3. Bieri

    Bieri

    Joined:
    Feb 21, 2021
    Posts:
    3
    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:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class SelectionHandler : MonoBehaviour
    6. {
    7. //using my prefabs here with ALL character Infos
    8.     public CharacterData[] characterData;
    9.  
    10.     private int currentIndex = 0;
    11. //this list will basically get filled AFTER the charsGO are created
    12.     public List<GameObject> characterList = new List<GameObject>();
    13.  
    14.  
    15.     private void Start()
    16.     {
    17.         foreach( var characterData in characterData)
    18.         {
    19.             GameObject go = Instantiate(characterData.CharGO); //instantiate
    20.             go.SetActive(false); //turn off
    21.             characterList.Add(go); //store the clone!
    22.         }
    23.  
    24.         characterList[0].SetActive(true); //basically show the first char on the selection screen
    25.        
    26.     }
    27. //NEXT works like a charm now!
    28.     private void Next()
    29.     {
    30.         characterList[currentIndex].SetActive(false);
    31.         currentIndex++;
    32.         if (currentIndex >= characterList.Count)
    33.         {
    34.             currentIndex = 0;
    35.         }
    36.         characterList[currentIndex].SetActive(true);
    37.     }
    38.  
    39. }
     
    Last edited: Feb 25, 2021
  4. chengwang2077

    chengwang2077

    Joined:
    Nov 23, 2019
    Posts:
    131
    Code (CSharp):
    1. using System.Collections.Generic;
    2. using UnityEngine;
    3.  
    4. public class Test : MonoBehaviour
    5. {
    6.     private readonly List<GameObject> characterList = new List<GameObject>();
    7.  
    8.     private int currentIndex = 0;
    9.  
    10.     // Create a "Characters" folder in "Resources" folder, then put all your character prefab into "Characters" Folder
    11.     private void Start()
    12.     {
    13.         // 1 load all character prefabs
    14.         var characterPrefabs = Resources.LoadAll<GameObject>("Characters");
    15.         // 2 create them and set active false, and put into list
    16.         foreach (var characterPrefab in characterPrefabs)
    17.         {
    18.             var instance = Object.Instantiate(characterPrefab);
    19.             instance.SetActive(false);
    20.             characterList.Add(instance);
    21.         }
    22.  
    23.         // 3 set 0 active
    24.         characterList[0].SetActive(true);
    25.     }
    26.  
    27.     public void Next()
    28.     {
    29.         characterList[currentIndex].SetActive(false);
    30.         currentIndex += 1;
    31.         if (currentIndex >= characterList.Count)
    32.         {
    33.             currentIndex = 0;
    34.         }
    35.  
    36.         characterList[currentIndex].SetActive(true);
    37.     }
    38. }
     
  5. chengwang2077

    chengwang2077

    Joined:
    Nov 23, 2019
    Posts:
    131
    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
     
  6. Bieri

    Bieri

    Joined:
    Feb 21, 2021
    Posts:
    3
    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:
    Code (CSharp):
    1. public class SelectionHandler : MonoBehaviour
    2. {
    3.  
    4.     //public CharacterData[] characterData;
    5.  
    6.     private int currentIndex = 0;
    7.     private readonly List<GameObject> characterList = new List<GameObject>();
    8.  
    9.  
    10.     private void Start()
    11.     {
    12.         var characterPrefabs = Resources.LoadAll<GameObject>("Characters");
    13.         foreach( var characterPrefab in characterPrefabs)
    14.         {
    15.             var go = Object.Instantiate(characterPrefab);
    16.             go.SetActive(false);
    17.             characterList.Add(go);
    18.         }
    19.  
    20.         characterList[0].SetActive(true);
    21.        
    22.     }
    those are my SO character models with all the data:
    https://ibb.co/4PGSCNh
     
  7. chengwang2077

    chengwang2077

    Joined:
    Nov 23, 2019
    Posts:
    131
    You need to modify Resource.LoadAll<GameObject> to your type like Resources.LoadAll<YourType>, I haven't used Scriptobject, so I'm not sure how to use it
     
  8. chengwang2077

    chengwang2077

    Joined:
    Nov 23, 2019
    Posts:
    131
    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