Dear Clockmaker Postmortem
Something I like to do after each completed project is to write a postmortem talking about how I made the game and what I’ve learned from it. This exercise is mostly a way for me to reflect on the development and learn from it, but hopefully others may also benefit from it.
Because I’m a solo game developer doing everything myself from scratch (or close to), this is a pretty long wall of text. Feel free to skip the sections that aren’t relevant to you! I added little emojis to help identify the topic of each header.
Call me Ishmael
Picture this: it’s 1998 and you’re 9. You take the bulky cartridge and slam it into your Nintendo 64 and push play. Suddenly, a polygonal horse rides over a hill as the sun sets and the best melancholic music you’ve ever heard in your short life plays. You didn’t even Press Start yet but the spell is already complete, The Legends of Zelda: Ocarina of Time has taken root in your imagination for years to come.
Your mind was just blown, you’re not thinking rationally so you blurt out “I’m gonna be a game developer when I grow up!”. Way to ruin your life. In the meantime, you make your dial-up modem scream and spend a few days downloading tools on the internet including Don Miguel’s translation of RPG Maker 2000. You later learn programming with DarkBASIC because you know deep in your bones the reason Ocarina captured you so completely was because Hyrule felt like a real place in a way a 2D world can never emulate.
But making a 3D game is no easy task. You’re still a good ten years and change away from accessible versions of Unity3D or Blender. You dream big but fail small. You learn a ton but never manage to walk two steps one in front of the other before meeting the ground. So you give up and switch to other kinds of games. Story-driven games, RPGs, 2D action-adventure games. You find some success there. You complete a few projects and learn how this whole “game development” thing actually works.
But you’re still thinking of your white whale, your Moby Dick: the 3D-rendered Hyrule. This adventure you played as a kid, this virtual place that somehow felt just as real as your hometown. “It’s unrealistic to make a full 3D action-adventure game as a lone programmer”, you say. “This is just not what I’m good at, it’s okay.”
Except it’s not okay. You’ve heard the call and at some point you will have to answer it.
The Road to the Clocktower
Sorry for the little story, but I needed you in my shoes to understand why this project is such a big deal to me. You may look at screenshots and think “Meh. I’ve seen solo efforts that looked and played better than this” and 1) I know and 2) I don’t care. (Reaching 2 took some time.)
To my defense(?), this game is not made with Unity, Unreal or Godot or whatever. It’s my own, 100% homegrown tech, the same one I’ve been using for five years and counting, since Aereven Lunar Wake. This is inconsequential to most players who only see the end result, but my strategy as a developer has always been to invest for the long term. Now, I’ve always said the off-the-shelf engines bring too little to the table for 2D games to justify depending on them, but is that also true for 3D games? This is a fair question, but my answer is the same as it has always been: my engine doesn't try to do everything. It only has to support a few very specific scenarios.
I’m also fine with restricting what I’m trying to achieve depending on my tech. Most indies probably start their project with a complete vision they want to achieve and then look for the tools that will get them there, but that’s not entirely how I operate. Just as often I look at my existing tools and decide what I could make with them. That’s why I can have personal breakthroughs when other developers just use Unity or Unreal to get there without thinking about it.
Tech can be a limitation, sure, but when it comes to 3D I’ve found I'm mostly restricted by the workflow. I’m not an artist, let alone a 3D artist. Making a 3D game involves a lot of different disciplines, shoes I can't always fill competently. So even if I simply used Unreal, I couldn't realistically make my own Ocarina of Time. I couldn't provide the assets it would require. My tech exists to support a very specific way of working that is meant to get me as close as possible to my dream but taking an unusual path that benefits from my skills. A lot of this postmortem will be about my search for this fabled workflow.
(Fun anecdote: at the same time I was finishing Dear Clockmaker, I was also working on a short Unreal prototype for my day job. Every evening I was relieved to go home and fire up Dream thinking “finally an engine that feels right!”. As powerful and polished as Unreal is, it still doesn’t beat using a tailor-made tool.)
Still, getting there took some work. A lot of work. Work that spanned a decade or so. Not because I kept adding necessary features, but because it took a while to learn what those features should be to begin with. This project was made possible thanks to three main additions to my tech stack: mesh instancing, deferred rendering and simple box collisions. None of them are that complex to implement, but those were my breakthroughs.
Open the World, one Brick at a time
I’ve also wanted to make an open world game for a while. (Since 2017 or so, at the risk of giving away the pattern…)
Well, “Open” is maybe not the best term for it, so let’s say a “Seamless World”: one large continuous space without any transition. Whether or not the progression itself is open is less important to me.
I’ve always assumed making such an open world game would be a good match for a solo programmer. It’s more about systems and high-level rules than the nitty-gritty of specific level design or environment art. With procedural generation, I could trade some design and art work for tech work which seems like a better fit for my skills. I’ve certainly accumulated plenty of ideas for such a project in recent years and I've been eager to put them into practice.
Right before I started Dear Clockmaker, I was hands deep in such a prototype. Many of the technical and artistic choices that made Dear Clockmaker possible were inherited from this project. Actually, I joined this jam just to force myself to use this tech for a real, reasonably-scoped project before I went any further.
And because of the scope inherent to such an open world, the most important direction I chose for this prototype was: everything must be modular. Meaning the entire game is built by assembling smaller reusable blocks. That philosophy is present in Dear Clockmaker as well, ranging from the characters to the environments to the behaviors.
In search of an artstyle (🎨)
Characters
One of the biggest hurdles was obviously the art. I’m okay at pixel art and can draw to some extent, but 3D modeling is hard, especially for organic objects. It also involves a ton more work and complexities: modeling, UV unwrapping, rigging, animation, etc. You don’t just draw a funny little guy a handful of times and call it a sprite.
Now, if you recall some of my earlier postmortems, I was already modeling and animating 3D characters to render sprites for my 2D games. It was made easier in the sense that the low resolution freed me from texturing or proper rigging. I could make simple models made out of distinct parts like it was still the glorious N64 days and it wouldn’t show on a 32x32px sprite. This workflow worked for me and I modeled a lot of parts for this character creator through the years.
This simple character creator already fit the “everything must be modular” mandate perfectly. I knew if I wanted to have animated 3D characters in my games, I would have to reuse this system… but not the assets that went with it. Those models were made to look good when raytraced and weren’t suited for real-time rendering. Also, I worried the mix of realistic(-ish) proportions with low-details would clash.
So I took inspiration from someone truly First Class:
I had actually made a model of Lloyd from Aereven inspired by FF7’s Cloud twenty years ago (remember Milkshape3D?) and I used it as inspiration for those new models. I imagined those chibi low poly characters could be cel-shaded to contrast with the environment’s smoother lighting, just like in Breath of the Wild. Though they ended up being too low poly to really benefit from the cel shading, so maybe I needed a few more triangles to get closer to The Wind Waker’s look than Final Fantasy 7.
Environments
Characters were one part of the equation, but what about environments?
The environments of Ocarina of Time, my initial inspiration, were directly modeled as a complete mesh by a designer and/or artist. Textures were meticulously placed and lighting was baked in vertex colors. This is the “low tech / maximum artistry” approach. I mean, look at Skyward Sword’s gorgeous environments, still made this way a few console generations later:
“Low tech / maximum artistry” is absolutely the wrong way to go for a solo programmer.
What are the alternatives?
I was a LEGO kid growing up and I maintained a fascination for modular assembly. There’s elegance in building large environments out of a small pool of reusable bricks. This is one of my motivations for the “everything is modular” ethos, so it was obvious modular environments were the solution.
My initial plan was to use voxels as my building blocks, especially for the open world prototype. It went really well with the collision system (see below) and would allow me to build complex environments out of a handful of reusable pieces. You can't go more modular than that!
I tested that idea out for the open world prototype, building environments with MagicaVoxel where each color would map to a block type.
It quickly became apparent that I couldn't just pre-assemble the environment into a single mesh: there were too many vertices, even storing them on disk took hundreds of megabytes. This called for hardware instancing, a feature of most modern GPUs that let you draw the same mesh many times quickly with simple variations, notably their position. I implemented it in my SPF platform layer library (further eroding the ‘simple’ qualifier) and started playing with all this.
The voxel approach really stressed this system. You’re rendering a lot of those small (but thankfully simple) bricks. I could probably make it work fast enough but another issue quickly reared its ugly head: building voxel models is tedious. I mean, if I had been a kid with a lot of free time after school when Minecraft came out, I too would have built entire castles one block at a time. But as a grown-up game developer also moonlighting as a game developer, it was too time consuming. It didn’t help that MagicaVoxel’s camera controls were not well suited to navigate interiors.
If LEGOs were not feasible, how about DUPLOs?
Instead of building out of voxels, I could also assemble entire environments out of larger meshes, as long as they matched the correct grid size and pivot. In video games, this “kit” technique was pioneered by Bethesda for Skyrim and Fallout. I watched and rewatched their talks on the topic and then I started experimenting with Kenney’s AssetForge software.
AssetForge was promising, but it quickly showed some limitations. I wanted to assign pieces to different layers so I could quickly toggle them on or off (like hiding the ceiling) but couldn’t. I wanted to add extra metadata to some pieces to use them as markers for spawned entities, but couldn’t. And the UX wasn't quite what I would have wanted.
Eventually I rolled out my sleeves and recreated that tool in my engine. Then I was free to implement all the features I needed, with the UX I wanted. The moral of the story is the same as usual: using third party tools is nice and well to get a quick leg up but at some point you want to invest in yourself.
Though one difficulty remained: adhering to the grid and choosing a pivot point is not an easy or obvious task. Not at all. There’s an art to it and it took me many false starts before I came up with a system that worked.
And then I stumbled into another issue: my pieces were still too small and granular. A wall was 2 meters long by 3 meters high. It was fine, but it encouraged tight environments without much space to move or to accommodate the camera. Avoiding that required countless pieces that were both a strain on the instancing system, the collision system (which we will mention later) and my ability to iterate on the environment.
My solution was to go above DUPLOs and use QUATROs, aka quickly building a system to merge an assembly of smaller pieces into a larger one. Then I made a handful of 3x2 assemblies of walls (and doorframes) and used that in most places with a grid of 6x6 meters. It was a real time-saver and I could still reduce the grid size at will to accommodate tighter spaces or add finer details.
It finally fit and making new environments was a blast. At long last, I was making an interactive 3D world like I had been dreaming of since 1998!
Rendering (🖥️)
“Flat shaded low poly” is en-vogue among indies for a simple reason: textures are time-consuming. That’s one less asset type to produce and you’re spared from UV unwrapping your models. Believe me, I tried texturing my modular kits, thinking it would be doable as they were few, but even then it took forever and I finally decided against it.
But on its own, flat-shaded doesn’t look good. You need either a spectacular art direction with impeccable colors or some good lighting to make it pop. Global illumination and radiosity are the ideal for nice color bleeding, but there was no way I could achieve that. It’s too complicated and “math-y” for me. On the other hand, with “spectacular art direction” we’re back into “maximum artistry” territory.
So lighting it is! But this led to a complication: since I was using hardware instancing, I couldn't bake the lighting in the vertex normals like I was used to. I needed real-time lighting, which scared the hell out of me. I’m fine with writing complex tools but I like to keep the runtime as simple as it can be. And raytracing isn't even that complex compared to the dirty pile of smart hacks that powers modern day rasterization.
But I couldn't avoid it, especially for the open world prototype. So I took a deep breath, rolled my sleeves and started RenderDoc.
I started with shadow mapping, which I had been trying on and off for years. This is probably the least important visual effect for Dear Clockmaker considering most of the game is taking place in interiors where the sunlight can't reach, but it would have been key for the open world prototype.
The next stop was SSAO. I needed it to give depth that couldn't be faked with textures because I wasn't using any. But this effect basically requires deferred rendering. Because I knew I would also need a lot of point lights to make the lighting interesting, I went for it. I was familiar with the principle and had implemented it once with XNA, but my “Simple Platform” library wasn’t exactly meant for it. There’s nothing “simple” about rendering to different buffers of different formats to later assemble them in a single lighting pass. It took some time for me to decide how I should expand the API to support MRT without compromising the ease of making actually-simple 2D pixel art games.
But once that hurdle was gone, I could simply spam point lights. Most of Dear Clockmaker’s lighting is diegetic, meaning it comes from real sources like torches placed in the environment, but I completed it with a few large invisible lights to brighten larger rooms and give them a mood.
The next effects I wanted were reflections and emission. I wasn't going to go anywhere near PBR but I still wanted to have those two sliders (I stored them in the UVs I wasn't using!). Reflection uses cubemaps, of course, but not real-time ones. Actually, if you watch closely, you will notice the reflections don't match the room you’re in. That’s because I raytraced one cubemap per biome using a simple fake room. Simple, cheap and good enough! Emission was simply a matter of writing the mask to a texture, blurring it and adding it back to the result, just like the subtle bloom that tries to emulate some of the color bleeding I would have gotten from GI.
Cel shading is also stored as a material mask later used to posterize the lighting on the affected models.
And that’s it for the rendering! Nothing exceptional compared to modern AAA games or even Unity’s pre-built renderer, but a pretty big step-up from the vertex colored pixel-arted flat environments I thought I would limit myself to when I first built this engine.
Driven by Clockwork (🖥️)
From DCC to engine
Getting spritesheets into the engine is easy, but there’s a lot more moving parts when it comes to 3D.
My 3D package of choice is still Cinema4D… R11. Released in 2008. It works! It’s simple and elegant and I know my way around it. It’s certainly not supported anymore and writing an exporter in COFFEE Script is nobody’s idea of a fun evening, but it does the job. Though I really didn’t want to write COFFEE Script this time around so I just reverse-engineered the “Cinema4D XML” file format instead. It’s a bit messy (many properties aren’t named!) and it doesn't support 100% of C4D’s features, but it’s still better than writing some barely-documented pseudo-JavaScript code (which says a lot).
Of course, I’ve been eyeing Blender for years now. This tool had long suffered from two issues that plague the FOSS community: poor UX and defensive contributors. But ever since version 2.8, Blender has shed its “I don’t care, it works for me!!” culture and made strides toward improving its usability. It took many more years and versions to get something I could use without investing years of practice and making it my entire identity. Even today, some of its UX decisions still baffle me (eg: the way it handles its hierarchy) but I could make do with it if I ever needed to modernize my toolkit. To prove it, I also built an importer that uses Blender’s command line to trigger the glTF exporter and read that. This was a successful proof of concept… but I still used good old C4D R11 for all assets.
Head Against the Wall: a Collision Story
Collision is the bane of game development.
Traversing walls, falling through the ground, getting stuck in corners, plenty of 3D games – including modern AAA offerings and old masterpieces alike – ship with those issues. Float imprecision is a big offender here. I never managed to get an ellipsoid-vs-triangle collision (like the peroxide paper) scheme working in a robust way. There would always be a time when collisions failed, sending me back to the innocent land of 2D games with their perfect pixel grid.
I swear, most of my attempts at 3D through the years were roadblocked by collision detection. After writing off overkill and finicky physics engines like Bullet3D, I attempted a lot of creative solutions to work around the problem, including continuous voxel-based collision detection with linear interpolation to hide the grid. I was never entirely satisfied.
And then I made Aereven Advance for the GBA. This 2D game uses a really simple collision-and-response scheme. Detection is done by moving one pixel at a time and checking if the player’s pivot is inside a wall or not. Response is more interesting: each axis is tested independently. This gives a nice, natural wall sliding for free. Because you may be blocked on Y but you can still move on X. Of course, this simplification only works because walls are straight edges. You can’t do slopes that way. But if you can accept this limitation, it’s simple and it works very well. Both Aereven Advance and Distant Paradise worked that way so it was absolutely fine for top-down and side-scrolling games.
Could it work in 3D…?
In the open world prototype, collisions were derived from bitmaps. For instance I would have a bitmap encoding the vegetation for the entire world, so I could just pick the color of the tile the player was trying to access, see if it was green like a tree, and if so I knew the height was 2m tall and anything under would collide. It was a nice constant-time algorithm and because a bitmap is a succession of straight square cells it was the perfect fit for the approach described above. Though this encouraged a terraced voxel-like world when I wanted smooth terrain, so I’m not sure it’s 100% the answer for this use-case.
But for Dear Clockmaker, I could tweak it a bit. Because the environment is assembled from kit pieces, I could simply associate one or more axis-aligned bounding boxes to each piece in the DCC and check if the player’s pivot was inside. It worked: I got nice sliding collisions out of the box (ha!), as long as I didn’t rotate a piece in less than 90° increments.
However, I could still experience tunneling when dashing into the thinner pieces. To fix that, I simply extruded the player’s bounding box by the length of the move on the tested axis. Again, because it’s all straight edges, it’s possible to keep the whole sweeping algorithm as a check of AABB vs AABB. I could easily get the closest intersection on the tested axis, move up to that point, and stop. This resulted in my holy grail: 100% reliable collision detection and response. No tunneling, no getting stuck. It meant avoiding all slopes or diagonal corners but it was a fair price to finally make a real 3D game.
Playing with LEGOs
In The Trespasser’s postmortem I wrote I let myself be carried away with a data-driven approach, developing many tools to do for data what a good compiler was already doing for code. I later reined it in for Silent Paradise, Lost Paradise and Aereven Sleeping Azure. And while it’s true The Trespasser’s approach was overly complex, much of it came from the fact I was still figuring it out and had multiple ways of doing the same thing. But I later came to think it did bring something to the table, even for a solo programmer.
Discoverability is one such advantage: you click “Add” and you’re offered the list of every toy you can play with. It’s not that simple with code, even with powerful autocomplete like C#’s version of IntelliSense: you kinda have to know in advance what you’re looking for, which can lead to forgetting existing classes and creating duplicates. A game is also a visual medium and for some properties, going directly through a visual editor is a real gain. Switching to Photoshop to pick a color and copy/paste its hex in the code becomes tedious fast. And the last reason is that this clear separation between code and data can help define a stable API, something I’ve been looking into recently.
As an experiment, this time I went full data-driven, even more so than The Trespasser. I did have to develop new tools, some of them which weren’t quite mature even by the end of the project. But overall? Pretty positive! It helped that I finally switched to actual graphs for my state machines, which are better represented visually. It made more sense from the start.
So, how does it work?
I’m still using the ECS described in Aereven Lunar Wake’s postmortem. So we still have Entities grouping Components that are queried and transformed by Systems. All this happens in a Scene.
This is already pretty modular, but I also wanted the layer above to fit the same “assemble small building blocks of behavior” mentality. This is achieved by having polymorphic serializable classes and assembling them using JSON trees.
So when a new entity is spawned, a predefined series of EntityBuilders (= instances of classes implementing the IEntityBuilder interface) are run to add the right components with the right values, according to its own logic. A reusable Prefab is just a series of preset EntityBuilders. Many EntityBuilders have a 1:1 relationship with a component, but some will setup multiple components at once and others will setup the same component but in different ways, etc. I had tried in the past to directly expose components as data but I find it more valuable to have this layer of indirection, which allows for a better UX, some simple dynamism (eg: I have a ConditionalBuilder that will evaluate a condition and run different sub-builders in response, allowing my Prefabs to spawn differently according to instance parameters or player’s progression) and a clear opportunity to load resources if needed.
Scenes likewise can be configured by SceneBuilders. SceneBuilders can for instance add new Systems, like different UI widgets. I only have one Scene in Dear Clockmaker, but builders don’t have to run at creation, they can also be run in response to events, like when you move from one room to another. That’s how I handle changing biomes: each room is associated with a SceneBuilder that changes the fog color, plays the appropriate BGM, etc. Even the room system itself is initially added and setup by a SceneBuilder. It’s also a SceneBuilder that is responsible for spawning the player entity.
Scripting for entities is done by combining two other constructs: EntityActions and EntityConditions. Conditions are simple: they take an entity as input and output a boolean. Does the entity have more than half its HP? That’s a condition. Is it grounded? Dead? In contact with something? All conditions. (Some EntityConditions don’t actually care about the entity parameter, stuff like “is this save flag raised?” or “are we in a debug build?”.)
EntityActions are… actually identical to EntityBuilders. They take an entity and do something. A builder is simply an action that does something to the entity, while actions do something according to the entity (eg: play spatial sound, spawn another entity at the same position, etc). Many objects are implementing both interfaces with the exact same methods. I plan to remove this distinction later and treat everything as entity actions. Just like conditions, some actions don’t actually care about the entity, like raising a flag in the save file, etc.
Then we have States and Transitions between them. It’s classic finite state machine stuff, but for some reason I never really used them in my previous games (except for the player controller, but it was expressed as code). This time I took the time to implement a full-blown visual editor to make data-driven FSM as graphs. Each state can execute EntityActions when entered or left, and also each frame if needed. Transitions evaluate EntityConditions to decide the next active state. Sometimes you need to store information in the entity itself to communicate between states, so I implemented a Blackboard component that can store integers or strings. It can also be used to customize prefab instances, as some builders can lookup values from it.
Finally, an Event system runs in parallel to state machines. It’s simply a component on the entity that describes a list of events made of an EntityCondition and EntityActions to execute once the condition evaluates to true. It helped to rig simple interactions without requiring a full-blown FSM (eg: on Triggered, run DisplayMessage) or to have small interactions that happen in any state (eg: on Damaged, spawn VFX + play SFX).
In total there are 67 actions, 48 builders and 40 conditions. That’s enough to power everything you see in Dear Clockmaker. They could certainly be used to make very different games! There's very little code in Dear Clockmaker’s executable that is related to that specific game (maybe the grappling hook system? But it’s reusable).
Assets management
One issue I had with a data-driven approach in the past is the amount of JSON to parse when starting the game. It’s probably not really significant but it bothers me on principle. To avoid this, in Dear Clockmaker every data asset is “cooked” into a single binary archive. It’s mostly transparent because the data classes simply describe their fields and different visitors are responsible for implementing serialization or the property grid from this description. So I could simply swap the JSON serializer for a binary equivalent in release builds and that’s it.
I did invest some time working on tools to tell me which data requires which or what building blocks are actually used and where. I also had a ‘substitute’ system to replace a missing class by a neutral one to allow the game to boot despite data errors. Then I could use the editor to quickly select a new type and preserve as many fields as possible. That was enough for Dear Clockmaker, but in the future I think I may implement a system of aliases to automatically redirect a missing type to its successor, and a process to go over all data to persist the replacement. It may end up becoming a full-blown data deprecation and migration service, who knows.
Now that I knew which files used which classes, I knew when it was safe to remove one. I expect this will get more complicated as I make other projects using the same engine, but that's already an issue I'm facing with code references living in separate Visual Studio solutions.
One difference from my previous games is that the runtime can query the list of all known assets and know their type in advance. Before, I had to explicitly reference data in a central database, using identifiers as keys. Now the path to any data file acts as the key, just like it would for textures. Also, classes aren't the only resources that can be substituted when missing. Assets can be substituted as well, so if a referenced texture is missing for instance, another one can be used instead so the game doesn't break.
Editor Commands
Commands are similar to entity actions except they’re made to automate parts of the ‘offline’ workflow. They’re used to import or convert data, generate stuff, etc. They don’t run automatically as part of the game, they must be manually triggered from the editor when needed. Individual commands can be aggregated in a “playlist” command.
For instance, there’s a command to export the kit pieces from the DCC. It’s also part of the “Build All” playlist that runs every automated step required to get the game’s data up to date. There's also a command to “cook” the many JSON files into the final binary bundle.
Commands can even be called from the executable’s command line without having to open the editor. That’s very useful when the data is broken and the game crashes on boot and you need to trigger a command to fix it. Also useful to automatically create a release bundle.
I like this approach. It’s simple yet very flexible and reusable. It can also be integrated into some primitive CI/CD pipeline.
Concept & Design (🕹️)
The Clockmaker’s Wife
Because the open world prototype I was making was meant to become an Aereven game, I first thought this smaller practice game should be one too. Maybe another one of Lloyd’s experimental adventures? And because we were suffering from a heatwave at the time, I was dreaming of an icy mountain under a starry sky, with ice caves and all. So chill! The story could be about Lloyd meeting a mad Zael sorcerer playing Frankenstein at the top of his icy tower.
And then the jam started with the theme “clockwork”, which I did not vote for. Actually, I voted for every other theme but this one.
Deflated, I sat down and wrote the word “clockwork” on a Google Doc to see where it would lead me. I could ape Castlevania’s clocktower and call it a day but was that it? It was still a good starting point: explore the workshop of the world’s best clockmaker, built inside a weird pocket dimension.
Then came the enemies, mechanical toys with wind-up keys on their back. I still had the mad wizard/Frankenstein idea on the back of my mind, so it was obvious the clockmaker was trying to create artificial life. Bosses could be improved automatons looking more life-like.
Also, Frankenstein’s creature wished for a wife to feel less lonely, so maybe that was the clockmaker’s goal? This led to a story about playing as the clockmaker’s daughter trying to make her father come to his senses and accept the death of his wife. But wait, wouldn’t it be even better if you played the wife herself? The clockmaker thought she was dead and was trying to recreate her artificially but she was like “dude, stop it, I’m right here!” And then wham! you learn she was actually dead and the player is merely a prototype who believed herself to be the real deal. And double-wham! when you learn the clocktower was never married to begin with because his clocktower is actually an extradimensional prison he was sent to as a boy. He’s just trying to build some company for himself like Frankenstein’s creature.
Now I was inspired.
The story would be a mix of Frankenstein and the myth of Pygmalion. The discarded prototypes would be inspired by well-known fairy-tales like The Snow Queen or One Thousand and One Nights.
The tales and the biomes came from what I anticipated would be the needs of the open-world game: as an Aereven game, it would surely feature ice palaces for the Zaels, desert ruins for the Dragonkin and pseudo-Shinto temples for the Aquans. If I could fit those in this game, it would mean creating kits I could reuse later.
For the Japanese tale, I initially selected The Tale of the Bamboo Cutter but later changed it to the legend of Urashima Taro as I’m absolutely fascinated by the underwater Ryugu Palace which features in many of my games going back to Tower of Ordal.
Dear journal (✍)
At this point, the tentative title was “The Clockmaker’s Wife” as a riff on “The Time-traveler’s Wife”, but I later changed it for the more punchy “Dear Clockmaker” as I decided how I would tell the story.
Back when I made Silent Paradise, I decided not to rely on the omniscient narrator Dark Souls popularized for item descriptions and instead limit myself to what was publicly known about the underwater city you were exploring and leave the inner reveals to codex entries. I opted to do something similar here, with most item descriptions being told in the first person as a way to characterize Galatea, the player character. This way you would learn who she was, her motives, personality, and what she believed to be true.
Later items would start sewing doubt about her real nature, preparing for the twist. And then the armor pieces descriptions would be written from the point of view of the characters they imitated, as a way to learn more about those bosses you had unceremoniously dispatched. It was a way to challenge Galatea’s narrative and tell you who the clockmaker really was and guide you toward saving him (and yourself). I took some inspiration from the Weapon Stories featured in the Drakengard/Nier series.
Fashion Souls is the real Dark Souls
Let’s talk about those armor pieces, shall we? The whole concept is lifted from the open world game. You can tell because it works exactly like in Breath of the Wild, with three matching pieces making a set (except there’s no gameplay bonus here).
Most of my metroidvanias feature alternative outfits, especially those relying on pre-rendered 3D models. But with a full 3D game I could go further and have you mix and match sets to create the appearance you want. In other words… Fashion Souls, baby! I couldn’t resist this idea. I already had this character creator, it cost me nothing to implement this feature.
But then I hit an issue: you reached the clockmaker and learned the truth… now what? How do you actually leave the pocket dimension he’s been locked in all his life? How come he never found the exit on his own if it’s just a matter of exploring and collecting trinkets? I didn’t have time to design an involved sequence (or “inverted castle” as I like to call it) to reach this secret ending.
What I had were those purely cosmetic armor pieces that felt completely divorced from the rest of the game. Could I tie them to the ending? Collect them all to leave the tower? How would that make any sense?
I don’t remember how the idea of dressing up as the four bosses to light four candles came to me, but it was all at once and it fit perfectly with the fairytale motif. I had already decided Otohime would be an NPC instead of a boss (to reduce scope) so she could be the one leading you toward that path.
Sadly, there’s an issue with this: it means collecting the different armor sets is the endgame. So it’s basically too late to play dress-up! Ideally you want to get new armor pieces regularly so you can shake things up as you progress, not look the same for 99% of the game and then unlock all the alternative options in the last minutes. Oh well, a lesson for another time. (And some pieces can actually be unlocked early if you know what you’re doing.)
Also, this requirement for the ending was a bit too subtle. That’s a regular issue with my work. I love games that make you think and engage deeply with the story, but I always overestimate the clarity of the clues. I feel like I’m basically giving the solution away and yet most people absolutely miss it. It happened again with Dear Clockmaker, so I went to some lengths after the jam to add more clues and highlight the existing ones.
Level design (🕹️)
I know MVM is a metroidvania compo but this time I didn't stress that requirement too much. I’ve joined enough times to know participants are pretty loose with the definition so I did the same. There’s just as much Zelda or Dark Souls DNA in Dear Clockmaker as there is Metroid’s. The Desert Ruins are basically a Zelda dungeon, Small Keys included!
The first two regions (the meatiest parts of the game) were designed using GMTK’s graph notation. It's not how I usually design metroidvanias but the latest Aereven game, Sleeping Azure, was made this way. It’s a nice technique to preview complexity and ramp up difficulty.
Sectorization (🖥️)
Something super cool about the first Dark Souls is that the entire world is seamless. Everything is (roughly) connected and (mostly) makes sense. You can walk from one point of the world to its opposite without encountering any loading screen.
I wanted that for Dear Clockmaker. But while I’m pretty sure I could fit the entire world in memory, it’s not possible to display it all at once and it’s not practical to keep all entities alive and simulated no matter where they are.
So, I used a time-honored tradition and implemented some sectorization. The world is split in rooms connected by accesses. At runtime, I keep a graph of those rooms and check in which one the player currently is (using its bounding box, which became an issue, as we will see later). I add this current room to the list of currently active rooms and then add all its neigbors as well. When a room becomes active, all entities placed inside spawn. When it becomes inactive, they despawn. Moving from one room to another triggers a SceneBuilder to change the environment settings (cubemap, fog, BGM, etc). Very simple!
Well, one issue is that you can’t connect multiple rooms in a straight line. Imagine you’re into room A and see through an opening into room B. Both are active, so that’s fine. But what happens if B has another door leading to room C and you can see it from A? C isn’t connected to the current room, so it won’t be visible. You will see the void!
I initially accepted this limitation, taking note of not doing straight lines of sight between more than two rooms. The first corridor you encounter is awkwardly shaped like an S to break line of sight. But of course, it’s just too limiting, especially for man-made environments. At some point you want doors facing each other. I didn’t track all such instances, so you can definitely see missing rooms in some situations. They appear when you get closer, so it’s only a “harmless” visual bug, but it’s not great. Maybe precomputing line of sights could be a solution, or having impostors for each room, I’m not sure. I don’t want to overcomplexify this system, but that’s what you get when the camera is free to look wherever it pleases.
Another issue I encountered was to identify in which room the player was. Each room has an automatically-computed AABB, so if the player’s pivot is inside, you’re considered inside the room. Again, this is very simple and efficient, but a bit limiting. What if your room is concave? It may not technically overlap with its neighbors but its AABB may. In which case, the player can be detected in two rooms at once. Which one is the correct one?
It wasn’t too noticeable until I introduced a new rule: enemies must be in the same room as the player to detect them (to avoid sentinels trying to fire through walls, or enemies coming to you before you can notice them). Now, if the player was detected in the wrong room, the enemies would stand by and do nothing. One way I solved those issues was by decomposing big rooms into further smaller rooms so that their bounds would be more precise. (If there was no enemy around, I didn’t bother.) But this was a pain, which leads us to the way the world is actually assembled…
Assembling the world
Making an interconnected world that loops back on itself is hard enough in 2D but it’s even worse in 3D.
I made it harder on myself by not building my rooms on a rigid grid. When I'm making a 2D game, every room size is a multiple of the screen size (usually 20x11 tiles) so I know stuff will always line up, even if it sometimes requires adding transition rooms to connect both ends (the issue is more often when I don't have enough space for those connections). Here, without this grid size, I was basically blind.
The few extra loop backs present in Dear Clockmaker were added at the very end, so they were tailor-made to fit the space left by the rest of the map and thankfully I didn't resize any room afterward. But that’s a terrible way to work!
This issue was partially mitigated by my workflow, which consisted in making an entire region at once before splitting it up in distinct rooms to help sectorisation (which sadly encouraged concave rooms, making the boundaries problem worse). But again, changing any room’s size afterward would have been a nightmare.
If I revisit this format in the future, my plan would be to mandate a rigid grid size for the rooms themselves. Probably a multiple of 6x6 to match my biggest pieces. This should make it easier to line-up rooms and avoid overlaps. In theory, at least…
Iron Pipe to the head (🕹️)
The first thing I wrote on my Google Doc was “Goal: make an interesting 3D space you want to explore. Everything else is secondary“.
Combat was very, very secondary. You can probably tell! I think that out of all my games, Lost Paradise is probably the only one where I actively tried to implement good combat. I love the difficult fights of Dark Souls and co, but I have no interest in implementing something like that in my games. I rather subscribe to the Zelda ethos where all enemies are canon-fodder to keep you occupied as you explore, but otherwise nothing to write home about. And I’m not big on the trend of metroidvanias to adopt this aspect of the Souls series, which I blame on both Salt & Sanctuary and Hollow Knight.
I also suspected making 3D melee combat was going to be a nightmare. And it… wasn’t? Not entirely, at least. The hardest part was to animate a passable 3-hit combo. Once I had that, the rest was relatively easy. But again, it's a very simple hack and slash. The initial jam version didn’t even have a lock-on feature. Because I didn’t spend a lot of energy on this, the enemy variety suffered a bit. Though the game isn’t long and the four archetypes covered most of it: the basic Grunt, the ranged Sentinel, the dashing Pursuer and the dangerous Heavy.
I was more interested in the bosses, mostly for narrative reasons. Though at some point I did write “could I remove the bosses?” in the margin of my notebook, and I did cut Otohime’s boss fight by making her a friendly NPC. But even for the three fights remaining, I knew I wanted to use a similar approach from Lost Paradise and have them be variations of each other. It all circles back to the “everything must be modular” mandate.
I’m happy with them. Making them using my fancy new FSM tool was quite pleasant and I think they’re a highlight of the game. Though it helps that none of them engage the player in direct combat. They’re more like the puzzle-y boss fights you can find in Zelda.
The musicbox (🎵)
Not much to say on that front. I used the same generation algorithm as Distant Paradise. The only difference is that I made preset instrumentations instead of fully random (that’s how I could make sure the tracks fit the biomes). I also disabled the countermelody as I couldn’t get it to a satisfactory level before the end of the jam. That will be a topic for later.
I realize I never really talked in those postmortems about how I make my sound effects. The truth is that, more often than not, I simply mimic the sound with my mouth and use that. Doing a dash? I know how it’s supposed to sound but I have no idea how to come up with it so I just go “wooosh!” into my headset and post-process the hell out of it in Audacity to the point where you (hopefully) can’t tell it’s just my voice. Sometimes I also do very simple foiley. The splashing sound is just me shaking a half-empty water bottle near the mic. The grappling hook is my backpack’s zipper. Etc. Hopefully it’s not too immersion-breaking!
Conclusion
As you can see, making a 3D game is a complex endeavor. They’re made of many moving parts and restrictions you need to carefully juggle. But they’re so rewarding! I can’t stress it enough how magical it was to move through this big seamless world as it took shape. Maybe it’s old news for most players, but as a creator, it’s anything but. Needless to say, I’m super proud of this project.
I had long feared making a 3D game because I imagined the result to be a ugly, janky mess. But I don’t think Dear Clockmaker is any worse than my 2D offerings. Sure, the animations are a bit awkward and there's some shadows popping here and there as occluders leave your field of vision and get culled (just like Pokémon Scarlet and Violet! And it never bothered anyone…*check notes* ah my bad, it did), but it was definitely playable and even enjoyable. The weaknesses here are my usual blind spots as a creator.
So now the question isn’t “can I do it?” but “can I improve on it?” and “should I?”
I don’t know how to explain it, but I really don’t like runtime complexity. I’ve seen computing steadily degrade in the last twenty years, to the point we can’t even take Windows for granted in the future. Indies who built their entire careers around Unity3D had a couple panic attacks recently. Will today’s games still be playable in ten years? Twenty? If Unity goes under, what will happen to those games when the next generation of hardware requires them to be updated? When Microsoft abandoned XNA, MonoGame and FNA reimplemented the entire thing and took over, but I don’t think it’s realistic to reimplement the entirety of Unity (multiple versions of it even!).
Because Dreamnoid is a long-term project, I imagine myself in twenty years, after the tech ecosystem I’ve known most of my life lost it all at the AI roulette or enshittified beyond salvation, and wondering if I can port Dear Clockmaker. I would need .NET, which is already a huge dependency with an uncertain future. Then I would need to reimplement the entire renderer with whatever succeeded to OpenGL (which, at this rate, may not even be Vulkan or WebGPU)... Rewrite all shaders… And that’s for a 1:1 port! If I wanted to add content, I would need to get all my 3D meshes available in a new DCC (which may or may not be Blender) with enough data retained that I can export it back as kits… That’s a lot of work!
This vision makes me uneasy. That’s why I’ve been working lately on better defining the “pocket epics” I’ve been making and finding ways to rationalize the tech they require and reduce the dependencies to the minimum that can be expected from a platform. But they’re simpler 2D games, with a simpler workflow.
I don’t see a clear vision for that with Dear Clockmaker. It unlocked countless possibilities for me, sure, but it feels fragile. Like there’s too many failure points. Still, I loved making it! You gotta feed the creative wolves from time to time, you know? But I think it should remain an exception.
Now, that doesn’t mean 3D games can’t possibly be rationalized. N64 and PSX emulation is working relatively smoothly these days. If I keep looking for alternate art styles and workflows, if I juggle different constraints, maybe I can find ways to make simpler but still rewarding 3D games. That would be a dream! Some creators are doing really interesting things in that space and I’m still trying to learn from them.
Until then, I’m certainly willing to make a few exceptions from time to time!
Get Dear Clockmaker
Dear Clockmaker
Explore a mysterious and dangerous clocktower to save your husband
Status | Released |
Author | Dreamnoid |
Genre | Action |
Tags | 3D, Action-Adventure, Exploration, Female Protagonist, Low-poly, Metroidvania, Singleplayer, Third Person |
Languages | English |
Accessibility | Configurable controls |
More posts
- Dear Clockmaker version 1.12 days ago
- Dear Clockmaker18 days ago
Leave a comment
Log in with itch.io to leave a comment.