The Friday Tiding #15: Programming By Spite


This is a post I made to the Zinnia Games website: https://zinniagames.com/the-friday-tiding-15-programming-by-spite/


The Friday Tiding #15: Programming By Spite

18 Apr, 2025

zinniablog_fts15_1

I've mentioned before on this blog that I am not a good programmer. While this might sound like another drop into the endless ocean of self-deprecation all over the internet, it is actually just a literal assessment of my abilities.

I didn't become a programmer because I wanted to. I became a programmer out of spite. No one else was going to program my games for me, and if I wanted to make games I either had to learn how to do it or give up. So that is exactly what I did. My knowledge of programming is incredibly informal, mostly earned through trial and error.

Such a background makes me prone to bad coding habits and a habit of rewriting lots of code for things in games. If you are familiar with programming, you'll know that the ultimate goal of it is to avoid repeating yourself more than necessary. What I mean by that is rather than writing a piece of code 20 times over, it makes a lot more sense to just write that piece of code once and reference it 20 times.

When I made the various enemies that populate Demos 1 and 2 of Skag Malibu, I programmed them all separately from each other. I knew even then that this was not a smart idea, but my original plan was just to brute force it since I couldn't fathom a way to make a reusable system that also supported unique enemy behaviors.

But now all that coding and design work is gone. The new version of Skag Malibu is being built from the ground up. I could just brute force it again, but with what I've learned since August and starting the last iteration of the game I know enough now to try and make a reusable system.

The Enemy States

The Finite State Machine is a classic in the programming world. It's a system that lets us define "states" that an entity can be in. State machines are particularly useful for video games since we don't want every single possible thing an entity can do being accessible to them at all times.

For example: if you are falling in the air, then you can't walk until you are on the ground. Using a state machine lets us tell our enemy what to do in a situation, and make sure that it can't do anything that it shouldn't be able to do in that state.

Now Demos 1 and 2 already had a Finite State Machine in them for our enemies. however, this state machine was being rebuilt for each enemy. The plan with my new state machine is to instead make a single one that can be attached to all of our enemies. This state machine can then be given separately programmed states that define the unique behavior of each enemy. These individual states can then be reused on other enemies. So instead of programming three enemies that can walk separately each time, we program a "Walk" state and then just give it to all three of those enemies.

The Engine

So let's take it from the top. The first thing I did was make a script that contains a set of properties that are almost guaranteed to be used by all of our enemies. Things like gravity, health, the direction they are facing, and so on. This list of properties can be changed for each individual enemy, and they can be referenced by our more specific behavior scripts later on as well. This script also makes it so we can have one single block of code that handles things like damaging the enemy and damaging the player.

Next was by making the actual state machine. Now I've already been using one for the player, so I just snatched that code and changed a few things so the enemy's state machine isn't trying to find player inputs.

The next thing to do was to make some states for us to use. I started this process out by recreating the Hoppy enemy. This little guy simply moves forwards until they hit a wall, at which they turn around. The first thing to figure out was a walking state, which is what they spend most of their time in. This was easy to make, and I used some agnostic wording in the script so it's simply looking for the enemy, and not a Hoppy specifically.

smdv_10_hoppysback-ezgif

With this walk script done, any enemy that I want to walk back and forth can simply be given this script and it will allow them to do so. Next is the death script. This is by far the simplest one, as all enemies in Skag Malibu currently get knocked upwards a bit, and then fall down until they leave the screen. So all I had to do was program that in, and this script will be easy to add to every enemy that the player can damage.

Finally, something different is that I am adding a falling state to the Hoppy. In the older Demos they didn't actually have one, and I had made it so if they reached a ledge they would turn around. They'll now hop on down to their deaths instead, so I will need a state that handles their hang time.

Once again this is simple. All we want to do is make it so they fall until they hit the ground or leave the screen. With these scripts, you can see why exactly this new system is going to be so much better for the development time of Skag Malibu. In the older Demos we had to program all of this stuff separately each and every single time we made a new enemy. Now we just make one script for each state and then we can use and reuse it to our heart's content.

All of this work has only been for one enemy however. I can talk about the theoretical effectiveness of this system all day, but if we don't make more enemies how do we even know it's working?

Squad Up

Since we are already going down memory lane with these enemies I might as well go in the same order that I added them in originally.

The Bogey

Our second enemy is the stationary turret that I called a Bogey for reasons beyond my comprehension. The Bogey is a very simple enemy. If it is onscreen, it will face in the direction of the player and fire a projectile horizontally. After this projectile is fired the Bogey will wait for a bit and then fire another one. While the Bogey makes use of our universal enemy properties we set up earlier, it doesn't share any states with the Hoppy other than the dead state.

smdv_11_bogeysback-ezgif

The Mitten

Previously known as the Letter, this enemy chases the player before delivering a close range melee attack. Besides being airborne, they also fly straight through level geometry. These are simple changes we can make just by not having a falling state for them, or level collision checks.

So funny story, the Mitten also does not share any states with the Hoppy or Bogey besides death. They end up being a show of our universal properties but not much for our actual state machine.

smdv_12_mittensback-ezgif

The Vortex

The last of the enemies that appeared in Demo 1. This one floats in midair and will fire a projectile directly towards the player when they are near. Not too different from a Bogey and that means our state machine can come into play. In fact, the only change we need to make with the Vortex is changing what projectile it fires.

smdv_13_vortexback-ezgif

The State Of Things

This system has already begun showing major benefits over my previous way of programming enemies. So much coding time has been completely erased, as I can now relish in the use of reusable scripts. This system also means that whenever a bug crops up, I only have to fix it once and that fix will propagate to every single enemy that uses that section of code.

Though the work isn't done yet. While I was able to bring back all four enemies of Demo 1, Demo 2 introduced four more enemies that have even more complicated behaviors. While they'll likely take more time to add in, I am already prepared to handle them and have programmed my enemy code in a way that will facilitate their addition.

Wow this ended up being a really long blog post. Not too surprising since this code is going to be the backbone of a major part of the game. Hopefully this dive was at least somewhat interesting. Thank you for reading.

Get Skag Malibu

Leave a comment

Log in with itch.io to leave a comment.