R-ADIUS AI: A Not-A-Post-Mortem Post Mortem

Posted by (twitter: @battlecoder)
September 2nd, 2015 6:15 am

I want to start with a big thanks to every person who’ve played my entry so far. You are the best!

After each LD, I like to write about what went right and what went wrong (which is normally an extensive list of hilarious fails and the occasional random good decision), but this time I’m doing something a bit different. I’ll be focusing on something that a lot of people seem to be intrigued about: The AI for the enemy spaceship in my entry; R-ADIUS:

R-ADIUS AI: It can be a bit frustrating, I know.

R-ADIUS AI: It can be a bit frustrating, I know.

I didn’t think it was something worth writing about, but surprisingly a lot of people seem to think it is and have shown interest on a full write-up on how it works,  so I guess I’ll do exactly that, hoping that it would help someone out there… somehow…. I don’t know.

If you are one of those who wanted to know the magic behind the “clever” ship, you’ll be incredibly disappointed, though.

I know from experience that writing good AI takes a lot of time, so this was actually the thing that terrified me the most when I came up with the idea for my game.

I wanted the player to feel like he/she was playing the role of the “computer” in a classic shoot’em up, and for that to happen, the ship had to feel like it was being controlled by a half-competent human. But because this is LudumDare it needed to be something I could program in an afternoon or less, so I feared that I would end up with a stupidly boring and easy to trick ship, that would run face-first into enemy fire.

I had a lot of crazy and “smart” (air-quotes-smart) ideas, from pathfinding through heatmaps to cluster-based analysis with data extrapolation, all of them trying to deal with the ever-changing landscape of possible threats, but they were all too complex and “risky” to ensure that they would work, and definitely nothing I could implement in a reasonable amount of time.

I needed a way of simplifying the problem, so I thought that perhaps I could sort the incoming enemies by distance first, and then “deal” with them from closest to farthest. It didn’t take much from there to realized that it would actually be enough to ignore any incoming threat except for the closest one (enemy or bullet), which is a dramatic oversimplification of the problem, but it would work as long as the ship can deal with the threats fast enough.

(You can see this behavior in the GIF above)

I also limited the AI actions to a set  that would mimic “real controls”. This is all the AI can do in the game:

  • Move in any of the 4 directions (Left, Right (boost), Up, Down)
  • Pew Pew!
  • Do nothing.

The ship movement is acceleration-based (as it would be for a human-controlled ship) so when it decides to move, the game will act as if the AI moved the imaginary arcade stick in the desired direction, setting the ship’s acceleration accordingly. This means the ship doesn’t have precise frame-accurate control over its own position, and it doesn’t attempt to predict the next few frames based on the information it has. Depending on the current speed vector, it may take quite a number of frames to change course, and the AI doesn’t take this into account.

It basically controls the stick and hopes that it’ll be able to move in time! (like a normal person would, I guess).

There’s a cooldown for the attack, so even if the ship attempts to metaphorically “mash” the imaginary attack button, a shot won’t succeed if not enough time has passed since the last bullet was fired.

Every frame, the ship asks for a reference to the closest threat:

  • If there is none, it will begin to move to the Default tactical position™, which is vertically centered, with some room behind for retreat maneuvers.  This is a very nice position to dodge and neutralize most of the incoming threats.
  • If there’s an enemy (not a bullet) far, yet still within a certain distance, it will try to (vertically) align itself with it, and shoot when it enters its “line of sight” (±4 pixels in the Y axis)
  • If the threat is closer (enemy or bullet), past a “comfort” distance threshold, it will attempt to dodge it instead, trying to move along the axis where it has more room for dodging first (that normally means X). If it can’t (limits of the screen reached, for instance) it will choose the other axis instead.  It will also attempt to take down the threat (again, if it’s not a bullet) every time it falls within its “line of sight”.

And that’s basically it. I first coded the ship as a player-controlled unit to test if the movement speed/accel felt good and gave enough “reaction time”, so for the first hour or so, the ship was controlled by me. Then I automated the movement with what’s essentially the 3-cases-IF outlined above, which didn’t take much time to code.

I implemented the dodging first, tweaking the reaction distance and enemy speeds so it would be challenging yet beatable. Then added the shooting, adjusting the different “parameters” some more. I was lucky that it was a really a fast and mostly-painless process, that still gave a decent-enough AI.


The ship literally didn't see that coming.

The ship literally didn’t see that coming.

In fact, this resulted in a surprisingly competent AI (for a jam game), that can still be tricked with good timing. You can see in the previous GIF how the ship is too busy dodging the bullet from the “Discus” to avoid a collision with the incoming “Beet”.

