Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
This post has been wikified, any user with enough reputation can edit it.
avatar image
1
Question by Slimy619 · Feb 24, 2014 at 02:02 PM · c#prefabloadingclones

Saving and loading Prefab clones at runtime, C#

I am making a simple map creator/editor for my final year project where i can place prefab clones in 3d space to build a multistory building. I use two types of cubes namely a "WallCube" and a "FloorCube".

I toggle between the cube selection and instantiate them on mouse-click.

I need a way to save the position and the type of the instantiated prefab and load it back at runtime. The save data needs to be in the form of a human readable text file.

I know how to instantiate and destroy the cubes, as well as create, edit and read text files, but I just can't figure out a way to interpret the saved data and use it to re-instantiate the prefabs when loading the save file.

Having an electrical engineering background means that I have a limited knowledge of the subject matter. Any assistance would be highly appreciated.

P.S. I need to save the data in the same directory as the map editor

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

2 Replies

· Add your reply
  • Sort: 
avatar image
0
Best Answer

Answer by TonyLi · Feb 24, 2014 at 02:58 PM

If you put all your clones under a root GameObject, you can just iterate over the children to list them.

The simplest text file format would be something like:

 WallCube 0 0 0
 WallCube 2 5 3
 FloorCube 8 1 7

But I'd recommend using JSON or XML because it's easier to expand and maintain. C# makes XML pretty easy. Roughly (and without testing since I'm not near Unity right now):

 public class CubeInfo { // Stores the info about one cube.
     public string prefabName;
     public Vector3 position;
     public Quaternion rotation;
     
     public CubeInfo() {}
     
     public CubeInfo(Transform cube) {
         prefabName = cube.name.Replace(" (Clone)", string.Empty);
         position = cube.position;
         rotation = cube.rotation;
     }
 }
 
 public class BuildingInfo { // Stores info about all the cubes.
     public List<CubeInfo> cubeList;
 
     public BuildingInfo() {}
 
     public BuildingInfo(GameObject rootObject) {
         cubeList = new List<CubeInfo>();
         foreach (var child in rootObject) {
             cubeList.Add(new CubeInfo(child));
         }
     }
     
     public Instantiate(GameObject rootObject) {
         // Rebuild the cubes after loading building info:
         foreach (var cubeInfo in cubeList) {
             GameObject cube = Instantiate(
                 Resources.Load(cubeInfo.prefabName),
                 cubeInfo.position, cubeInfo.rotation);
             cube.transform.parent = rootObject.
         }
     }
 }
 
 void Save(GameObject rootObject, string filename) {
     BuildingInfo buildingInfo = new BuildingInfo(rootObject);
     XmlSerializer serializer = new XmlSerializer(typeof(BuildingInfo));
     TextWriter writer = new StreamWriter(filename);
     serializer.Serialize(writer, buildingInfo);
     writer.Close();
 }
 
 void Load(GameObject rootObject, string filename) {
     XmlSerializer serializer = new XmlSerializer(typeof(BuildingInfo));
     TextReader reader = new StreamReader(filename);
     BuildingInfo buildingInfo = serializer.Deserialize(reader) as BuildingInfo;
     buildingInfo.Instantiate(rootObject);
 }

For clarity, the code above also skips null checking and other good coding practices. I'm typing this directly into the answer box since I'm not near Unity, so it might be a minor miracle if it compiles without syntax errors. But it should give you a general idea of one way to do this.

Comment
Add comment · Show 4 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image RudyTheDev · Feb 24, 2014 at 03:06 PM 0
Share

@TonyLi: Hah, you beat me to it by a $$anonymous$$ute :) One thing I would add is that I assumed that op might need different data for different classes, like, say:

 WallCube 0 0
 WallCube 2 3
 FloorCube 8 flat 7.324

Otherwise, it works nicely for same-class based data.

avatar image Slimy619 · Feb 25, 2014 at 02:52 PM 0
Share

Thanks a lot for the guidance! :)

avatar image Slimy619 · Feb 27, 2014 at 02:13 PM 0
Share

@TonyLi: I did some $$anonymous$$or changes to your code to make it work.

