I’m working on a game in which a 3D map (which is tile-based) is represented by a hierarchy of objects with a single GameObject at the root, custom scripts, etc. Obviously there are other objects in the scene as well, this is just the map itself. This is already working for me (custom editor, path finding, game rules, etc.) so I don’t want to change this setup. However I have an issue.
So far I’ve saved these maps by creating a prefab for each. This works well, with one exception - prefab connections are lost for objects deeper in the hierarchy. I know this is a known issue with no good solution so far. I’d like to avoid having to buy some package just to solve this.
Here are things I tried to solve this:
Replacing prefab objects with “impostors” when saving. When the map is loaded these impostors are automatically replaced with the proper GameObject.
Issues: performance-wise it’s terrible when saving, acceptable but not the best when loading. Most likely going to have issues with physics and other things that rely on the map being static.
Saving the list of prefabs into a map inside the script, re-building from this when loading.
Issues: a lot of issues that came up with the previous solution, plus a weird bug that sometimes didn’t save or restore all the objects properly.
Removing all the scene objects except the map and saving it as a new scene (from a script). Loading it additively.
Issues: for some reason the saved scene would sometimes have objects (main camera) left that should have been removed. Plus a random inspector error when doing this manipulation that I couldn’t figure out. Didn’t seem to cause problems, but annoying.
Writing a custom serializer to take care of it all.
Issues: ran into a lot of issues related to null references, setting different script types based on saved data on objects, etc.
May work, but I didn’t want to spend more time with it than this.
So now my question is: is there a simple, or at least working solution for this issue?
Again, I’d like to avoid switching to an external editor or a new map setup if possible, since I’ve put a lot of work into getting this working already.
All I really want is to save a GameObject’s hierarchy as an Asset that is not a prefab, just a loadable set of objects.
After messing around with this some more (particularly working on no. 2 again) I realized that very often when iterating and removing/instantiating children in an editor function it may “miss” some of the children. For example if I have a lot of child objects, and want to destroy all of them before saving, some of them will not be destroyed. Can this be a bug or something?
Not sure if this is the reason, but you’re not iterating start-to-end are you? Because depending on how your loop is set-up, that could end up skipping some objects.
I solved that exact problem with saving cloned gameobject to prefab. Let me try to explain if it doesn’t make sense yet.
Save your levels in separate scenes, which has your root level gameobject which itself is not connected to prefab.
Create Editor script that clones gameobject, saves it into a prefab in Resources folder, and then delete the cloned gameobject in scene. Your original prefab connections in that root level gameobject should stay as they were never touched.
When running the game you can Instantiate saved level prefab from resources.
Other things: Combine meshes in editor and do other optimizes and then save cloned root level gameobject to prefab. This increases the prefab size. You can do this at runtime too which increases RAM usage and takes some time but decreases app size. It is very important to not touch the original root level gameobject so you can keep your prefab connections!
What we did with our game SpinCraft for iOS is that we combined meshes at runtime.
There might be and probably are better ways of doing this, but its just what we thought would be enough.
I hope this was helpful to someone or that it raises some further questions.
I don’t get it, how does this keep the nested prefab connections in the saved file? From what I saw once you save the root gameobject as a prefab, all its children will lose their original prefab data.
You don’t save the original root gameobject as prefab, you clone it and then save the cloned one to prefab and delete the cloned gameobject from the scene. Ofcourse you have to save it again after you have edited the original gameobject because it is not connected to any prefab. This way we build all our levels and “baked” them into prefabs while still keeping the nested prefab connections for quick level editing.
-hp
P.S. It doesn’t keep the nested prefab connections of the saved level prefab of course. For that problem I don’t know the answer.
Anyway, if anyone cares, here’s the solution I found:
-my map holds a list of GameObjects (prefabs reference) and positions, that is serialized, etc.
-when loaded, it creates a temporary object with all the tile objects (stored in the aforementioned list) as children - this object is NOT in the map’s hierarchy and is thrown away when the map is unloaded/destroyed - so essentially this is the phyisical representation of the serialized map
The results:
-saving (serialization) is fast as hell, obviously
-nested prefabs no longer exist so they’re not an issue
-map sizes are small
-editing is a little slow (at least in theory), since dictionaries cannot be serialized, so I have to work around that with lists
-loading maps is a little slow unfortunately, since all the tiles need to be instantiated one by one manually
Well my solution (in the previous reply) is still working fine, but I have a new problem.
It turns out sometimes you just have to modify values on instantiated objects. But I’d like to only save the modified values but generally keep the other variables the same as on the prefab. Is there a simple way to do this?