Categories
Development

Game Development

So over the course of developing BattleGrid, I’ve learned a lot about game development – nitty gritty stuff that it’s hard to learn without actually doing any of the work. I find a lot of this fascinating. I develop applications for a living, and while the basics are all the same, the details about how to do certain things are totally different. Case in point:

I don’t care how quick it is, split it up over multiple frames
There are a lot of things that I could do with a single line of code. I’m a bit of a code snob – I love clean, elegant code that’s easy to read, understand, and maintain. (I have a coworker that doesn’t feel the same way. We don’t get along.) In game development, though, you sometimes have to take a single unit of work and split it up over multiple frames. This means doing a bit of extra work to keep track of your progress each frame, so you can continue on the next frame. There are elegant ways to do this (I think I have a decent method), but it will never be as nice as the one-line beauty that I had before.

An example would probably help. Take targeting. Each turret and unit in BattleGrid has a targeting component that picks out the best target on the map. I’ve simply defined “best” as “closest”, so we just need to do a range check to find the closest. When I started, I just did the work, something like:

public void FindTarget()
{
    var target = this.Targeting.FindClosestTarget();
    this.SetTarget(target);
}

This worked great, except when an enemy was destroyed and the 5 turrets targeting it all decided to find new targets. Finding a target for an individual turret was easy and quick enough to do in a single frame, but if too many turrets all tried to find a target at the same time, the game starts to chug. So, I developed a simple queue:

TaskQueue.Enqueue(this.FindTarget);

Without going into any detail about what that means, that just puts the “FindTarget” action onto the task queue. The task queue executes one operation every tick (about 1/60th of a second), so if 5 turrets need targets, they just queue up their “FindTarget” actions, and targets are found over the next 5 ticks. This is fast enough that a player never notices, but slow enough that it doesn’t hurt framerate.

All this talk about targeting loosely relates to my next point:

AI is hard, but rewarding
I’ve never had kids, but I imagine teaching a kid to do something and then seeing them do it gives about the same warm fuzzy feeling that seeing an AI do what you taught it gives me. I’ve done a lot of work on the AI in BattleGrid, and I know there’s still plenty to be done. One of the hardest things to figure out was how to “teach” the AI what to build in given situations. I had a few ideas that were really complex, but ended up with a pretty simple idea – give the AI “effectiveness” values to work with.

This is what players do without thinking too much about it. “Oh, that guy has a blaster turret protecting his base. Missile turrets are longer range and can destroy that turret easily. I’ll build a missile turret.” I stored “effectiveness” values for every structure in the game. For instance, I’ve set it up so blaster turrets are highly effective against all mobile units, and artillery is effective against all stationary structures.

Now, I knew I had set these values and taught the AI how to use them. Even knowing that, the first time I saw an AI build a missile turret just out of range of one of my blaster turrets, I was amazed. That’s something a player would do – build a longer-range turret out of range of the shorter-range turret.

I’m still amazed when I see the AI counter my structures with the same things I would. I build artillery, they build shields and tanks. I build tanks, they build blasters. It’s the standard rock-paper-scissors scenario, but it’s fun to see it in action.

Continuing on AI…

Sometimes the AI needs to cheat
One of the things I noticed while playing is that the AI is much more difficult when it can afford more. When I dropped the price of all the structures (for testing), the AI could more effectively counter anything I did because they had the cash to do it. So, for more difficult AI settings, the AI cheats a bit… They get twice as much income as the player. This gives them significantly more cash, which means they’re not only thinking faster, they’re also building more that the player has to fight through. Fortunately, the AI isn’t particularly devious or clever, so the player can still beat them, but it takes significantly more work, which is exactly what I wanted for more difficult AI.

Balance is hard
I’ve struggled to get everything to feel balanced. The more options you give a player, the more difficult it is to make sure those options are balanced. I want BattleGrid to support multiple styles of play and make them all viable (playing offensively or defensively), but that makes it incredibly difficult to make sure each play style gets a fair shake. I don’t really have a solution here; it just takes a lot of testing and tweaking.

There are many more examples, but this is enough for now. Hopefully over time I’ll start to find elegant ways to solve all these problems; ways that I can carry forward into other projects.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.