Gravity Bomber: adding AI and level generation

It’s been exactly a month since I last wrote about the game I’m making in GameMaker. The good news: it’s all coming together well! I’ve given the game the working title Gravity Bomber, which I think sums up the central mechanic pretty tidily.

When I wrote my previous post, I had a demo level where I could alter the speed and acceleration of the ship and the gravitational properties of a planet, and then fire one at the other. It was very basic: the graphics were created with little more than lines and circles that I put together within the GameMaker app.

My original graphics with the first version of the gravity equation.

I got bored of looking at these simplistic graphics fairly early on and turned to the GameMaker Marketplace, where I found Jobo’s Sci-Fi Graphics Mega Pack on sale for about £3. A few sprite swaps later and Gravity Bomber started to look like an actual game. I also bought Jobo’s Realistic Explosions Pack and added a couple in.

But it was still a demo. It was still missing a fundamental piece: a goal.

The Sci-Fi pack came with a lovely battleship design that became the target for my ship—now a missile—to hit. This inspired me to tinker more with the way I was representing gravity, and ultimately to swap my method with a simpler version. In the old method, the gravity field for a planet had 3 different variables, which meant that planets did not affect the missile when it was too far away, and then overly warped its direction and velocity when it was close. It was too fiddly to adjust.

Now looking a lot better! This shot is lined up to hit its target.

With the new gravity equation, all the planets affect the missile wherever it is on the screen, as long as it’s moving. The only variable I need to adjust is the mass of the planet, which means I can easily differentiate between suns and moons. It’s much easier to use, and it led me along another line of enquiry: level generation.

The tracking mechanism for the missile works like this: an object (the tracker) is sent out on the path the ship will take, only instead of it moving in real-time, it simulates the journey in a single frame, leaving a bunch of dots to mark the path. If the player adjusts the angle of the missile, all the dots disappear and the tracker is run again. Normally, I only let the tracker move for a small distance, but my in-built debug mode completes the whole journey (with a cut-off point to avoid perfect-orbit-related memory leaks). It takes into account hitting the planets and the target.

My debug tool lets me see the randomly built level with the solutions.

Rather than manually designing a level, which would be a slow, arduous process, I opted to randomly generate each level. When the game loads, up to 6 planets of various sizes are plonked into the level. The game then tests the level by using the tracker at every possible forward-facing angle from the point of launch. If it finds enough ways through to hit the target, the level is viable and the player can play through it. If the level isn’t viable, the level regenerates until a viable level is found.

Easy. Then I added player 2 and did the same calculation at the start of every level in the other direction.

Suddenly, a level might have to be regenerated anywhere between 1 and 1,000 times to get a viable option. Depending on which PC I was using, a level could take several minutes to load; ridiculous considering the simplicity of the game. I added a limit on the number of planets, so that it would start with 4 or 5 planets and then drop to 2 or 3 if a viable level wasn’t generated quickly enough. It didn’t make enough of a difference; even with this, a level might still take more than a minute to load.

So I cheated. I built a mechanism that can save viable levels and reload them later. Now, the game tries to build a 5 or 6 planet level, then a 3 or 4 planet level. If it hasn’t achieved a working level in less than 70 attempts, it’ll load up the database of previously found viable levels and pick one of those. Any newly generated levels get added to the database, and I’ve preloaded the database with about 130 levels so far (although if I change anything going forward, such as the size of the level or the missiles or the planets, I’ll have to repopulate it). Every level loads up in a few seconds. I added a bit of colour and background randomisation to give a bit of natural variance and voila!

The enemy takes its shot. It missed.

That was 2-player sorted, but I also wanted a game that I can play in my natural environment: that is, alone. Thankfully, when I built the tracking system to count the number of hits on the opposite target, I made sure I could record the initial firing angle of those hits. When playing single player, those initial angles get loaded into an array (specifically a ds_list) and one of them is picked at random. I add a variance to the picked firing angle that narrows according to the game difficulty and load all the angles (including the winning one) into a new list, which is then shuffled. Hey presto: the game has an AI that looks like it’s trying to narrow down its shot, and that gets ‘better’ as the difficulty level is increased.

I have a working game.

Gravity Bomber isn’t finished yet. I’ve got a whole list of tasks to go through. There are no sounds. I want to add in asteroids to hit for bonus points (scoring was something else I added in fairly early, although it’ll need some tweaking). I still don’t like the controls, and I would like controller support. The UI looks rubbish. I need a main menu screen for the player to select 1-player or 2-player, and to choose their player colour. I need to add statistics so that I can define who wins overall. I need a player save option. I have a bunch of other cosmetic changes I need to figure out. All of the timing stuff is funky right now, which annoys me because one of the things I am usually most pernickety about in my day job is game timing.

I love a good to-do list.

A little way to go, then. I’m learning a lot about development practises as a part of this exercise: when to code in a straight line and when a script might make life easier. But it’s fun, above all, even if my brain does spend undue amounts of my rest and work time trying to figure out what to do next.

Install Gravity Bomber in its current form with the link below. As before, all feedback welcome!

Download GravityBomber .exe file – Windows only – 25MB

Note about building a Mac version: sadly, due to Apple’s insistence that any apps for Macs need to be built on a Mac (and the subsequent hoops they make you jump through to get even a basic Mac app working), I am currently unable to build a Mac version. At some point, assuming this project keeps going, I will try to rectify the situation, but… yeah. The instructions look complicated!