Hello readers! Can you believe it’s nearly the end of February? Even with the extra day, we’re about a week away from March. Which would mean that we’ve been back in Darwin for 6 months already! Time flies when you’re having fun and/or trying to start your own indie game development company.
And having fun we are! Louise is continuing her animation journey using Spine2D; after seeing what it was capable of doing for games such as Cult of the Lamb and deciding on a non-pixel art style for our first project, it was a no-brainer. While Godot can technically do all that Spine2D does within the editor, that system is a bit of a jack-of-all-trades solution that isn’t particularly user friendly. The pricing tiers of Spine2D are a touch aggravating; it doesn’t offer mesh deformation or inverse kinematics at the ‘essential’ tier which is still ~$AUD100. But at least it isn’t a subscription!
While Louise works on becoming an animation expert, I’ve been diving into the world of procedural generation (sometimes known as ‘procgen’). Procedural generation isn’t something I have looked into at all previously which, looking back, is a little strange given my history with game jams. I’ve seen in the past that generating a bunch of levels can be a great way of extending a gameplay idea during the limited time of a game jam. I guess in my mind I’d always considered it too complicated to implement. But in the context of an indie studio consisting of two people, I feel like I need to explore all of the tools available to us that might help do some of the heavy lifting of producing content. And hey, if it’s good enough for almost every roguelike ever, it’s good enough for us!
After two weeks of a self-led boot camp I can confirm that it is pretty complicated to start with, but it’s very rewarding when you see things come together. For my implementation in Godot 4, I used a combination of GDQuest’s excellent procedural generation examples repository, and an explanatory blog post from fellow indie developer A Bit Awake. Using those resources, it was fairly straightforward to get a basic top-down generation of caves and tunnels going. Which, with my penchant for brightly-coloured squares as placeholder art on full display, looked like this:
There you can see the orange cavern spaces, blue impenetrable walls, and purple destructible tunnels. Which is great! But what if we wanted players to not necessarily know which walls were destructible and which weren’t? We would need to have some way of camouflaging the tiles so that they appeared to be indestructible until otherwise revealed by some visual cue, or the player diving headfirst into them.
Now, in the version above it’d be easy: change the purple tile sprite to a blue tile sprite. Done! But there’s two things to consider for building towards a future version:
- What’s not obvious in that clip is that I am instantiating objects at each identified location for a tunnel cell. Which isn’t exactly what one might call performant. So we need some method of having cells that have collisions without the overhead of creating hundreds, or even thousands, of nodes at runtime.
- Once you move past squares and into actual sprite art, it becomes clear that a method of logically determining what sprite to show based on the geography of the sprites around it is needed.
Enter: Tile maps. Tile maps in general aren’t new: they were first used in 1979 in Namco’s Galaxian arcade game. Within Godot, they offer the ability to generate tiles for the player to explore that contain information such as collision and physics properties without needing to create a node for every single position in the level. And most importantly for us, they can utilise something normally called ‘auto-tiling’ but now known as ‘terrain’ in the later versions of Godot. A terrain tells the tile map how each of the sprites within its tile set are connected. Take for example this scaled-down version of the excellent (and available for free if you need it!) mossy cavern tile set:
The pink highlights are telling that terrain where it will connect and how it will appear based on how the geometry around it is configured. Are the tiles in a straight line horizontally? Then they’ll connect with end pieces at either end. Are they in a square? Four corner pieces please! You can see auto-tiling terrain in action below:
In this example I’m drawing directly in the Godot editor using the tilemap, but what if you could also use terrains to connect tiles that have been placed algorithmically? I think you can see what I’m getting at. First we use the procedural generation algorithm to place tiles down across the map, then we apply the terrain setup to tell them how to connect to each other et voila! We should have a procedurally-generated level where the sprites all join up nicely. Which we do indeed get. But just in case you thought it’d be that easy, there’s a wrinkle.
Using a system means that you have to embrace all the foibles of said system. And one of the foibles of tile maps within Godot is that they aren’t really able to assign properties to individual cells on the tile map. You can assign properties to the tiles that are used on multiple cells – one level higher in the hierarchy – but not to instances of those tiles. This means that if we wanted to mark a cell in the tile map as being destructible (which we very much want to be able to do) we have to include a little workaround. Instead of trying to force that information into the tile map, we instead create a dictionary of the cell positions that have been created, and assign various properties to that dictionary. I’m someone who needs metaphors to be able to understand things long-term, so I like to think of it as a glass sheet that goes on top of the tile map, on which I’m writing down the properties of each cell underneath it.
If we do that, and add a couple of little instructions about when to break a wall tile from the player’s perspective, we get something that looks pretty close to what I was envisioning from the start:
The end product: procedurally-generated levels with destructible tiles that automatically adjust their appearance to match the new level geometry. Obviously there’s still a long way to go: producing our own tile sheets, accounting for level height, adjusting the level generation parameters, and so on and so forth. But it’s pretty neat for two weeks’ work! gotta love Godot and its wonderful community for quick prototyping and implementation.
I’ve got a particularly long shift ahead of me (twenty-one 14-hour days in a row 😫) so I’ll likely not update this for a month or so. But I’m really excited about how this project is moving along. I can’t wait to be able to get some of Lou’s art in-game and start seeing how it will really look long-term. Until next time!
phill.