Since I removed all my brain state machine logic in favour of this new AI, I no longer have certain features I had, like seeking out the player. In fact, this will have to be done almost completely differently now. Currently, the enemies that lose sight of the player just stand still forever:
The question is how I should encode something like “seek player” in my desire behaviours. Technically, this is what beliefs are for in BDI systems — to specify things like “there is a player and they were last seen here”. And I can sort of do this, but I have to be careful with my logic not to make a mess. Firstly, my current beliefs are more like event triggers. So I think what I need to do is have custom rules for enabling or disabling individual desires. Such as “can see player” enables “shoot” or “fire” and then something like “lost sight of player” can enable “seek player”. I’ll call these “assumptions” and add to the desire definitions:
So now desires will be inactive if the assumptions are not fulfilled and not merely defaulted to idle due to a threshold:
And since desires can be inactive and their beliefs won’t change them, I need a forced decay of inactive desired:
So now I can also add a new desire to seek the player (roughly speaking):
I am yet to add enemy awareness levels of the player, so for now it’s just an instant permanent flag the first time they see the player. The question here is what beliefs exactly further the desire to seek the enemy. I guess it doesn’t really matter that much since there are no desires “fighting” each other yet. I can just add something timed like:
In fact, I now have an option to vary for the recently seen belief, i.e. how long ago:
But for this I need an opposite belief, which I can achieve by allowing my continuous belief to react to the opposite result:
Anyway, the seek desire works fine (in principle):
Once enemies lose sight of the player, they go into the “seek player” desire (which doesn’t actually do anything yet). So now I can add some “conflicting” desire, such as trying to go back to spawn once the player hasn’t been seen for a while or the enemy is really far away:
And this also works fine (also in principle):
So now I can store the spawn location, the player location and then call my pathing routine on those during the relevant intentions. This does turn my enemies abruptly from “shuffle around” into “instant hot pursuit”, but the concept works great and, more importantly, they recover afterwards back into their attacking:
Again, balancing this is just a matter of tweaking the numbers and adding various extra checks and timings. (I believe I said the same about the brain logic, but oh well.)
For one, I can add an uncertainty to where the enemies think they last saw the player. (I can even make it an increasing one, but I doubt anyone playing this would ever notice, so why bother.) I can add a random offset to where the enemies will go:
Of course, it is easy for enemies to never actually find the player (they will stay on the assumed player coordinate and the eventually go back to spawn):
So let’s add a wander desire which activates when the enemy is close to where they think the player is:
So now the enemy desires to wander around until the enemy was last seen too long ago:
Now I just need some tweakable wandering options:
While watching the two desires “argue”, I noticed an interesting problem with their scores. Two desires may be at maximum and so appear to be equal. But one of them might have beliefs that strongly contribute to keeping it at maximum while the other might barely hold on to it. This is because my scores are not absolutes from inputs but deliberately accumulate over time. I want the prominent desire to win in this scenario. So to fix this I clamp all my desires at about 80%. Then (theoretically) the desire that has strongest contributors will keep rising above the other and then both desires will get clamped, except the weaker desire will also weaken proportionally.
Anyway, a lot of tweaking later, this works reasonably well:
Here three enemies were seeking the player. One arrived where they can see the player, but two did not. The two then proceeded to wander around and both happened to find the player. As always, “good enough”.
Now the only time the enemies are not doing anything is when they are idle. This feels wrong. I won’t do any fancy stuff like patrol points or anything. But I can do a simple idle/wander around the spawn point desire:
And all the accompanying properties, which are very similar to other random movement states, just number to tweak:
I also had to adjust the return to spawn desire to also grow when the enemies wander too far from the spawn. Otherwise, they could just theoretically wander the entire dungeon. And this works more or less fine (sped up a lot):
I think this about covers all the basics I need for (gun-yielding) enemies. They idle, they attack and flank, they seek and search for the player. In other words, whenever the player is near, they can see some sort of activity happening. And I can tweak and fiddle with pretty much every parameter.