0x01 - Let there be things

Making a game is hard. The sheer amount of stuff that needs to be done is insane, specially when doing it solo. I already got some stuff done, but my main goal for this beginning is to lay strong foundations for the project. The two systems I’m mainly working on are the Map system and the Player’s core mechanics. Although the first lines of code I wrote were to make a CharacterBody2D move and jump, I’ll start from the Map system because it’s where the idea of a game came to be (and my memory is still fresh from the last time I was working on it).

The Map System

There is one single thing in a Metroidvania that I need up and running the most in here: The minimap. It’s a must-have piece of user experience for the genre, as it provides the player with the notion of locality in a huge interconnected world. And I didn’t know shit about how to make one. As it turns out, the whole map system needs to work together for it to happen. The map system can be divided into 3 sections:

1. The Importers;
2. The Runtime;
3. The Minimap per se.

I’m sticking with Tiled map editor for the level design because it’s free and open-source, so I need a way to stuff the Tilemaps into Godot and build my scenes from that.

Starting with the importers: I tried some plug’n’play solutions, but none could work the way I wanted, so I decided to write one myself. Godot has an API for Importer Plugins, and they allow the editor to automatically trigger a reimport whenever the source asset changes. This means I can save changes directly to a Tiled project and the plugin will take care of reading the XML from the .tmx map file and rebuilding the scene tree. Here’s an overview of how it looks like:

Map system diagram Yes, I still use paper.

The plugin let the .tmx and tsx files live as first-class citizens inside the editor, acting as proxies to a runtime representation, which can be a scene. So, you just drag and drop the file into the scene to instantiate it. By the way, tilesets in Godot work in some really odd ways, some of which are quite limiting. For example, I had to fully write my own tile animation player as a workaround to the engine’s half-assed tile animations. Other times I had to do some very funky stuff on code to make it work. It took some time to get all things done right, but it was worth it.

The Minimap

As I have, now, full control over the importing phase of the maps, I took advantage of it to process the minimap data by reading the tiles from each map’s collision layer and combining it with the map’s world positional data, procedurally generating the minimap in the process.

When run, the HUD loads the minimap data into a stateful model, then used to draw the minimap on screen in real-time. The player’s position is globally tracked at all times so that it can “visit” the cells and explore the map. It’s all configurable, with colors, style and drip. I definitely got the basics right, thanks to some already existing plugins. Anyways, I still need to fine-tune some parts to control better how intel is given to the player, and add map indicators for important stuff.

The way the minimap works internally is quite ingenious, but I can speak about it in another time. For now, here’s the first screenshot of the game running:

First screenshot

0x00 - A Dream Begins

Honestly, I’ve already been developing this project for quite some time, now. I never took the process of documenting the progress of my projects seriously, though. More often than not, ideas just died inside my head, never to see any sunlight. In the never-ending cycle of overthinking, nothing was ever good enough. I hope this time it's different.

The last few years have not been very kind. Not only to me, but the whole world seems to be spiraling downwards in a weird trend of chaos and numbness. At my age, I’m starting to feel haunted by the ghosts of what could have been, looking back only to see the remnants of a long trail of abandoned project, hopes, and dreams. This could possibly be my last try – you never know – at standing before a life of grayness, empty, devoid of purpose, running in circles like a dog forever chasing after its own tail.

Now, the game industry... Well, it seems pretty fucked up to me: Patent scandals, AI slop, runtime fees, increasing inflation of console and game prices, and I'm not even touching on any of the corporative problems of tech companies (hello, layoffs). Corporate greed is just squeezing every last cent from the industry. I remember when Unity once was who democratized the access to the best game making tools available at the time, only to fumble up pretty hard and lose the trust of a big part of the community. Myself included.

I became a programmer because I wanted to make games. I went to university because I wanted to make games. I graduated in Design because I wanted to make games. Heck, even my first paying job was to program a game. But things rarely work out as we want, and my skills were better compensated elsewhere. I had to give up my dreams, gradually.

Seeing all of this happening at the same time was like watching my world come crumbling down slowly, piece by piece. This is not the future I envisioned when younger, this is not a world worth fightning for anymore. For what? So that half a dozen men can watch dem numbers go up? Things need to change. I want to make things differently. I want to rebuild my world back, now with my own hands. I want to feel the joy of playing videogames again.

Not guilt. Not anguish. Joy. I want to make a game that makes me feel the same joy I had when playing Metroid. I always wanted to make a Metroid. Not a Metroidvania, I want to make a Metroid. I want to make MY Metroid. And that's what I'm gonna do. I want to dare. And I want to challenge the status quo, starting by the tools of the trade: As much as I can, I'll only use free and open-source software.

Enter Godot. And was I waiting for it. It's basically Free Real Estate™. And I'm in. Oddly enough, the language I'm mostly well-versed with is Swift. Oh, look! Swift is now natively interoperable with C++, and Godot now has Swift bindings – built by the community – to the underlying engine. How convenient!

Inspired by some Godot metroidvania plugins, and, with this unorthodox choice of a stack, I decided to tinker with the possibilities: I grabbed some open-source sprites for the main character, extended a CharacterBody2D node to make it move to my input, and made a sketch for the main music theme. In little time I made the character jump, grab walls, and shoot some stuff. Well, looks like I'm up to something!

To be honest, I gave up a couple times to this project. It was fun but I didn't believe that I could do it. It's way too much work. However, each time I picked it to play with, I added more stuff. And more. By the time I'm writing this, I've already built an importer plugin to convert Tiled's .tmx maps into Godot scenes, a minimap system for the HUD, 3 types of enemy AI, and all core movement mechanics, with, like, around seven different weapons to play with.

I replicated the beam weapons, playing with collision masks to imitate the wave and plasma beams, I did wall jumps, missiles, nasty water physics, the speed booster, and even a morph ball rip-off that morphs into a cube. But it really snapped the moment I pulled off the shinespark mechanic (eventually, it ended up being way easier than I thought). THAT was something.

But I want to go beyond. I programmed some new abilities, like water-walking and a functional hookshot. I want the movement game to be solid, to make a game built for speedrunning, by learning from the best titles and picking a little from each one to make something unique.

This post is getting dense already, so I think I'll take my cue to leave. I'll try to be more objective next time. Thing is that I have a working prototype up and running. And, for the first time, I have a clear direction to follow. Maybe, in the end, it turns out to be Just Another Metroidvania.

Tomorrow I have things to do.