I went down to London to see Orchestral Manoeuvres in the Dark at the Royal Albert Hall this week. That was on Monday, and since I got the train back on the Tuesday, I figured I might as well take the rest of the week off work too. Go hard or go home, am I right? (Or in this case, do both.)
That gave me a few days to work on something a bit meatier than usual, the kind of work that I shy away from because, while it may be necessary, it’s complex and scary. Why did somebody so full of fear take up solo game development? That’s a question I ask myself every day.
I haven’t released it yet, but I recently fixed another problem with saved games: loading a game at night would cause the street lights not to turn on. Nobody has reported it, but I spotted it myself and had to clean it up. I fixed it, it’s fine, but the root cause is something that’s been niggling at me for a while.
Lots of pieces of an Exon level initialise themselves according to the whims of Unity itelf. They’re in the level, they have some logic in Awake or Start, and that all fires automatically when the scene is loaded. Fine.
In this case, the street lights were initialising themselves to be either on or off depending on the time of day. Except… this was before the saved data was reinstated: it was always the default, always midday. The lights quietly turned themselves off, then the darkness was applied from the save… Without any transition, so they didn’t turn on again.
There are other complications in this flow.
Unit Nodes, for example, spawn their units only if this is your “first visit” to a particular level. Otherwise, they expect their unit to have been regenerated from save data (whether you’re loading a save directly into that level or returning to it from another). That means I have a whole heap of Awake/Start logic bracketed by “is this your first visit?” conditionals.
So I’ve been feeling like I need to restructure how a level initialises, get out of those Awake and Start callbacks over which I don’t really have enough control. They’re useful for objects coming into existence, for sure, but level initialisation is no longer so simple or self-contained.
Effectively, it needs to be something like:
- Give Unity a frame to do all the ultra-basic Awake initialisation like instantiating lists and whatnot
- Take a moment to build the pathfinding grid and initialise other more complex systems
- Either inject the saved data OR initialise the level for the first time
- (Spawn an understudy hero if there isn’t a proper one)
- Finally, give control back to the player and start fading in
Previously, my levels were structured quite haphazardly, so this would actually have been pretty difficult to coordinate. Now, though, I’ve enforced a consistent structure, so most of these save-or-initialise objects are Nodes that live under Areas; it’s very easy for the game to list them and work through them. I can do that “is this your first time?” check once and just call the right initialiser thereafter.
Of course this gets me thinking. I’ve added a little extra, currently empty, hook between zero and pathfinding, for building the level. That could be some procedural generation, or it could be loading it from a different external source.
I have to admit: despite how I’ve built it, laser-focused on my desires, reaching for the platonic ideal of a video game I want to play, I will never be able to enjoy Exon. I crave novelty, and since I built it, since I know every inch of it, right down to its beating heart, Exon cannot surprise me. It cannot delight me.
This is why procedural generation is so seductive; the thought that I could build a mechanism that fitted my desires and yet would still be able to surprise me, to produce novel and exciting output that still lives within the parameters of the mythical Game I Would Love To Play.
I’m getting all maudlin because deep dives like this have been getting rarer — I’ve been moving away from programming the engine and getting into building levels. That was always the plan; to really hammer out the foundation and then put it away and live happily ever after in the editor…
But I keep thinking about how I’ve tied myself to the Unity editor. All of my tools — the conversation editor, the trigger editor, Terragne — are built as editor extensions. They cannot exist apart from it, and their output is compiled; they merely rearrange the blocks I could put together by hand with Unity’s own tools.
But they are systems, systems that mostly exist on top of Unity itself: they could be assembled at runtime. Terragne meshes are built from primitive data structures and they make use of no editor-only mechanisms. Triggers are lists of action classes executed in sequence; the drag ‘n’ drop references I use to tie things together are boiled down to string IDs at runtime, so why couldn’t they be stored like that in the first place?
I keep wanting to work on levels for Exon outside my main PC. My little laptop is fine for Milkshape, for Paint Shop Pro and for writing text; but it’s not powerful enough to run Unity and thus not powerful enough to let me truly build levels. But what if I could strip away the rest of Unity? What if I could pare away the harshest parts of the actual game engine — the dynamic shadows and the constant raycasting — and make a build that just let you edit Terragne and triggers and conversations?
What I’m trying to say is: seriously, why am I not building an external level editor? Why am I not shipping such a thing with my game? Why can’t I encourage other humans to provide the novel scenarios I crave, but within the parameters I set? (Ignoring, for the moment, the vast assumption that others would even care to work within my art and my engine.)
It might not sound like much, but with this rearrangement of the level load order, I can almost see how an external level editor would work. Almost.