Firstly, hello everyone! I used to do loads of journal posts during the jam, but as I've grown older and time has become shorter in supply, I find making time for it more and more difficult. Not least because where once I used GameMaker to make 2D games, making gifs of 3D UE5 gameplay is much more difficult to fit in the 4MB limit we still have :sweat_smile: I've come a long way since LD27, and this was my 22nd LD entry.
I'm sometimes asked how I'm able to fit the amount of content I do in my games, and I thought it might be interesting for people to hear a little about the development of my LD59 entry, with a highlight on the tech design and some other neat little things to point out along the way. For context, I'm also a professional gameplay programmer as my day job, and whilst applying my regular workflow in a jam would be a fool's errand, it has absolutely allowed me to adapt my way of working during a jam. Particularl, to create modular systems that let the content-creation part of game-dev flow super fast once they're up and running - something that works great in a jam. More on that later.

Ideation
I was only able to start late on Saturday night, as I was at the Magic: The Gathering Strixhaven prerelease! Getting home and seeing the theme, I did what I usually do here: create an empty document and brainstorm every word and concept I can think of relating to the theme. Usually, I take a walk after and think on it, but being out all day, I ruminated in my lounge instead, whereupon my clock chimed. I grew up around an old mantle clock which had the traditional Westminster chime, and so I made sure to have one on my wall when I left home, as I'm very fond of the melody. I immediately latched onto the idea of being inside a giant clock tower, where you had to ring the bells on the hour manually. This is the clock that inspired the whole thing:

Originally, the plan was to do a "Papers, Please" style game where you had to watch the clock and ring the bells on the hour, with more weird rules and stipulations added as you progressed. Long-story-short, however, I couldn't think of a way to make the game loop feel fun. That's usually the part I'm prioritising over everything: feasibility to make the gameplay loop and game-feel good. It's at this point I decided to be a bit daring, retaining the bell ringing idea, but instead using those bells to ring out commands. I have a bad habit of always wanting to put combat in my games, and decided I could try and make a game about being in some kind of mech fighting airships with a very simple battle system, but inputting commands was to be done by ringing out short melodies.
My Usual Plan and First Steps
This is hardly unique, but the goal is usually to get the purest MVP gameplay loop working on the first day, content on the second, and polish on the third. With only two days, I had to be very stringent and knew some polish would fall by the wayside, especially when I realised I wanted animated portraits to give character to the enemies you were fighting. I am a horrible artist! With that said, the game's implementation was effectively split into 3 sections:
- Interactable objects and the bell sequence-based input system
- The second-to-second airship combat with an enemy AI, with both player and enemy's basic toolkit as well as health and death
- the overarching progression "encounter" system that would handle the enemy's state, keeping the fight itself an encapsulated experience that could be started, finished, and swapped out
That third one was going to be crucial. Once upon a time when I was a teen, I probably would have hard-coded everything to make it a fixed series of fights barely aware of any context, but I knew going in that making this a more sophisticated system was going to be imperative to make it easy to create lots of fights. More on that later. First, on Saturday night, I began with the bell input system!
End of day one: bell sequence commands:
Thankfully, implementation of the actual bell ringing and sequencing system was very easy and was complete before the end of the night. Essentially, ringing the bell adds a character to a string that gets built, and then pressing the "execute command" button parses the string. If it's a valid command, it plays back the sequence for you and then executes the command. By this point, I'd decided on two more things: firstly, that you were inside a giant metal whale, that would sing the command back to you with a brassy synth. Second, that I would use the same notes as is used in my clock: C, F, G, and A. With each command being assigned within an enum, I was able to simply map a string of notes to each one:

Whilst I normally don't love string-matching, this was actually very effective for the jam and also meant I didn't need to pre-record the sequences being played back, I just give it the sound of each note and have it play them back dynamically. This meant I could adjust the difficulty of the game on the fly by the melodies assigned here - one of many levers I'd have, even if I wouldn't have time to adjust them all! By the end of the night I had a very ugly but working bell sequence command system, with sound! You'll have to trust me on that last bit. Audio is 100% mandatory and should never be ignored! :wink:

