This is part 2 in a series of blog posts describing what we did during the development of our game Cardlings. You can buy it on Steam for $4.99 and, by the way, that would be a great way of supporting us. Just saying... :)
If you haven't read part 1, I recommend reading that first.
What went right: AI design
Before Cardlings, we had never worked on a strategy game. We knew that designing and implementing the AI is usually the hardest part of these games, so we started doing some extensive research into how Age of Empires and similar games did it.
Unsurprisingly, there are countless approaches that people have been taking for the past 40 years, some more successful than others. So we went with a mix-and-match approach, getting some ideas from different sources and mixing them together with our own. I think we ended up with a nice algorithm that is relatively simple, fast and quite effective.
First of all, the AI must always have a clear long-term strategy, and this strategy dictates what short-term actions it will take; however, changes in circumstances (such as the inability to successfully carry out these short-term actions, or new information that becomes available as the game goes on) should affect the long-term strategy.
To make an example: you can win a game of Cardlings by either upgrading your castle, or by destroying your opponent's castle. The AI will start with one of these goals in mind, more often than not it will be trying to destroy the opponent's castle. However, if the opponent does a good job at defending their castle and the resources needed to upgrade the castle become readily available, at some point the AI will say "forget about their castle, let's just upgrade ours".
It is important, however, that the AI doesn't change its mind too often: this would result in erratic behavior that would lead nowhere. Only change the long-term strategy when there's a clear advantage in doing so, AND when it's been long enough since the last time you changed your strategy.
But let's have a more detailed look at the implementation.
Based on the currently active long-term strategy, we give the AI some "personality traits". This a list of sentences with an associated score, and it looks something like this:
"I like to explore new areas of the map": 10, "I prefer to have my units next to my buildings": 5, "I like to spend gold": -2, ...
It's a fairly long list. In reality we don't even use a single number for each sentence, rather we use an array to describe how these things change over the course of the game. For example, exploring new areas is crucial during the early game, much less so as time goes on. So the relevant entry in the "personality traits" list looks something like this:
"I like to explore new areas of the map": [10, 7, 2, 0.3]
Now when the AI needs to decide what to do next, it will first enumerate all possible moves: I can place an archer here, or I could place it here; I could build a blacksmith here or there; I can move this unit; I can upgrade this other unit, etc.
Then, based on the personality traits, we give a score to the current game state. So if "I prefer to have my unit next to my buildings" is a positive number, and the AI's units are close to the AI's buildings, we add a positive value to the score, and so on.
Subsequently, we try to perform each of the possible moves, and then give a score to the resulting game state. This gives us a good indication of how each move is aligned with the current personality traits, i.e. with the current long-term strategy.
As it turns out, this gets us quite far, but it's not nearly enough to make a good AI. We need to go deeper, like most AIs do for games like chess or go. That is, once we have selected a few possible moves according to the criteria described above, for each of those we start thinking: if I made this move, what would I do next? And what would be the move after that?
As you can imagine, this takes quite a bit of time. And in fact, it's essential that this happens on a separate thread - there is just no way to make it happen on the main thread where you're doing all the rest of the game logic. For us, a WebWorker worked perfectly. The AI exists in its own separate thread, and exchanges messages with our game server like the local human player does (see part 1 for more details).
Another key aspect is to determine what numbers go into that personality traits list. You could do much of it by trial and error, but by far the most effective approach is that of having AI players battling each other to determine who has the better combination of personality trait, and proceed in a genetic programming manner.
All in all, I'm quite happy with what we got. It's not enough to beat the most experienced strategy gamers out there, but it's certainly a pretty decent challenge for most players.
What went wrong: getting on Steam too late
Having never self-published a game on Steam before, we were obviously bound to make some stupid mistakes. And we made many. If I had to single out one of them though, I'd say that the stupidest decision we've made was waiting too long to make our Steam page public.
Valve even say it explicitly in their developer documentation: "You can put up a Coming Soon page for your product well in advance of your release date. This way, you can let customers know the title is coming to Steam and start building an audience and excitement around your product."
We should have listened :) Instead, we decided to wait until the game was nearly ready and we had set a release date before making the store page public. Funnily enough, the store page itself had been ready for months before that, with screenshots and a trailer and all that.
So why is that important? Let's talk numbers.
As a small indie developer, you can do a lot of things to make people aware of your game: social media, blog posts, talk about it in forums and all that. You may be able to reach a few thousand people by doing so. This leads to a few dozen people actually visiting your product's page.
On the other hand, Steam is a huge platform, with nearly 100 million active users per month. And all of them are dedicated gamers that are ready to spend some cash on new games. Think about the scale of it for a moment. This means that just by virtue of existing on Steam, your product's page will get at least hundreds if not thousands of impressions per day, dwarfing any of your other attempts at promoting it.
People get to your product's page because it gets suggested in "more games like this" lists, or because they browse random upcoming games, etc. It's only a small, very very tiny fraction of the Steam user base that ends up onto your product page, but because of the massive size of that user base, it's still a lot of users.
Now some of these people will add the game to their wishlists (not many, but in our case it was a nice double-digit number every single day before release), and on average 1 in 4 of those people will eventually buy the game.
Obviously your milage may and will vary, but we did lose a significant number of potential sales for no good reason.
In short my advice would be to get into a position where you have some nice screenshots and a trailer, and start working on your Steam page and make it public asap. It's definitely worth it.