Could I feel more stupid?

Could I feel more stupid?

[Disclaimer: This article was originally posted over at Dev6 Game Studio.]


Hi everyone,

recently I started working on a computer-controlled opponent for Pixel Commander and today I’d like to walk you through the first steps I took to make it kick my butt without cheating. So if you are interested in our AI and want to see horrible programmer art, be my guest.


So whats the deal here?

To explain my train of thoughts I’m going to use a very simple example seen below.


A simple level in Pixel Commander containing five factories.

In the picture above you can see a very basic level of AngryPixels I used to implement the first draft of the AI. The player’s and the AI’s bases are directly opposite of each other across a small lake with two low-tier bases to the right and one high-tier base to the left. This leaves the AI enough choices so I can start fiddling with it until I switch to a more complex level to test it under more difficult circumstances.

Before I could start implementing the AI’s decision making I had to think about when the AI would actually be able to make decisions. As the player, you can only do that in the planning phase and are unable to change your plans and the paths you laid out during the combat phase. To keep the AI fair (for now) I decided that it should use the game’s phases exactly like the player has to, meaning it would plan during the planning phase and be idle during the combat phase. As soon as the player has finished his planning and informs the game that he is ready to continue, the AI quickly makes its plans and the combat phase begins. This means the AI has the same disadvantages as the player when it comes to conquering factories, namely not being able to change the production or the chosen path right after taking it, resulting in a few miss-productions.


Finding a path

Once that was decided I had to come up with an initial strategy of what the AI should concern itself with. The first thing that came to my mind were the factory routes the player is laying out. Up until now, our level designers have been laying out the AI’s paths so for me it was the first logical step to make the AI do that itself. In order for the AI to know the paths it can take I added a simple node-based path network to the level that looked somewhat like in the image below.

The initial path network of the level.

The initial path network of the level.

Each node of the network (represented by a yellow dot in the picture above) has three arrays of objects:

  • Factories that can be conquered at the node
  • Factories whose production exits to the node
  • Nodes connected to the node

To be honest, in my very first implementation I did not save an array of factory exits which posed a severe problem in a different level. Our factories do not always exit their production to the same node they can be captured from. For example, in a different level we have a factory on a hill that has to be captured from above but makes its units exit through a cave to the south. In order to simplify this situation and resolve the problem I added the additional information.

Using this network and A* pathfinding the AI can now get a path from any factory in the network to another, which enables it to decide which factory to attack.


Strategic values

To enable the AI to make an educated decision I started the AI’s plan method by assigning a strategic value to each factory. The initial value of 1.0 can be modified by three values: attack, conquer and defend. These values can be defined for each AI in the editor to give the designers some freedom and influence on the behaviour. Attack resembles conquering a factory that is being controlled by an enemy, conquer describes taking a neutral base and defend involves defending a friendly factory from being enemy units. Friendly factories that are not being contested are assigned a value of 0 because there is no gain from looking at them.

Once the initial values are calculated, the AI selects the best current target for each factory and lays out the shortest path between them using invisible path flags. The best target is always the factory with the highest strategic value. Would the AI use the values as they are right now, it would always attack the player’s main base.

Initial strategic values for each factory.

Initial strategic values for each factory.

Immediately attacking the player’s base would make for a pretty boring AI and, as a result, no fun game. So I decided to adjust each strategic value based on the distance between the current factory being planned for and the factory being targetted. That way, the first factory being targetted was the closest one.

Strategic values modified by distance.

Strategic values modified by distance.


Could I feel more stupid?

Using this simple decision method, I had already created an opponent powerful enough to easily defeat a new player not paying enough attention, or myself for that matter. While playing this level against the AI to test it I lost about 80% of all games I played. Needless to say, I felt quite stupid to lose against an AI so bare-bone..


Addendum: How did it turn out?

At the time I wrote this article I was at the very beginning of designing and implementing the AI for the game and by now it has been finished for quite some time. Besides a lot of optimization work the most important features I added were water paths, unit selection based on the enemy’s units and a nice editor to easily create and adjust path networks.

I am satisfied with how the AI turned out as it is able to create challenging and interesting situations that require skill and planning to overcome. If you’d like to check it out yourself, you probably already download the game in several app stores. Simply check the games of Dev6, they should have a few links over there.

If you stuck with me until this point, thank you very much for reading and enjoy the rest of your day.

Leave a Reply

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

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>