Months ago, when I convinced my begrudging roommate to playtest Orbitroids for the first time, I received some advice that I was at first reluctant to deal with. After ten minutes of playing the game, he told me he was bored of “just shooting rocks”. It was scary to hear this back then, because I thought his criticism was a reflection of my core gameplay mechanics which I had gone to great lengths to refine. Nevertheless, his feedback was valid, and as more playtesters started voicing similar concerns I realized that the mechanics themselves weren’t the culprit. A lot of people did find the game highly enjoyable to play but still felt like it was a grind. I realized that this was because the act of shooting asteroids was not living up to the full potential of the gameplay mechanics. Not by a long shot.
So what specifically needed to change? Obviously, asteroids can only be so hard to shoot if they don’t dodge or fight back. So clearly the best solution would be to introduce an interactive element to the game – either multiplayer combat or A.I. I will leave multiplayer for another blog post, suffice it to say that it is not easy to implement and incredibly risky for a game that isn’t guaranteed a large player base. This brings us to A.I.
Unfortunately, in a game like Orbitroids creating enemies is far from simple. To demonstrate, imagine the simplest video game enemy that you could engage with in combat. For the sake of irony lets call him Hal. Hal sits in one place until he sees you, and then he shoots in your direction until either you or he is dead. There are so many interesting ways Hal could be used in a standard top-down shooter. He could block a path. He could hide behind a wall in ambush. He and a dozen other Hals could form a wall of defense. In most games, Hal is an extremely useful asset in level design.
However, in his current state, Hal is next to useless in Orbitroids. Here’s why:
- Sitting in one place means gravity will pull you into a planet. Hal will only live for a few seconds, unless he spawns into a stable orbit.
- If Hal is in a stable orbit, there is a very high chance he will run into other objects in orbit. If there is even a light scattering of debris across Hal’s path, you would just need to wait until Hal inevitably runs into something.
- If Hal aims at you and shoots, chances are that gravity will cause his bullet to miss. Also, if recoil applies to Hal’s gun (as it does to yours), Hal will quickly find himself in an unstable orbit and die.
All in all, Hal is much more likely to kill himself than to kill you. Perhaps throwing ten Hals into the game every few seconds to fire off a few shots would pose something of a challenge (and turn the level into some sort of Hal blender) but killing these enemies wouldn’t give you the same satisfaction as hunting down and outsmarting a worthy opponent. In effect, the challenge wouldn’t be much different than simply adding more asteroids to the level.
Let’s make Hal smarter. If Hal started in a stable orbit, was able to dodge incoming objects, and could aim towards where you were going instead of- OK. STOP. Stop right there. Gravity in this game creates complications, and we are already way ahead of ourselves. Lets take this piece by piece. Starting in a stable orbit isn’t actually too difficult. The equation for finding your velocity is right here: v = sqrt(GM / r). (r = distance from the planet, G = gravitational constant, and M = mass of the planet) Cool. Progress!
How about dodging incoming objects? Hal could move in the opposite direction of anything that gets too close to him, right? Wrong. For starters, how close is “too close”? If a giant space rock is flying quickly towards his face, he needs to be alerted well in advance. But if there is an asteroid minding its own business in a slightly higher orbit than him, it’s no threat to him at all. It isn’t enough to project their velocities forward either, because gravity curves their trajectories over time. Luckily, Johannes Kepler has Hal covered. Since Orbitroids is a two-dimensional game, Hal’s elliptical trajectory can be calculated with three of the five orbital elements (eccentricity, semi-major axis, argument of periapsis) and time. Doing this with every orbiting object in the game could show us where collisions occur and how to avoid them.
Sweet, it looks like we can kill two birds with one stone by using the same method described above to see if a bullet Hal shoots will intersect his target’s path. From there he can adjust his aim accordingly. With just a fair bit of math, we’ve successfully transformed Hal from a blind monkey with a gun into a worthy opponent with which to face off.
But wait… what if there is more than one planet? That is to say, what happens to Hal’s new navigation tools when you plop him into some of the most interesting levels of the game? Short answer: They fall apart. Long answer: Hal has to choose which planet to use for the variables in his equations. He decides this using patched conics, which measure each planet’s sphere of influence. (This is how the game Kerbal Space Program approaches this problem.) In real life, the gravity from the ignored planet will cause tidal forces that gently offset objects from their predicted paths. But in my game? That tidal force acts more like a gravitational hurricane since all the planets are orbiting each other at breakneck speeds and in ridiculously close proximity.
Unfortunately, this puts Hal back at square one. The only known way to accurately predict trajectories in a multi-planet gravitational system is to integrate. This means that for every frame (or every few frames), every object in orbit needs to have their position and velocity calculated for every tenth of a second for the next three seconds. That’s a lot of every‘s. But we’re not done yet! Once Hal is aware of his pending demise, the warning lights go on, and he is looking for a way out. How does he know which way to go? He needs to calculate not just his current trajectory, but his potential trajectory if he moves slightly forward, or slightly backward, or slightly to the left. You get the point. All in all, Hal is calculating six different “escape” trajectories, and deciding which way to move by taking the trajectory with the safest path. To aim, Hal can calculate the potential trajectory of a bullet fired from his gun, and compare it to potential trajectories to the left and right, then adjust his aim accordingly.
Whew! Hal finally graduated from the Orbitroids School of Celestial Mechanics with a diploma in Not Dying Like a Chump. Is Hal an expert? Definitely not. Can he kill most human players? You betcha : ) Does his overly complex navigational system absolutely demolish the game’s frame rate when there are lots of objects in the scene? sigh… There is still plenty of optimization to be done such as transitioning to a symplectic integrator, learning what a symplectic integrator is and why it’s better than a normal integrator (I know someone way smarter than me is reading this and rolling their eyes), and offloading it to a new task using Unity 2018’s new job system. My A.I. is far from perfect but it is fun to play against and genuinely feels like it has a mind of its own. At the very least, it beats “just shooting rocks”.