I'm posting the code just in case anyone like me needs a little help figuring out the problems in the code.

 using System.Collections;
 using System.Collections.Generic;
 //using System.Xml; 
 using System.Xml.Serialization;
 using System.IO; 
 //using System.Text; 
 
 public class SaveLoadSystem : $$anonymous$$onoBehaviour {
     
     
     public GameObject CubeContainer;
     
     // Use this for initialization
     void Start () {
         
     }
     
     // Update is called once per frame
     void Update () {
         
     }
     
     public class CubeInfo
     {
         public string prefabName;
         public Vector3 position;
         //public Quaternion rotation;
         
         public CubeInfo()
         {
         }
         
         public CubeInfo(Transform cube ) 
         {
             prefabName = cube.name.Replace("(Clone)", string.Empty);
             position = cube.position;
             //rotation = cube.rotation;
         }
     }
     
     
     public class BuildingInfo
     { // Stores info about all the cubes.
         
         // $$anonymous$$ake a List holding objects of type CubeInfo
         public List<CubeInfo> cubeList;
         
         public BuildingInfo() 
         {
             // $$anonymous$$ake a new instance of the List "cubeList"
         }
         
         public BuildingInfo(GameObject rootObject) 
         {
             cubeList = new List<CubeInfo>();
             
             foreach (Transform child in rootObject.transform) 
             {
                 cubeList.Add (new CubeInfo(child));
                 //print (child);
             }
         }
         
         public void reload(GameObject rootObject)
         {
             // Rebuild the cubes after loading building info:
             foreach (var cubeInfo in cubeList) 
             {
                 GameObject cube = Instantiate(Resources.Load(cubeInfo.prefabName),cubeInfo.position, Quaternion.identity) as GameObject;
                 cube.transform.parent = rootObject.transform;
             }
         }
     }
     
     
     void Save(GameObject rootObject, string filename) 
     {
         BuildingInfo buildingInfo = new BuildingInfo(rootObject);
         XmlSerializer serializer = new XmlSerializer(typeof(BuildingInfo));
         TextWriter writer = new StreamWriter(filename);
         serializer.Serialize(writer, buildingInfo);
         writer.Close();
         print ("Objects saved into X$$anonymous$$L file\n");
     }
     
     void Load(GameObject rootObject, string filename) 
     {
         //        while(rootObject.transform.GetChildCount()>0)
         //        {
         //            GameObject.Destroy(rootObject.transform.GetChild (0));
         //        } 
         
         XmlSerializer serializer = new XmlSerializer(typeof(BuildingInfo));
         TextReader reader = new StreamReader(filename);
         BuildingInfo buildingInfo = serializer.Deserialize(reader) as BuildingInfo;
         buildingInfo.reload(rootObject);
         reader.Close();
         print ("Objects loaded from X$$anonymous$$L file\n");
     }
     
     void OnGUI()
     {
         if (GUI.Button (new Rect (30, 60, 150, 30), "Save State")) 
         {
             Save (CubeContainer, "savefile.xml");
         }
         
         if (GUI.Button (new Rect (30, 90, 150, 30), "Load State")) 
         {
             Load (CubeContainer, "savefile.xml");
         }
     }
 }

Of course I will be changing it and adding stuff to it like null-checking and over-writing etc. But for now, this should suffice. Cheers! :)

avatar image TonyLi · Feb 27, 2014 at 03:31 PM 0
Share

Thanks for posting the fixed code. You might consider sharing it on Unify, too: http://wiki.unity3d.com/index.php/Scripts in case it can help someone else.

avatar image
0

Answer by RudyTheDev · Feb 24, 2014 at 03:01 PM

In common terms, Unity's editor is pretty much your level editor most of the time, and scenes are your levels. I assume you want custom editor during run-time, which is essentially a save game.

If you want it human-readable, you will most likely need to make your own save/load parser, re-create all your objects on load, and save/load each variable yourself. There are many different paradigms how saving/loading can be done. Usual recommendation for Unity is serialization (like Unity does internally) that preserves everything serializable about your objects. Of course, this is not at all human-readable if somewhat easier.

Before I go on, what you call "prefab clones" are just GameObjects in the scene (that they are blue means they have an editor-time prefab connection, but they are independent otherwise and become unlinked as soon as you start playing).

The following is personal preference. I usually keep my data bound as little to GameObjects as possible if I plan to save/load myself. This way I control myself everything I save and load. What I keep in GameObject scripts is basically their run-time and visual info that's not saved and various Unity events, like mouse clicks or collisions.

Let's say I have a WallCube class. When I create this class, I also make sure I instantiate a corresponding prefab for it and attach a simple reference script, say WallCubeGameObject. There are two cases how I can create the data class -- directly or by loading from save file. It also has a save routine. So something like:

 public class WallCube
 {
     public WallCubeGameObject ourWallCubeGameObject;
 
     public int ourHeight;
 
     public WallCube(WallCubeGameObject wallPrefab, int givenHeight)
     {
         // Initialize our variables as given
         ourHeight = givenHeight;
 
         // Make our game object
         ourWallCubeGameObject = (WallCubeGameObject)GameObject.Instantiate(wallPrefab);
         ourWallCubeGameObject.ourWallCube = this; // tell it who we are for back-talk
     }
 
     public WallCube(WallCubeGameObject wallPrefab, StreamReader saveFileStreamReader)
     {
         // Load our variables from save
         ourHeight = int.Parse(saveFileStreamReader.ReadLine());
 
         // Make our game object
         ourWallCubeGameObject = (WallCubeGameObject)GameObject.Instantiate(wallPrefab);
         ourWallCubeGameObject.ourWallCube = this; // tell it who we are for back-talk
     }
 
     public void Save(StreamWriter saveFileStreamWriter)
     {
         // Write down to save file who we are, so later loading knows this
         saveFileStreamWriter.WriteLine("WallCube");

         // Save our variables to save
         saveFileStreamWriter.WriteLine(ourHeight);
     }
 }
 
 public class WallCubeGameObject : MonoBehaviour
 {
     public WallCube ourWallCube; // so we know which data is related to this instance
 }

Let's say I am saving the entire game world. I would loop through all objects and call Save() on each. They also write down who they are, e.g. "WallCube". Then, when I an loading them, I would see a string "WallCube" and call WallCube class constructor. Something like:

 identifier = streamReader.ReadLine(); // whatever way you save files, StreamReader is an example
 if (identifier == "WallCube") cubes.Add(new WallCube(wallCubePrefab, streamReader));
 elseif (identifier == "FloorCube") cubes.Add(new FloorCube(floorCubePrefab, streamReader));

Again, I have to stipulate this is just how I have done things for certain scenarios and highly depends on how you store and manage your data. But may be it gives you an idea of how to approach this.

You could use Reflection, but that, without going into details, is--in my opinion--an overkill.

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Slimy619 · Feb 25, 2014 at 02:53 PM 0
Share

Thank you for the help! :)

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

24 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Cant delete clones of prefab 1 Answer

Multiple Cars not working 1 Answer

Distribute terrain in zones 3 Answers

Dynamically saving and loading player-created prefabs 0 Answers

Tetris, Tetrominoes Clones Spawn Same Time 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges