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.