Continuing my quest to make my very own video game.
I recently had the itch to continue with the development of my submarine simulation game for the PICO-8 fantasy console. As I said in my first article on this topic:
I’m a strong believer in the idea that tech journalists should always try to do some programming on the side to keep involved in the thing they’re writing about. It keeps you sharp and gives you more experience in the things you’re trying to understand.
So, here we go again. I’ve decided what I want the gameplay to be and I’ve got the graphics pretty much nailed down as well. Now the hard part begins: I’ve got to implement the mechanics and deal with the problems that arise in doing so. At first, let me explain what I want the game to be like.
subsim (a pico-8 submarine simulation)
You are the commander of a German submarine in WWII. Your sub is in the middle of the screen, which represents how far your sub commander can see. Your goal is to move across a vast stretch of the North Atlantic to find enemy merchant vessels and tankers and sink them with your torpedoes, hopefully without being spotted by ships or airplanes which will cause you to be hunted by enemy warships.
You have five movement controls at your disposal:
D Dives your sub
U Raises your sub
L Manoeuvres to port
R Manoeuvres to starboard
O Cycles the sub’s speed: Stop, Ahead, Full Ahead
The camera always stays centred on your sub in the middle of the screen. Your sub has three diving states: Surfaced, Periscope Depth and Submerged. When you give a dive or raise commands, your ship will take a few seconds to execute it. During this time, you can give no other diving commands but you can still manoeuvre.
X Fires a torpedo
The torpedo will slowly go in a straight line until it leaves the screen. You can only fire torpedoes when you are surfaced or at periscope depth. Additionally, at periscope depth, you view will be restricted to a more narrow area of the screen. When submerged, you only see what’s directly above your boat.
Your goal is to stay alive and sink as many merchant vessels and tankers as possible. Your score is calculated based on sunk tonnage. There are several kinds of merchants and a tankers with different tonnage. They take more or less torpedoes to sink based on tonnage; tankers are easier to destroy. Your commander gets different medals based on his total tonnage sunk. Ships spawn alone or in small convoys off screen somewhere on the map with a random course and different speeds. When hit, they will change course and try to escape.
The game will spawn spotter airplanes with a random course from time to time. If you are spotted by them – high likelihood when surfaced, small likelihood when at periscope depth, impossible when submerged – they will launch torpedoes towards your sub. Being spotted by these planes massively increases a hidden alert counter. Being surfaced with a merchant or tanker ship on screen also increases this counter. As the counter gets higher, the game will start spawning consecutive waves of different destroyers that zero in on the player’s sub and try to destroy it with depth charges or by ramming it. If the player is surfaced and collides with a destroyer, it’s game over. At periscope depth, the depth charges have a very large destructive radius. If the sub is submerged and a destroyer attacks with depth charges, the destroyer has do be pretty much right above the sub to destroy it. Additionally, being submerged makes torpedoes from spotter planes miss.
That’s the general design idea. But when I started thinking of how to actually implement it, I ran into some problems. The first problem I have to tackle is how to create the game world and have my sub interact with it. My first idea was to rotate the whole game world around my sub? I would have to rotate enemy sprites and keep track of their relative position to the player (sub) with angles and such. Because I couldn’t really find any detailed tutorials for PICO-8 on how to do this, I asked a question on the PICO-8 forums. At the time of writing, nobody has answered.
Why Rotate the Sub at All?
Then, I lay awake in bed last night and had this idea: Why even use a map when all we need to keep track of are enemy ships on an empty ocean. And how about this: We don’t even move the boat. We fake it. When the player uses the left button, we just rotate everything in the game world to the right in relation to the sub. That will make it seem like the sub is manoeuvring when we actually only keeping track of objects in relation to the sub.
I talked this idea through with my friend Clemens who actually wrote his own 2D game engine once. And he made a good point: There’s some serious math involved with that idea. Which is a problem because I’m not exactly a math-loving person. He also said that most old-school consoles of the era that PICO-8 is trying to emulate never did stuff like that because it generally looks shit if you transform low-resolution pixel sprites at arbitrary angles. He also said “keep it simple, stupid – you’ll learn more that way.” And he’s probably right there too.
A Simpler Approach
So in talking to Clemens, I came up with another idea: We use PICO-8’s built-in level map (which is well suited to top-down RPG games like Link’s Awakening) and make it infinite by wrapping it around at the edges. So when a game object reaches a border of the map, it’ll just continue on from the opposite edge. This brought a change in the layout of the main game screen with it. I had originally designed the game so that the sub is towards the bottom of the screen and we only move upwards.
As evidenced by the design idea explained at the beginning of this post, we will now have the sub in the centre of the screen. The top edge of the screen is always north on the map and the ship can rotate around and point in different directions. As the camera will always follow the sub, it will still stay in the same spot on screen as it rotates around. In this way, the screen (and camera viewpoint) will travel across the map. Which is a much more natural way of doing things on PICO-8 and should fashion me with a lot of tutorials and examples of different games that use a similar game world and camera setup.
In fact, these two example carts seem cover exactly what I need. I just need to combine this code and adapt it to my own use case:
This might also come in handy:
After that, I will just have to figure out how to spawn in ships off-screen and how to track them. Oh, and then I will have to learn how to rotate their sprites when I draw them on screen. And how to rotate the sub sprite. I haven’t decided if I want to draw several angled view sprites for every possible object or if I will rotate them by transforming the sprite. I have found some example sprite rotation code for PICO-8 that I could adapt to execute the latter idea:
We will see. I might just try that first to see how it looks. This solution just seems more elegant to me than multiple sprites for each object. If it’s at all doable in a way that I can figure out and that looks good, that is. Anyway, while I’m posting helpful links, this is how I made the animations for the torpedoes and the periscope:
And I adapted this code for a starfield to render my waves:
There’s also a hell of a lot of useful pointers in this first GitHub repo. And the second actually has a particle system. I am sure I won’t need a particle system any time soon, but it is amazing what people actually have gotten done within PICO-8’s amazingly harsh constraints.
Well. It looks like I have a lot of work ahead of me. Better get to it!