Tin Mining - Ludum Dare 48 post-mortem

4 min read (968 words)
Projects Game dev Ludum Dare

In April 2021, I participated in my first game jam, Ludum Dare 48. Ludum Dare is a popular online game jam; this event received over 3800 submissions. The theme was “Deeper and Deeper,” and I created a game where you manage a tin mine.

The year is 1790, and the Cornish tin industry is booming. You are a businessperson who has just secured investment to build a mine. The area is known to be rich in tin, which is in high demand.

Rather than controlling your workers directly, you drag out plans for tiles to be mined and built. The workers will mine tunnels and build where ordered. They will carry mined resources to the surface to be sold.

Gif of the Tin Mining game.
Gif of the Tin Mining game.


I started this a day late and had to work on Monday, so I was only able to implement the bare minimum viable gameplay. I had planned to add hazards, buildings to prevent these hazards, and a tech tree. For example, gas explosions, toxic gas, and flooding were huge problems in mining.

The map is procedurally-generated, using a combination of multiple simplex noises. The ores are randomly placed in veins, with the likelihood based on depth.

I made all the art myself, using GIMP and the Endesga 32 color palette. I choose to make the art super low resolution - 8x8 pixels - to make the art easier to make, and hopefully hide my lack of artistic skills.

Mining deeper
Mining deeper

I created the game using TypeScript and Phaser 3. Phaser 3 was an absolute pain to use. It was poorly documented, and I spent most of the time fighting against the API. One of the main things I’ve learned from doing this game is that I never want to use Phaser 3 again.

Game AI

I choose to use behaviour trees to implement the worker AI. Behaviour trees make it easier to implement extendable NPC behaviour, which will be useful when working on more complex behaviour in the post-jam version.

When a worker isn’t currently working on a task, it periodically asks the WorkManager for an available task. The WorkManager allocates tasks based on distance and a heuristic weighting of the task. For example, moving dropped items to the stockpile is weighted higher than mining or building, to avoid items building up and clogging the walkways.

Workers shouldn’t get stuck on work that isn’t possible, such as trying to mine tiles that are not yet exposed. The way I implemented this was a bit hacky: workers have “work failure lockouts.” If a worker attempts work and fails, then that worker won’t attempt that piece of work again for 10 seconds. The work manager will allocate tasks without checking their accessibility, and the worker is responsible for triggering a lockout if the work isn’t reachable.

There were many bugs in the AI system, some of which were only found after submission. Luckily, Ludum Dare allows releasing bug fixes after the deadline, so I was able to patch most of the issues. The remaining issues just couldn’t be fixed due to architectural issues, or performance issues; the pathfinder was pretty naive and slow.


The main reason I entered a game jam is that I wanted to finish a game, at least to the minimum viable gameplay. It forces you to focus on making the game, rather than making the code perfect, which is something I’ve not been the best at in the past. This project certainly achieved these goals. Whilst I didn’t implement all the features I wanted, I still finished it sufficiently for a small game.

I decided to learn a new framework for making games for the next game jam. I chose to learn the Godot Engine, and have since wrote several games in it, including a post-jam version of Tin Miner and an entry for Ludum Dare 49 - which I’ll write about at some point.

I look forward to working on the post-jam game in the future. I think this idea may be a good game to work towards publishing on Steam, due to the smaller scope compared to some of the other games I’ve made.

Post-jam version

As mentioned, Phaser 3 was an absolute pain to use. Therefore, I decided to rewrite the game using the Godot Engine. This was a pleasant experience, as Godot’s API is very nice to use.

A post-jam version of the game, written using Godot.
A post-jam version of the game, written using Godot.

It took a bit longer to make, as I focused more on doing things correctly. Whilst this was mostly differences in maintainability, I also snuck in some usability improvements:

Post-jam user improvements
Post-jam user improvements

The pathfinder in the LD version reads the tiles directly, which is slow as there needs to be a lot of navigation logic. The new Godot version stores a navigation graph to represent possible routes, which increases performance by a large factor.

One nice thing about the new graph-based pathfinder is that it’s quick to check whether a tile is on the network. This acts as a nice optimization for checking whether a tile can be accessed to perform work.

Another difference is the new version contains better debug tools. For example, a debug menu to edit the world, navigation graph debugging, and graphs.

Post-jam navigation mesh and debug graphs. Hovering over a tile with a job highlights the allocated NPC with a circle.
Post-jam navigation mesh and debug graphs. Hovering over a tile with a job highlights the allocated NPC with a circle.

Play the game

You can play the Ludum Dare version online. The post-jam version is currently in development and will be made available when ready.