The boss battle was also designed in a way that allows the player to exploit the AI, which is something you can pretty much do with the 2 attacks provided: A directed bullet, and a straight-line attack.

Overwhelming the AI at the boss battle is probably the easiest way to win.

Overwhelming the AI at the boss battle is probably the easiest way to win.

I would still like to add a Post-Mortem of sorts, as this is the first “successful” solo jam I do.


What went well

  • I managed to participate. I wasn’t sure I was going to make it, as I had 90% of my Saturday already taken and my Sunday was 50% a void of uncertainty.
  • I used tools I feel comfortable with; MonkeyX and my own engine for the code, Gimp and GraphicsGale for the Art, SFXR and Audacity for SFXs, and LMMS for music.
  • Speaking of music, for the first time EVER I was able to add audio in a reasonable time (2-3 hours). I’m really slow at making music and SFXs, but I made enough compromises and used enough shortcuts (like abusing arpeggios) to make it all in time, and even when the result is not worth of any award, still improves the game experience.
  • Against all odds, I kept myself pretty optimistic and relatively relaxed all the time, despite the stress and lack of a clear schedule for my weekend.
  • I was able to pull off a really-low res game, which was a personal goal of mine (although cheating a bit; the upgrade screen is more hi-res than the game itself in order to render the smaller texts needed by the descriptions).

What went wrong

  • Some things could be improved so there’s a number of “known issues”. To name a few: I didn’t double-check where the SFXs are played so you can hear the enemies dying when they go out of the screen. The UI could also be improved so the attack names and costs don’t get in the way of the action.
  • Didn’t have time to add more/better animations for explosions and deaths. I would also have loved to add more enemies, upgrades or different attacks for the ship, like a real shmup.
  • Despite being “good enough” the AI still makes stupid decisions and sometimes gets stuck in the Boss stage, which the player can totally exploit to its advantage.
  • I wrongly assumed that most people would just stop playing after being defeated enough times or after defeating the ship, so “adding a victory screen” was last in my priority queue, and didn’t make it to the Jam version. I thought players would just either leave the game at that point, or just keep playing for no more than a couple of rounds for the sheer pleasure of messing with the AI, so it wasn’t really required, and I convinced myself that it was in fact better that way. It turns out some of them kept playing enough to max out all the upgrades, which was a problem, as the game had nothing else to offer beyond that point, so I kinda had to add a victory screen to a post-jam version. This was a “nice” problem to have though, mainly because it meant they enjoyed the game far more than I had anticipated.
  • This could have been a Compo entry had my Saturday been free of appointments and stuff to do :(


I had fun as usual, and I really hope all of you had fun working on your games too.

Although I normally play LD games from the “Rate Games” page whenever I can, I constantly check comments on my entry to try the games of those who were kind enough to play mine, so if you play R-ADIUS please leave a comment when you rate it!



Tags: , , , , ,

2 Responses to “R-ADIUS AI: A Not-A-Post-Mortem Post Mortem”

  1. I think a rough in-game description of these rules really would have improved my enjoyment of the game. Not knowing how the ship behaved made scoring hits feel more like a gamble than a test of skill since I didn’t really know any tricks for overwhelming the AI.
    A really interesting system, though. I’m glad I read through this.

    • MrTwister says:

      I’m sure that knowing how the AI “thinks” would allow people to defeat the ship more easily. In fact, it’s possible to kill the ship the first round with nothing but perfectly-timed attacks, but the whole point of the “game” is not really the 1-on-1 combat between your units and the ship, but your overall strategy (i.e: How do you plan to defeat the ship? investing all your resources on your minions and swarming the ship with a bunch of little units early on? saving all your resources for the boss battle and reducing the costs of the Boss attacks? a mixed approach?).

      As the entry description says, it’s mostly a planning/resource-management game, although you can try to outsmart the AI with every deployed unit or attack (and this is especially the case if your strategy is defeating the ship during the boss fight instead of early with minions) but it’s part of what I wanted the player to play with.

      Having said that, I agree that it would have made the game all the more enjoyable if there was more control over how your units interact with the ship. Even per-unit stats-management (i.e: improve their resistance, or their speed, or switch the way they move to more unpredictable patterns) would have given the player more control over the outcome of each encounter. There’s a lot that can be done in that regard without changing the game concept at all.

      Anyway, I’m glad you enjoyed reading this post, and I’m really sorry if the game caused you more frustration than enjoyment!

Leave a Reply

You must be logged in to post a comment.

[cache: storing page]