Hey folks,
Designer here o/
My task over the last few weeks is getting the AI up and running, so here's an update on my progress so far:
Creating a workable perception system for a 2D game in unreal has proved a much bigger challenge than we had expected. However, despite the initial problems we’ve managed to come up with something perfect for our needs. One of our coders, Rex, did a great job in creating us a bespoke sense configuration for 2D.
What we now have is a collection of several 2D cones, which give a much better representation of the AI’s sight. We’ve also offset the position of the visibility raycast to go from eye to eye, rather than the centre of each character.
These two changes have made a massive difference to how it functions, and give us much more room to add interesting gameplay features. There’s plenty of tweaking ahead but by and large the AI sees you when you think it should, and hiding from it is also much more intuitive than before.
Speaking of tweaking these values, Rex also implemented a new debug to replace Epic’s own Gameplay debugger for our purposes. It easily lets us know which cone/s we are in, and if the AI is successfully able to raycast to the player.
EQSUnreal Engine has a really powerful tool known as the ‘Environment Query System’. This system allows you to ask questions about the environment around you, and filter it down into useable bits of data. Using this hugely powerful tool for a 2D game is obviously overkill, but the key advantage is that they are very easy to create and test just using blueprint and the in-game editor. My aim wherever possible is for everything to remain completely readable by anyone on the team, so they can make their own improvements and suggestions.
At the moment I’m only implementing a few simple tests, for example: ‘find the nearest waypoint I can successfully plot a path to’ and ‘pick a random spot near to where I last saw the player’. Here's an example of picking a nearby valid point (the blue points are discarded as the AI can't reach them):
I’m looking forward to expanding these in the future using a few simple tricks to help the AI make smarter decisions without cheating too much. For example, when I create a query to pick a random spot near where the AI last saw the player, I can weight the results towards where the player actually is (even if they are hidden!).
Last Known PositionAnother important aspect of our perception system is the concept of ‘last known position’, which I’ll refer to as LKP from now on to preserve my sanity!
Unreal’s perception system has it’s own concept of LKP, but we aren’t currently using it just yet. My simplified version positions an object whenever the player leaves the view cones. This position is then used as a start point for a search, should the AI reach the point and still not get a visual on the player.
Having this LKP object also allows me to deploy another classic stealth AI cheat which I like to refer to as ‘6th sense’.
Imagine a situation where I pass through an AI’s view cones heading in a direction it can’t see. How do I make the AI seem smart and know which way the player has gone? Sure, I could make it super complicated by using things like Dead Reckoning combined with multiple EQS to decide which cover the player is likely to be in. This is the sort of thing you’d find in Crysis or Halo, and as such is somewhat beyond our scope as a 2D game.
Instead, the LKP is updated for a short time (~0.5 seconds) after the AI has technically lost sight of them. From the player's perspective, this usually just looks like intuition, and would only look like cheating if the time is too long. As with most things in life, this is best explained with a gif.
The green tick in the cross hair is my LKP. See how it continues to update even after the player character leaves the view cones.
SuspicionSuspicion is what we use to determine what the AI thinks is worth investigating, and later chasing after. The rate the suspicion increases is determined by whichever cone the player character is currently in. If they are in more than one cone, the cone with the higher rate of suspicion is used.
Currently we have 3 cones:
Close Cone - Instant max suspicion. If the AI sees you here, it will chase immediately.
Mid Cone - Average level increase.
Far Cone - Small increase.
Note that currently this suspicion system doesn’t take into account how well lit the player is. I’ll try adding a modifier based on that during the next pass as right now I just feel it’d muddy the waters while we test out the basics.
I also added some code to cover colliding with the the AI. Spoilers - they don’t like it very much.
Behavior TreeAll these new features mean there’s a lot more going on in the Behavior Tree now. I think it’s time to start splitting these into separate behaviors . . .
There are a few other issues that have started to appear, now things are a bit more complicated - I have quite a few areas where I quite harshly abort sequences if things change (like for example the player leaves the AI’s sight) and these now cause visible hitching as the AI flip flops between two branches. I’ll need to take a step back and rethink some of these longer sequences and find some more graceful break points.
So, that’s all for now! What’s next?
- Hooking up all the animations
- Moving the view cone around (looking up and down, moving up and down slopes etc)
- Adding some placeholder sounds
- Lots of tweaking of the ‘magic numbers’ until it feels good
Thanks for reading! I’d be happy to hear any feedback if people have any advice or thoughts to offer here.