After a bit of a break at the end of last month, I’ve started (slowly) on the 10th instalment of the RetroRemakes Challenge. I revisited my game list, again, and realised that I had no platformers in there, which was a bit of an oversight, especially given how popular that genre was on the Speccy. This month was supposed to be “Split Personalities”, but when I looked closer, I realised it had a lot in common with “Confuzion” from Month 1, and moreover, I envisaged some potential legal pitfalls with the use of celebrity photos, so abandoned that and decided to look into slotting a platformer into place to fill the gap.
I looked at many, dismissing the obvious ones, Manic Miner and Jet Set Willy, as they have had enough attention already. I asked my daughter to take a look at my shortlist and she definitively identified “Chuckie Egg” as the “least weird”, but hey she’s a Gen-Z so she’s not really going to ‘get’ the Speccy 😂
I’ve started on the game and spent a couple of hours tinkering with the control method in particular. While the controls are relatively simple and would be quite easy to hard-code in a normal system, in Godot it makes sense to use the 2D physics and kinematic body systems, to make these things work well. Forcing the kinematic systems to work like the original controls has proven to be a bit of a challenge, but I think I have it working well now. One of the problems I faced was the way the player transitions from running on a platform to climbing a ladder. In the end, I overcame this by using multiple tile maps. In Godot a TileMap is a specific node type that represents a grid-like array of tiles, each tile type has a visual representation and optional collision and navigation data. Another important feature of Godot’s 2D physics is the use of collision layers. Each object exists on one or more or 32 available layers, and in addition, can interact with objects on the same available set of layers by way of a mask. For example, a player might be on layer 1, a platform on layer 2, and the player can set the “mask” to include layer 2 so that when moving, it will collide and interact with the platforms. It’s a very flexible system. However, the TileMap in its entirety can only specify one combination of collision layer and mask, not per tile. So, by separating the elements into different TileMaps, I could have more control over the way it works. I moved the ladders into their own TileMap, on a different collision layer, that the main player body doesn’t interact with, so it won’t collide with the ladders causing them to block progress. I then added a secondary collision shape to the player, separate from the main physics one, that does interact with the layer that the ladders is on, but only as a detection mechanism, so it doesn’t block movement, but I can query if the player is touching a ladder, moreover, I can tweak the collision shape to make the detection as tight as I want it to be. Below is a picture of the tilemap for the map, showing the collision shape of the left half of the ladder, notice how it is not covering the entire square, only a smaller sliver in the centre of the ladder. Also below, is a picture of the player, with the extra collision shape highlighted, notice how that is narrower than the player too. This means that the system will only detect the player being on a ladder when it is quite close, and the two narrow collision shapes overlap.
With this in place, I can easily query if the player is over a ladder, and if they press the up or down key, allow them to switch to the climbing state and climb up/down, I also move the player to the centre of the ladder at the same time to make it more like the original. This is more forgiving than the original, which required you to be exactly at the centre of the ladder before you could climb, and I think it feels more natural.
You’ll also notice a couple of arrows in the player image. These are 2D ray casts, set to detect objects on specific layers. The problem these are designed to overcome is the means to leave a ladder and start running again. To support the idea of the player running along a platform that is intersected by a ladder, without falling down the gap, I introduced another TileMap containing just tiles that fill the gaps where the ladder crosses a platform, with no visual, just a collision. This means that the physics will allow the player to run safely across that gap. However, when climbing, it’s important they don’t impede the player, so when in the climbing state, the player is updated to ignore the collision layer this TileMap is on, so they can climb right on through. The ray cast will still see the tiles though, and this allows me to detect when the player is right on top of one of those gaps when climbing, and if they press the left/right control, it allows them to exit the ladder and resume running. The top arrow is used to detect the top of a ladder, to prevent the player from climbing off the top.
With all these pieces in place, I have a control system that feels good, mimicking the original where appropriate, but improving where I feel improvements were necessary to make a fun game. The next part is to import the 100 levels from the map file, I don’t plan to manually enter them, I’ll use a variation of the same technique I used for Splat, writing a Python script to analyse that image and extract data to build the level tilemaps. More on that next time.