Hello, im currently trying to develop an animal ai for my game.
What differs from many animal ai systems are that the animals are not only going to interact with the player, but also with other animals. What is the best way of doing the “find target and calculate action” part?
Right now i use a sphere collider and the “OnTrigger” functions, but the problem with that approach is to handle multiple targets, what would you guys recommend as a efficient way of getting multiple targets within a certain radius? Feels a bit heavy to do many spherecasts every frame?
There’s nothing wrong with the approach you suggested and it can handle multiple targets. Per animal, maintain a list of characters that enter/exit and track deaths and special events that remove characters that may be in the list. That’s how we do it on Folk Tale. Sphere casts and distance calculations are not recommended for the reason you stated.
What about checking not every frame, but every seconds, all the animals/players in the sphere radius, and add them to an array? You could sort them whatever way you wanted, and do the action depending on the type of animal/player it’s the first in the array
I’ll second what everyone else has said - colliders are more performant and more flexible than any other way of entity detection.
Better still, colliders better enforce the SOLID principles - your AI only knows about what it needs to know about, and if coded properly entails less coupling to other parts of your game object. There’s simply no reason not to use them.
I’d chose this
Use Vector3.Distance and Dot funciton. You can check animals within a certain distance and angle of of each other. You can check the collider and/or if the other’s collider has a certain script on it. If you have multiple animals within your animal’s view, set them to an array and have the array pick one.
If you want to check every couple of seconds, yield waitforseconds in a coroutine.
Use Physics.OverlapSphere to get an array of colliders within a certain radius.
If you’re interested in AI development you may want to read “Programming Game AI By Example”
Our next title is a sports game and I will be studying that book very closely
I’m going to get that book.
Thats a very good book.
Thanx everyone for your replies, i think the idea with a list and then use sphere collider seems like a good idea. Having 20+ animals using Physics.OverlapSphere seems expensive, even if not used every frame? I also like the idea that i don’t have to care about the animals thats not inside my radius. I will also probably make it that animals outside a certain distance will have their sphere colliders deactivated, this can of course be checked every second or even less often.
That book looks interesting : )
Physics casts return arrays, which means unavoidable heap allocation, which feed the garbage collector and cause the well known gc spike to happen sooner.
If you only have a few active animals+characters, iterating a set of cached “active actors” and calculating the sqrmagnitude ( or ever so slightly slower Vector3.Distance ) in a periodic coroutine may prove easier to implement assuming you are caching transform references. It won’t cause any heap allocation, but it’s a little wasteful.
For larger levels with lots of actors though, I’d still recommend triggers over physics casts. If you could pass an existing array into a physics cast and have it use that, then I’d consider it, but since you can’t in Unity, I personally would want to avoid the allocation and go with triggers. Once an animal has entered range, you only need to know when it leaves. With overlap sphere you are asking the same question every time which sounds like a waste.
A little analogy. At a party, does it make more sense to listen for the door to go, or every few seconds run to every guest in the room and ask them if they are still at the party.
A general rule for performance is to only run code when it’s required. By that rationale, triggers surely trump frequent physics casts.
EDIT : Sorry I misread your post…
I agree in this case, a sphere with a trigger is probably a better solution than Physics.OverlapSphere.
The user will just need to manage their list of GameObjects of what is in range and what is not.
One thing to consider though is what happens if an animal in range dies or is killed by another animal?
Then a message will need to be sent to the player’s list of in-range animals to remove it from the list.
Definately the more optimised solution, but it will take the developer a little more work.
Not afraid of some work ; )
Did not think about the thing when animals die, but thats simple cause they already have a list of animals in range, just loop through it and execute a function. A trickier problem is if an animal spawns inside of a “animal zone”, but i guess that can be solved as well.
Performance - and bug-solving idea.
In Thora, I’m working on a system that, only when you enter a certain subregion of a map do AI entities spawn. Leave the area, and the entities will be despawned by the region itself.
This serves two purposes: the player will always be able to enter the region at a certain distance; AI entities will spawn far enough inside that distance such that the AI will properly respond to OnTriggerEnter/OnTriggerExit events. Also, it saves on performance; the game is really only processing AI for a rather limited number of agents (including the player) at any given time.
The trouble comes when the player engages in battles…hopefully the concept will help you, though!
I will use some similar idea for my game, at least for a start. The dream would of course be persistent animals, but i think the pain is not worth it at the moment : )
AI is coming along nice, the carnivores can attack the herbivores + player and the herbivores tries to escape : )
How did you implement the initial behaviours? Any specific methodology you used?
Pretty straight forward:
At the core is a switch statement with different cases, like:
private enum eState
{
IDLE,
WANDER,
FLEE,
ATTACK,
DIE
}
Then in the “OnTriggerEnter” i check what kind of animal i am and what kind of animal the other animal is and set the switch variable to FLEE or ATTACK depending on that. On “OnTriggerExit” i just remove the animal from the list and checks if list is empty, if it is i go to the IDLE state.
Thats the basics, just ask if you have more questions : )
Sorry, I should have been more specific, how did you implement the actual behaviours… i.e flee, attack etc.
What sort of path finding/steering are you using?
Currently i don’t use any pathfinding or steering : p
Want to get the behavior core done first, the pathfinding can easily be separated from that so i will do that later somehow. Thats the part i think is the hardest : p
Virror - I have something that might prove helpful…look here, fifth post down (has two code blocks, authored by me).
It sounds rather like what you’re describing, there.