The Ships and player's combat system
There's actually not a whole lot to say about the player's combat system; the actual implementation is super basic. Projectiles, shields, and healing all work how you'd expect, and the bell sequencer just calls the appropriate function in code. They fire at the enemy ship, which is connected to the enemy ship's manager system. That's a much more complex beast I'll talk about plenty in a moment, but a fun thing I implemented early when making the enemy ship models is their "hovering" animation. A few years ago I spent a great deal of time researching 3D sniper scope implementations, and as part of that I made a few notes on how to implement a simple "breathing" effect for a player's scope to sway up and down and pseudo-randomly side-to-side. A visualisation is below. Using those notes, I applied the same breathing effect to the ships to achieve their hover. It only took a few minutes, and I think it's a million times better than having them simply be static:

The encounter system, enemy AI, and modular gameplay system design
This is kind of where I'm the most proud of the game, and it's split into two sections: the overarching encounter management, and the enemy AI itself. Before getting into anything deeper, I'll quickly talk about how I set up the AI to behave:
Enemy AI works mostly on a series of timers and weights. It's not a million miles away from a proper utility-theory-based approach, but I didn't have time to make the "utility" very smart. An enemy has a series of actions it can take, and a timer dictating how often it can take an action. When the timer is triggered, it chooses an action pseudo-randomly. Each action is given a weighting so it will be more or less likely to be chosen. Each action also has a cooldown timer, so we don't get a ship just constantly doing the same thing. In addition, to make them feel alive and less machine-like, they can react to the player firing any kind of weapon. When a player fires, the enemy AI has a pre-determined percentage chance to react, an action determining precisely how they can react, and a cooldown timer so they're not constantly avoiding your attacks! That would be lame. In jams, I find enums are so helpful for this sort of thing. You can see how the basics of the AI and combat system is sort of built on enums here:

Now to explain the part that ended up being the reason I was able to complete this jam. In planning my systems, I do my best to strike a balance between hard-coding and modularity. At the cost of some bespoke flexibility (and the time investment to make it possible), making gameplay systems modular in the right way means actually making new instances of the content within that system becomes suuuper easy. What do I mean? Well, in this instance, I built out an "encounter" system that tracks whether or not we're in a fight. When we enter a fight, we need to know what the fight is. And so, using the systems I described above, I implemented a data asset system that holds the enemy's "preset" - a single asset containing all the information you need for that enemy. Rather than containing it in any kind of fight management system, the data is kept in a separate asset, and all the relevant information is loaded into the encounter.
This data asset also has a slot for the actor containing the enemy ship actor itself, which has some space for bespoke logic inside. This is how I was able to make certain ships fire bigger different amounts, have different speeds, or shoot bigger cannonballs. Knowing where to make things modular and where to make things hard-coded and bespoke will help you tonnes in a jam! You can see an example of the asset here. As you can see, I can make enemies easier and harder by tinkering with these numbers, and - assuming I have the art and audio assets, I can make an entirely new boss in a matter of minutes!

And with all the "enemy preset" information entirely separated from the encounter system, and the encounter system being able to handle starting a fight, finishing it, and picking the next one, all I had to do was make a list for it to tick through, where reaching the end let you win! This also made it so much easier to re-order the fights for the tiny bit of balancing I was able to do.

