Short version (I'm @ work doing boring stuff): I have a 'basebuilding' type of situation where I instantiate Prefabs into my scene by mouseclick. Each Prefab has a script attached to it, wich, on Awake, adds it's transform position and some other info to a List. Using a self created "AddPositionTo List"-method Works like a charm! Now I added a basic 'Save and Load level layout' option to my scene using PlayerPrefs. Prefabs are instantiated perfectly on 'loading', all of the right type, all at the right position with the right Quaternions etc. But ... Only the first Prefab adds his position to the List. ... So I added some debugging to my script. Just before the "AddPositionTo List"-method and right after. All variables, postions, tags etc. are making it into the consoles log. So the Awake() is triggerd for all prefabs instantiated in my scene and the code runs. But why is only the first Prefab Instantiated able to add his position to the List?
I'm not used to the whole terminology of scripting yet, but it's a public List. If that is what you mean. This List is created when the scene loads. So it's always there for use. It uses the same class script in both cases.. When I do it by mouseclick, a prefab gets instantiated and the Awake() on the prefab adds information to the list. Now. On Load, the same prefab gets instantiated, using the same Awake() on the prefab to add information to the same List. But fails (exept for te first prefab). The only difference, when I click there is only one prefab instantiated within update(), only one script trying to add information to the List. On Load there is a loop trying to instantiate multiple prefabs, who all, on Awake(), try to add something to the List within one update().
There shouldn't be any problem if the List is already initialized and every unit/prefab tries to add itself to that list. Are you sure you made your list only in one copy, like in some singleton object that is your central location for gathering that scene information? I wonder if you interpret the situation a bit wrong and you have many Lists, for example. Also, use Awake only to initialize objects so that you deal with the components etc. that exist in the object itself, not in other objects. In Start you can look for those other dependencies, like try to cache values from other objects to a List (just as an example.) EDIT: can you post some code snippet where and how you have that List.
It looks like this is the case, so OP, show the code of class where list is defined and where you add your item.
The script that is on my nodes: Code (CSharp): using UnityEngine; using System.Collections; public class NodeScript : MonoBehaviour { // stuff happening public void Awake() { // stuff happening // adding nodes to list nodeLijstScript.ToevoegenAanPfNodeLijsten(dezeNode.transform.position, dezeNode, dezeNode.tag); // more stuff happening } } The 'nodeLijstScript' which has the method: Code (CSharp): using System.Collections.Generic; using UnityEngine; public class NodeLijstScript : MonoBehaviour { public List<Vector3> pf_nodes_positie_Lijst = new List<Vector3>(); // the original List! public List<GameObject> pf_nodes_gameobject_Lijst = new List<GameObject>(); // the original List! // This checks if position already exists in List public bool CheckOfPfNodeAlBestaat(Vector3 nodePositie) { if (pf_nodes_positie_Lijst.Count != 0 && pf_nodes_positie_Lijst.Contains(nodePositie)) // of de locatie al in de lijst voorkomt { return true; } else return false; } // This adds the position and objects to the List (using the above metyhod to check for duplicates) public void ToevoegenAanPfNodeLijsten(Vector3 nodePositie, GameObject nodeGameObject, string tag) { if (CheckOfPfNodeAlBestaat(nodePositie) == false && tag == "Pf_Node") { pf_nodes_positie_Lijst.Add(nodePositie); pf_nodes_gameobject_Lijst.Add(nodeGameObject); } } This is what happens when Instantiate by mouseclicking (just building a layout): The list contains locations and GameObjects from the white spheres (nodes). These are children the blue cube frame thing which is the prefab instantiated. This is what happens if I Save, restart the scene, and Load.
Now reading through my post I suddenly notice it isn't the fist node at all … . The first prefab instantiated is at (0,0,0), the one next to the green cube, only has 3 nodes. In this case I have 5 positions in my list. Did some more testing. It seems that when I Load the objects the original positions of the nodes in the blue prefab cube-frame-thing are added to the list, not the positions of the nodes in the scene, but the relative postions to their parent. Why does this happen on Loading and not when maually instantiating?
Allright the whole save and load thing .. Code (CSharp): using System.Collections; using UnityEngine.SceneManagement; using System.Collections.Generic; using UnityEngine; public class SaveLayoutManager : MonoBehaviour { private static SaveLayoutManager slm; public List<SaveableSectiesAlgemeen> SectionsSaveLijst { get; private set; } public static SaveLayoutManager Save_Layout_Manager { get { if (slm == null) { slm = GameObject.FindObjectOfType<SaveLayoutManager>(); } return slm; } } void Awake() { SectionsSaveLijst = new List<SaveableSectiesAlgemeen>(); } public void Save() { string huidigeSceneNaam = SceneManager.GetActiveScene().name; int aantal_in_SaveLijst = SectionsSaveLijst.Count; // aantal objecten in savefile opslaan onder huidige scene naam PlayerPrefs.SetInt(huidigeSceneNaam, aantal_in_SaveLijst); for( int i = 0; i < SectionsSaveLijst.Count; i++) { SectionsSaveLijst[i].Save(i); // roept de savefunctie aan welke bij het specifieke GamObject in SectiesSaveLijst hoort, zie Save() in SaveableSectiesAlgemeen } } public void Load() { // Eerst alle bestaande Saveables verwijderen en SaveLijst leegmaken foreach (SaveableSectiesAlgemeen obj in SectionsSaveLijst) { print("Gevonden voor Destroy: " + obj); if (obj != null) { Destroy(obj.gameObject); } } SectionsSaveLijst.Clear(); // Alle objecten inladen uit de savefile int aantal_in_SaveLijst = PlayerPrefs.GetInt(SceneManager.GetActiveScene().name); // eerst totaal aantal ophalen opgeslagen onder huidige scene naam for (int i = 0; i < aantal_in_SaveLijst; i++) { string huidigeSceneNaam = SceneManager.GetActiveScene().name; string index = i.ToString(); string kenmerk_van_save = huidigeSceneNaam + "-" + index; string savestring_compleet = PlayerPrefs.GetString(kenmerk_van_save); // haalt "scenenaam-i" uit save string[] savestring_opgeknipt = savestring_compleet.Split('#'); GameObject objectType = null; switch (savestring_opgeknipt[0]) // index [0] = objecttype (Enum) { case "Frame_0": objectType = Instantiate(Resources.Load("Frame_0") as GameObject); break; case "Frame_1": objectType = Instantiate(Resources.Load("Frame_1") as GameObject); break; case "Frame_2": objectType = Instantiate(Resources.Load("Frame_2") as GameObject); break; case "Frame_3": objectType = Instantiate(Resources.Load("Frame_3") as GameObject); break; case "Frame_4": objectType = Instantiate(Resources.Load("Frame_4") as GameObject); break; case "Frame_5": objectType = Instantiate(Resources.Load("Frame_5") as GameObject); break; case "Frame_6": objectType = Instantiate(Resources.Load("Frame_6") as GameObject); break; case "Frame_7": objectType = Instantiate(Resources.Load("Frame_7") as GameObject); break; case "Frame_8": objectType = Instantiate(Resources.Load("Frame_8") as GameObject); break; } if(objectType!= null) { objectType.GetComponent<SaveableSectiesAlgemeen>().Load(savestring_opgeknipt); } else print("Enum ObjectType staat niet in beschibare lijst met Enum om te laden."); } } public Vector3 TekstNaarVectorOmzetten(string tekst) { // string is bijv. (3, 6, 12) tekst = tekst.Trim(new char[] { '(', ')' }); // haakjes om de tekst weghalen tekst = tekst.Replace(", ", "#"); // komma-spaties er tussenuit halen en vervangen door # string[] tekst_gesplitst = tekst.Split('#'); // opsplitsen in array van waardes, splitsen op # // floats maken van strings float x = float.Parse(tekst_gesplitst[0]); float y = float.Parse(tekst_gesplitst[1]); float z = float.Parse(tekst_gesplitst[2]); return new Vector3(x, y, z); } public Quaternion TekstNaarRotatie(string tekst) { // string is bijv. (90, 0, 0) tekst = tekst.Trim(new char[] { '(', ')' }); // haakjes om de tekst weghalen tekst = tekst.Replace(", ", "#"); // komma-spaties er tussenuit halen en vervangen door # string[] tekst_gesplitst = tekst.Split('#'); // opsplitsen in array van waardes, splitsen op # // floats maken van strings float x = float.Parse(tekst_gesplitst[0]); float y = float.Parse(tekst_gesplitst[1]); float z = float.Parse(tekst_gesplitst[2]); float w = float.Parse(tekst_gesplitst[3]); return new Quaternion(x, y, z, w); } } Abstract Class for the saveable objects: Code (CSharp): using System.Collections; using System.Collections.Generic; using UnityEngine.SceneManagement; using UnityEngine; enum ObjectType { Frame_0, Frame_1, Frame_2, Frame_3, Frame_4, Frame_5, Frame_6, Frame_7, Frame_8} // selecteerbaar via inspector public abstract class SaveableSectiesAlgemeen : MonoBehaviour // abstract, kan niet aan gameobject gekoppeld worden { // Deze class bevat alle algemene functrionaliteit voor objecten protected string object_specifieke_eigenschappen; [SerializeField] private ObjectType objectType; private void Awake() // in dit geval Awake. { // Indien objecten bij de start van het spel al aanwezig zijn moet dit in de 'Start' worden opgenomen!!! // De lijst wordt al onder 'Awake' aangemaakt. SaveLayoutManager.Save_Layout_Manager.SectionsSaveLijst.Add(this); } public virtual void Save(int indexnummer) // vitual, wordt later in specifieke scrip overruled { string huidigeSceneNaam = SceneManager.GetActiveScene().name; string index = indexnummer.ToString(); string kenmerk_van_save = huidigeSceneNaam + "-" + index; PlayerPrefs.SetString(kenmerk_van_save, objectType + "#" + transform.position.ToString() + "#" + transform.localRotation.ToString() + "#" + object_specifieke_eigenschappen); // # is deelteken! } public virtual void Load(string[] tekst_data_gesplitst) // vitual, wordt later in specifieke scrip overruled { transform.localPosition = SaveLayoutManager.Save_Layout_Manager.TekstNaarVectorOmzetten(tekst_data_gesplitst[1]); transform.localRotation = SaveLayoutManager.Save_Layout_Manager.TekstNaarRotatie(tekst_data_gesplitst[2]); } public void DestroySaveable() { SaveLayoutManager.Save_Layout_Manager.SectionsSaveLijst.Remove(this); Destroy(gameObject); } } And for the saveable object specific: Code (CSharp): using System.Collections; using System.Collections.Generic; using UnityEngine; public class SaveableSectieSpecifiek : SaveableSectiesAlgemeen // <<<< LET OP: dit script is gabaseerd op SaveableSectieAlgemeen srcipt!! { // Deze class bevat alle specifieke functionaliteit voor dit specifieke object [SerializeField] private float damage; [SerializeField] private float strength; public override void Save(int index) { object_specifieke_eigenschappen = damage.ToString() + "#" + strength.ToString(); base.Save(index); // Haalt vervolgens de "base" Save functie uit SaveableSectiesAlgemeen script } public override void Load(string[] tekst_data_gesplitst) { damage = float.Parse(tekst_data_gesplitst[3]); strength = float.Parse(tekst_data_gesplitst[4]); base.Load(tekst_data_gesplitst); // Haalt vervolgens de "base" Load functie uit SaveableSectiesAlgemeen script } }
Method used for instantiating manually: Code (CSharp): public void CreateNewFrame(Vector3 InstLoc) { frame_counter = frame_counter + 1; GameObject FrameClone = Instantiate(framesLijst[frame_index], InstLoc, Quaternion.Euler(0, frame_rotation, 0)); FrameClone.name = "Frame" + frame_counter; } Just the basic thing.
OK, my guess is that the value of NodeScript.nodeLijstScript is somehow incorrect on the templates you load via Resources.Load but correct on the object you are copying via framesLijst[frame_index]. (You've cut all the code showing how those variables are declared or initialized, so I can only guess.) Be sure you check your console for errors while you are running, and consider adding some Debug.Log calls to the Awake function so you can see what it's doing. I also notice that the list you showed your newly-instantiated objects adding themselves to in post #6 doesn't seem to be the same as the list you are saving and loading in SaveLayoutManager in post #9, so it's not clear how that data is coordinated between the two. Side note regarding this: Code (CSharp): switch (savestring_opgeknipt[0]) // index [0] = objecttype (Enum) { case "Frame_0": objectType = Instantiate(Resources.Load("Frame_0") as GameObject); break; case "Frame_1": objectType = Instantiate(Resources.Load("Frame_1") as GameObject); break; case "Frame_2": objectType = Instantiate(Resources.Load("Frame_2") as GameObject); break; case "Frame_3": objectType = Instantiate(Resources.Load("Frame_3") as GameObject); break; case "Frame_4": objectType = Instantiate(Resources.Load("Frame_4") as GameObject); break; case "Frame_5": objectType = Instantiate(Resources.Load("Frame_5") as GameObject); break; case "Frame_6": objectType = Instantiate(Resources.Load("Frame_6") as GameObject); break; case "Frame_7": objectType = Instantiate(Resources.Load("Frame_7") as GameObject); break; case "Frame_8": objectType = Instantiate(Resources.Load("Frame_8") as GameObject); break; } It looks like the name you are loading matches the "case" string in all cases. If that's the intent, you could probably replace the entire switch statement with something like this: Code (CSharp): objectType = Instantiate(Resources.Load(savestring_opgeknipt[0]) as GameObject);
I changed the 'private void Awake()' on the 'nodeScript' to 'private void update()'. BAM! Everything works, only it keeps updating every frame. My theory... On my 'SaveLayoutManager' script this is the first initialisation of a new prafab. Inside the switch: objectType = Instantiate(Resources.Load("Frame_0") as GameObject); This is when a object gets instatiated by hand: GameObject FrameClone = Instantiate(framesLijst[frame_index], InstLoc, Quaternion.Euler(0, frame_rotation, 0)); Before the line of code is finished, when I intantiate by hand, there is already a position and rotation set. On the SaveLayoutManager, the object is loaded script and all, at that point the Awake is already triggered but the object had not gotten his position and rotation yet. So it takes the defaut postions of the nodes inside the prefab.
Thnx for the advise. Also changed this line of code, doing the 'text to Vector' and 'text to Rotation' in one go. objectType = Instantiate(Resources.Load(savestring_opgeknipt[0]) as GameObject, TekstNaarVectorOmzetten(savestring_opgeknipt[1]), TekstNaarRotatieOmzetten(savestring_opgeknipt[2])); Now the 'Awake()' on 'nodeScript' works as expected.