I am currently working on an AI system in Unity for a stealth game but where the enemies are those that infiltrates and the player has to defend a specifc location, for example an object the enemies will try to steal. I wanted AI agent to act like I am when playing such a game, like hiding behind walls, hearing enemies footsteps, flee when an enemy is coming closer. I wanted my AI agent to have the same information as a real player. In a game there is mainly two information sources : what we see and what we hear. This article concerns the first source. How to give the AI agent a way of knowing what it sees.
Discussion
Unity gives many ways of analysing the game world. It has functions like Physics.RayCast(...) or Physics.OverlapSphere(...), it gives us also information about bounds, meshes and renderer. For my project, AI agents must be able to look for places to go, to have access to all objects they see and are interested in.
As I was thinking about what's a view, and how to give it to an AI agent, I was considering what are the view properties, it has a field of view, a facing direction, an origin and how far we see. I realised that this description is a good description of a camera. So why should I make a camera-like component if I can try using the existing Unity camera component.
I tried to figure out if there was a way to know every gameobject present in the line of sight of the camera in Unity. There is, but it is too time and memory expensive (I'll be happy to show you how). There are other information you may think of using like using renderer.isVisible, OnBecameVisible(), OnWillRenderObject() but you'll have to attach a script to every object you want your AI to be able to see. Besides, renderer.isVisible doesn't tell you from which camera it is visible, and none of these method takes care of occlusion. All these datas are hard to work with knowing we are working with mutliple camera.
As I was thinking about what's a view, and how to give it to an AI agent, I was considering what are the view properties, it has a field of view, a facing direction, an origin and how far we see. I realised that this description is a good description of a camera. So why should I make a camera-like component if I can try using the existing Unity camera component.
I tried to figure out if there was a way to know every gameobject present in the line of sight of the camera in Unity. There is, but it is too time and memory expensive (I'll be happy to show you how). There are other information you may think of using like using renderer.isVisible, OnBecameVisible(), OnWillRenderObject() but you'll have to attach a script to every object you want your AI to be able to see. Besides, renderer.isVisible doesn't tell you from which camera it is visible, and none of these method takes care of occlusion. All these datas are hard to work with knowing we are working with mutliple camera.
Know if GameObject is in AI Line of Sight
My idea is to attach a camera on every AI agent, a viewsensor. The camera is set with a certain field of view, and a far plane. Unity has two handy functions for camera testing, the first one gives back the 6 planes defining the camera frustum, and the second one tells if a bounds object is inside or outside the camera frustum.
Now we can know if a gameobjet is inside our view but not if we can see it because it may be hidden by another object closer the camera position. So I use linecasts to know if we can see the object. But to which position should I cast? Object center position is a good choice but not necessarily accurate enough. I use the object mesh bounds, and go through all the bounds positions and stop when a linecast don't go through anything and then I know a see the object.
The perfect way would be to do a linecast between each vertice of the mesh but it would be too much time expensive.
Now we can know if a gameobjet is inside our view but not if we can see it because it may be hidden by another object closer the camera position. So I use linecasts to know if we can see the object. But to which position should I cast? Object center position is a good choice but not necessarily accurate enough. I use the object mesh bounds, and go through all the bounds positions and stop when a linecast don't go through anything and then I know a see the object.
The perfect way would be to do a linecast between each vertice of the mesh but it would be too much time expensive.
Get All the GameObjects
Now we have a function telling us if a specific object is in AI line of sight, I just test every object given by an overlapping sphere check starting on the camera position and with a radius of my camera far plane distance. I call my previous SeeGameObject function on each object and keep those are in line of sight in an array.