Last week was my first week of full-time development back on Gunmetal Arcadia following Zero‘s launch. It was…slow. I’m still kind of in that “I just shipped a game and I want to turn off my brain and play video games for a change” mode. But I did get some stuff done, so let’s take a look at that.

I’ve been stewing over random level generation for some time. It was an unsolved problem as of last August when I introduced Zero to solve my ongoing production crisis, and I’ve only just recently begun to give serious thought to how it should work. Fortunately, inspiration struck early Tuesday morning, just when I was planning to start implementing some of those systems. I realized I could partially decouple the level data exported from my editor from the level data the player traverses such that I could still sample into the prefab data at will to build playable rooms on the fly. It’s hard to express exactly what was revelatory about this; fundamentally I’m still building prefabs in the editor and pasting them around in the game to construct full levels, but there was a subtle way of thinking about it that hadn’t quite clicked until then. Once I got over that hump, I’ve been able to actually start prototyping a very rough form of randomly generated levels.

So this week has mostly been spent getting my ducks in a row to deal with randomly generated levels in Gunmetal Arcadia. My first order of business was to load level data from the editor and paste rooms together in random ways while respecting the shape of the level which had been hardcoded in advance. (This is what I captured in the preceding video.) This quickly revealed a big problem I hadn’t predicted, which was how to deal with GUIDs of hand-placed entities in prefab rooms.

As I’ve mentioned before, I tag all my entities with a GUID. For all entities placed by hand in the editor, this GUID has historically been assigned by the editor. But now I’m entering a world where the data authored in the editor is only a template for what may appear in the game, and I can no longer trust this editor-assigned GUID to be unique. If the same prefab appears twice at runtime, and if each prefab spawns a copy of the same hand-placed entity, and if each of those entities shares the same GUID, then the game can’t distinguish between them. In practice, this issue manifested itself as a bug in which killing an entity in one room would have the side effect of killing its pair in another room built from the same prefab. Clearly I needed a new approach here.

My current solution is to assign GUIDs at runtime. I’ve done this in the past for dynamically-spawned entities, but that’s a subtly different case when it comes to entity serialization. (In particular, entity death must be serialized for hand-placed entities, while dynamically spawned entities can simply be forgotten altogether when they die.) In this case, I want to treat these things as if they had been assigned a GUID by the editor, but also ensure that their GUIDs are in fact unique even when the same prefabs appear multiple times.

To this end, I no longer assign GUIDs through the editor. GUIDs are strictly assigned by the game at runtime, and to ensure their uniqueness, they’re constructed bit by bit using data that will be unique to the context in which they appear.

I use 32-bit unsigned integers for my GUIDs. The high bit is reserved to indicate dynamically spawned entities. This leaves 31 bits to work with. I convert the coordinates of the room to signed bytes (effectively limiting the coordinates of levels to [-128, 127]) and write these into the GUID along with an unsigned byte representing the index of the entity as exported from the editor. In 24 bits, this gives me a value which is guaranteed to be unique and is valid for use as a GUID. With this substitution in place, I can reuse prefabs as many times as I like, and the game will view the entities within each as being totally unique, separate instances of the same template.

Since recording that video, I’ve begun toying with the idea of descreasing the size of prefabs to a quarter of a room. I’ll be talking a little more in Wednesday video about my reasonings for this and the problems it causes (and hopefully my solutions to those problems, assuming I’ve found any by then).