1
\$\begingroup\$

I'm working on placing predesigned tilemap rooms in my procedural dungeons, and I would like to design the items' and monsters' placement in these special rooms as well.

Currently I "compile" my predesigned room scene into a scriptable object, and the map generator loads that tilemap into "gameplay" tilemap.

I already parse the special game objects in the scene (like items and monsters), and store their transforms and prefab paths in the scriptable object.

But this has 2 problems:

  • Having every item and monster in the resources folder would make my executable huge.

    • But this could be solved by making a "MonsterPrefabDictionary" on a manager like gameobject, and drop every prefab into this list in the editor. The map generator would simply use this dictionary to find the object's prefab.
  • The biggest problem is that every variation of monster would need another prefab (or prefab variation). And by variation I mean the little changes as well.

    • Want a mob to have only 50% health in the room at start? Make a prefab for this?

    • Want a monster to start with a specific buff in this room? Make a prefab for this?

    • Want a monster to start in a different stance than usual in this room? Make a prefab for this?

    • So as you can see, this scales pretty badly.

    • But this could be solved by storing the MonsterScript's every data in the scriptable object.

    • But this would scale badly as well, because every new information about a monster would have to be added to this serialization process as well.

Is there a built-in, automatic, easy way to just save a GameObject's full state and just load everything with one line later on?

\$\endgroup\$
  • \$\begingroup\$ I don't understand why you would need all your items in the resource folder, or in a dictionary. You can reference the prefab asset directly in your scriptable object, no path or dictionary lookup required. \$\endgroup\$ – DMGregory Sep 21 '19 at 17:30
  • \$\begingroup\$ @DMGregory Yeah I could with drag-n-drop, but I'm working on a scene parser, where I only have access to the GameObjects. But it doesn't matter anyway, because the emphasis is on that if I set up a GameObject in that prefab room (scene) like a "Goblin" prefab but with 50% health, double than normal attack speed, etc, then I'd like to transform this information into my scriptable object, so I'll be able to load it into a Goblin prefab when it's spawned during map generation. \$\endgroup\$ – Tudvari Sep 21 '19 at 18:44
2
\$\begingroup\$

I think that you went down the wrong rabbit hole and should take a step back instead of going deeper.

You goal is to generate levels proceduraly. For that you want predesigned rooms containing different kinds of entities. So you why not create a prefab for every room?

Unity would serialize all child GameObjects of the room together with the room. Additional room-specific information can also be stored on a MonoBehaviour, let's call it RoomData, that is placed on the root object. You can copy and paste all fields and methods of your RoomScriptableObject into the new RoomData component.

On the class (LevelGenerator?) that previously hold a reference to all instances of your RoomScriptableObjects you now instead add a field public List<RoomData> rooms that holds a list of room prefabs. You can then create rooms by instantiating prefabs from the List. This should only change your generation code by a little bit and all GameObjects of the rooms are serialized.

This would also allow for room variants, something that you can't really do with scriptable objects without getting some sort of redundancy.

EDIT:

Naive approach:

To avoid multiple tilemaps you could load each room-tilemap, after instantiation, into the gameplay-tilemap and delete the room-tilemap. Then profile performance of this naive approach.

Approach similiar to yours:

You keep the RoomScriptableObject approach for rooms and instead of having one prefab of the whole room you only create a prefab that contains every GamObject of the room but the rooms tilemap. Then store this prefab in a single field GameObject roomContent of the RoomScriptableObject class. You still serialize the tilemap into the RoomScriptableObject like you did before. On generation you extend the gameplay-tilemap via the serialized data in the RoomScriptableObject like before and then instantiate the roomContent prefab.

On Optimization

It is common knowledge that premature optimization should be avoided and that simple solutions are desirable over complex ones. So I would encourage you to try the naive approach first before you invest time into optimizing something that doesn't necessarily needs it. This is especially true if optimizing makes content creation harder for designers or more prone to buggs.

This of cource has no meaning if you already know that this approach is too slow from prior experience or profiling.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ That would result in multiple tilemaps in scene, i.e 2 for every prefab room instance (1 collider, 1 non-collider). This is why I had to manually serialize the tiles from that tilemap into a ScriptableObject. So later on I could load them into the gameplay tilemaps, into the map structure on which pathfinding, etc is done, etc. Or maybe I'm getting something wrong. After instantiating the prefabs I would have to transfer every tile as well, then delete the prefab tilemaps. And this would mean that I would be at the same place but with less performance (due to instantiating)? \$\endgroup\$ – Tudvari Sep 22 '19 at 4:39
  • \$\begingroup\$ But yeah, at least I could predesign every GameObject in the room. Isn't there some kind of middle ground? Couldn't I easily serialize somehow a GameObject's entire state? \$\endgroup\$ – Tudvari Sep 22 '19 at 4:41
  • \$\begingroup\$ I see, sorry I missed the 'map generator loads room tilemap into gameplay tilemap' part of your question. I'll update my answer \$\endgroup\$ – Bartimaeus Sep 22 '19 at 8:56
  • \$\begingroup\$ I updated the answer, let me know if this still isn't what you are looking for \$\endgroup\$ – Bartimaeus Sep 22 '19 at 9:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.