Once I had this system set up and working, I got to do the fun part of making a bunch of ship models, writing/recording the dialogue, and simply assigning the numbers and actions. And drawing the portraits, of course. Once the art and audio assets were done, each ship's basic implementation only took about 10 minutes to set up!
Bonus bit: audio and learning something new
Here was something else I found worth mentioning. Never does a jam go by where I don't end up doing something for the first time and learning something new. This was the first time I had to write scripts for other people, and it was great fun, but a surprising amount of time and work too. I asked my friends on the day if they wanted to voice a character, giving them very little context beyond what was in the doc. It was great fun.
Once I had the recordings, though, I realised I had a serious dilemma. They were of varying audio quality, which I didn't think would be a problem as I had always intended to filter it through a radio effect. Once upon a time I'd have done the labour-intensive thing of putting each individual line through the multi-step process of creating that effect from scratch in audacity. I 100% didn't have time to do that, but these days I had a better way: create the effect chain in FL Studio, import a voiceline, then export it. Job done. Unfortunately, that still meant doing that process for all 91!! lines of enemy dialogue. This was when I took a chance, did some research, and decided to try finally using one area of the engine I had barely touched: metasound effect chains. I was aware of how to use metasound itself, but never had I created an effect chain. Thankfully, with the help of some guides I found online, I created precisely what I wanted, a chain with a low pass, high pass, and some distortion. With some more googling and experimentation, I figured out how to hook this up to the dialogue system, and suddenly I had a beautifully low quality, fuzzy radio effect filtering my dialogue at runtime!! This meant I could just import my audio as-is into the engine and let it do all the heavy lifting for me. A big win that saved me literally hours of work!

I have to give a quick shout-out to my friends who did the voiceovers for 4 of the 5 captains. They endured my short-notice demands and did an amazing job. Even though the gameplay's quality is debatable, you guys have universally praised them too and it's well deserved! :heart:
What didn't go well
It wouldn't be a Ludum Dare post-mortem without a look into what didn't work, and for me there are three standouts. The biggest one, and the most universal complaint, is actually the interaction medium. The ship itself was big and I wanted to convey a sense of scale. Indeed, at first, I neglected to mention that ringing the bells was going to cost some currency. If you've played the game and wondered why the back half of the ship is useless, in the place of the furniture was going to be a machine to charge up batteries, but I pivoted early and killed that entire part of the game. Despite this, running around clicking the bells can still be tedious, as can the lack of vision on the enemy. I wish I'd made the cockpit window much bigger, and put the bells closer together. I actually think this would be pretty fun in VR then.
Not everyone has the same musical memory, either. For some people, when you've heard the tunes enough times, you can associate the melody with the command you need and you no longer need to look back to the reference sheet. However, for those with no musical experience, this association doesn't always come naturally and so it's understandably a much more frustrating experience.
That also was exacerbated by the balancing. It's not a super difficult game, aside from the final boss, but there's a midpoint skill check, and I didn't have enough time to teach the player about baiting out reactions or how to use the shieldpiercer. The game was also never meant to let you heal, but I decided to add a difficult, long-winded sequence that heals you for a small amount - right at the last minute. In hindsight, I regret adding this in the way I did, I should either have made it heal lots, make the sequence short for a tiny heal, or removed it completely. A long sequence and small heal incentivised a very tedious gameplay pattern in low-health scenarios of escaping the enemy whilst spamming this melody over and over each time the player took too much damage. On the upside, did you notice that it's the little funeral bugle melody? :laughing: And did you spot the Westminster chime in a different command?
I also hate drawing! Whilst I'm really proud of my ship models (before LD57 I didn't know how to 3D model at all!) and enjoy my crude 3D modelling, I am really bad at 2D art and haven't needed to draw anything for a long time. I really wish I had a 2D artist to draw the portraits for me, and that goes double for the opening animatic thing. That was drawn in a real hurry at the end after work on Monday, and I really dislike how lame they look. I very much wish to work with others again for LD60! As it was, this could have been submitted to the compo if I'd spent Sat and Sun on it, instead of 1/3 of Saturday, Sunday, and half of Monday! Alas.
Conclusion
In the end, for all its flaws I'm really happy with how the game turned out. For a solo jam made in an extra-tight time crunch, I think the game-feel and content is there. I love how I managed the audio design, and I think this is the first time during a solo jam I've managed to make a proper, complete narrative experience. Sorry this was such a huge write-up, but thanks for reading. I hope you found it at all helpful! If you have any questions or thoughts, feel free to reach out to me any time.

If you haven't played it yet, feel free to check out For Boom The Bell Tolls here. Did I mention he's stolen your cat? :cryingcatface: