TankUp: State Machining the Behaviour part 2

I really want to make a decent state machine. I think the proper way to go is modular, eventful and probably recursive . The idea of really flexible state machine is… tantalizing, but unfortunately I still can not see t completely and, truthfully, TankUp will not utilize it fully. I don’t have a lot of possible states and they are, for better or for worse, hierarchical. The best I can get is a fairly bonsaical tree.

The core of my decision making is something like this:

conditionreaction
More than 1 enemyflee
1 enemyfight
Upgrades and Layerschoose layers
Nothing in rangeroam

Of course, this can be (and will be) elaborated upon by adding more precision to the conditions. Also… The best idea I’ve had so far is to add another layer to the behaviour.

All a tank can do is fight another tank, flee the scene, pick upsome asset or wander about, looking for trouble. However, the player is bound to have some more information about the battlefield than the autotanks (he sees further, for example). So I don’t want the player to see two tanks that appear to be in range of each other and immediately know with certainty what they will do. Some variability goes a long way.

Enter stances.

There are three primary stances – aggressive, balanced, evasive. Each autotank has one stance associated at birth. Shove that into the table and you get to that:

conditionAggressive reactionBalanced reactionEvasive reaction
More than 1 enemy, total size larger than own sizefleefleeflee
More than 1 enemy, total size smaller than own sizefightfleeflee
1 enemy, larger than selffightfightflee
1 enemy, smaller than selffightfightfight
Upgrades and Layersupgradeslayerslayers
No assets in rangeroamroamroam

You can see some real behavoiur now. Or a semblance of one, at least.

And if you’ve gone that far, there is one more step, that costs nothing, but adds a lot – two extra stances at each end of the spectrum and a simple mechanism for changing stance.

conditionBerserkAggressiveBalancedEvasiveCoward
More than 1 enemy, total size larger than own sizefightfleefleefleeflee
More than 1 enemy, total size smaller than own sizefightfightfleefleeflee
1 enemy, larger than selffightfightfightfleeflee
1 enemy, smaller than selffightfightfightfightflee
Upgrades and Layersupgradesupgradeslayerslayerslayers
No assets in rangeroamroamroamroamroam

Each stance sets two variables – upper and lower threshold for the autotank size (in terms of number of layers). Let’s say for balanced the upper bound is 4, the lower is 2.

For now (cause it’s untested) the lower bound is not taken into account until the autotank has reached it (see “Speed”, “50mph”). So the autotank is created, starting with 1 layer. If it collects another one, the tank gets in it’s own zone (I need a term… ‘native’?). If the tank picks up another 2 layers and gets to 4, he changes the stance to aggressive. If he drops below 2, he becoms a coward. Those stances dictate the reaction to his surroundings.

Important note about the tanks upbringing:

Let’s take an aggressive tank for example. The bounds are, let’s say, 6 and 3. So if an aggresive tank drops below 3 layers, he becomes balanced. However, the tank that was born balanced needs to drop below 4 to transition from aggresive to balanced. So the native stance matters. That should keep things interesting.

And of course, there is no upbound transition for the berserk, just as there is no downwards transition for the coward.

TankUp: State Machining the Behaviour

About the state machine.

I’m working my way towards the state machines that should govern the behaviour of the autotanks.

The main problem that I had was that generic tutorials and explanations of state-machines always start from a graph and describe a small number of states with transitions depending on a couple of variables at most.

Not that this is bad in any way, but I would not manage to describe what I need with this kind of constraints.

Well, given the fact that in the end each state will surely be linked to at least one other state and that, provided you don’t mess up something, you will be able to find a path from any one one state to any other, following the liks, you will have the graph as a result. If you try to start with a graph and multiple conditions, it is too easy to end up tangled up.

So… let’s start with all the conditions I want to keep in mind.

The AI tank can see other tanks and the pickups (within its sensor range). It can not assess anything else from an opponent than its size. So the stack size will be passed with the scanned data.

When the AITank (I’ll have to call it ‘autotank’ from now on, cause it’s easier to type)… so when the autotank gets information that there are enemies and, let’s say, a layer in range, it has to decide what to do.

The possible options are, as it can be expected: fight one of the enemies, go for the layer or bugger off.

However, I wanted to have the autotank act differently depending on the number of enemies, for example, or the size of the whole ‘gang’. It’s not that ‘enemy in range = attack’ is a bad pattern, but it’s suitable for large mobs, not individual combatants. Also, I don’t want to have super smart autotanks, but I need then to make sense.

Here’s what I have in my mind at this point…

(to be continued…)