Hello, I am working on a Top-Down (for now) survival shooter. I am am experienced programmer (fairly new to Unity). I have used Unity's navmesh and understand how it works. I am wondering how I would do horde AI. Not only following the player, but some choosing to attack and attempt to break down windows / doors, and others taking the easiest path through already open doors. Basically, how do I limit a window to maybe 5 or 6 zombies at a time trying to get through while the rest choose a different entrance? How is something like this usually done in Unity with the navmesh system. I am not asking for someone to code it for me, just the best approach. Thank you
Id be curious how others may work on this. Some ideas- use multiple targets. have a simple list script for attackable objects. When an object is attacked by a zombie add that zombie to its list. only let a zombie attack an object that has an open list of attackers. Code (CSharp): using UnityEngine; using System.Collections; using System.Collections.Generic; public class JBR_AI_Search_System : MonoBehaviour { //add proper tags in inspector public string playerTag; public string npcTag; public string MiscTargetTag; // allow targeting of each type of target public bool canTargetPlayerTag; public bool canTargetNPCTag; public bool canTargetMiscTargetTag; //list of all targets public List<GameObject> allTargets = new List<GameObject>(); //array of each target type public GameObject[] playerTargets; public GameObject[] NPCTargets; public GameObject[] miscTargets; // Use this for initialization void Start() { //optimization does this check 10 times per second vs. 30-60 times in regular update InvokeRepeating("CheckForTargets", 0.1f, 0.1f); } void CheckForTargets(){ //clear list of targets before we redo the list allTargets.Clear(); //if checked add all player targets if (canTargetPlayerTag) { playerTargets = GameObject.FindGameObjectsWithTag(playerTag); for (int i = 0; i < playerTargets.Length ; i++) { allTargets.Add(playerTargets[i]); Debug.Log(playerTargets[i]); } } //if checked add all NPC targets if (canTargetNPCTag) { NPCTargets = GameObject.FindGameObjectsWithTag(npcTag); for (int i = 0; i < NPCTargets.Length ; i++) { allTargets.Add(NPCTargets[i]); } } //if checked add all Misc targets if (canTargetMiscTargetTag) { miscTargets = GameObject.FindGameObjectsWithTag(MiscTargetTag); for (int i = 0; i < miscTargets.Length ; i++) { allTargets.Add(miscTargets[i]); } } //checked through list of all targets if (allTargets.Count > 0) { for (int i = 0; i < allTargets.Count ; i++) { //sift through all the targets for the best one // checks the distance away from ai to target float cDistance = Vector3.Distance(this.transform.position, allTargets[i].transform.position); Debug.Log("All Targets - " + allTargets[i] + "distance " + cDistance); }
Attackers handling Code (CSharp): using UnityEngine; using System.Collections; using System.Collections.Generic; // basic Aggro handling of anything that can be attacked public class JBR_AttackableObject : MonoBehaviour { public int maxAttackers = 6; //max allowed attackers public GameObject[] Attackers ; //Array of attackers public bool LimitReached = false; //if array is full sets to true // Use this for initialization void Start () { Attackers = new GameObject[maxAttackers]; Debug.Log(Attackers.Length); } // Update is called once per frame void Update () { } //method for adding Attackers public void TakeDamage(GameObject attackerGO) { //look through all array slots for (int i = 0; i < Attackers.Length +1; i++) { // first we check that this attacker hasnt been added to the array already if(Attackers[i] == attackerGO) { Debug.Log("Duplicate Attacker " + this.gameObject.name); return; } //next we add the attacker to the first open slot in the array if(Attackers[i] == null ) { Attackers[i] = attackerGO; Debug.Log("New Attacker added " + this.gameObject.name); return; } //if we made it to maxAttackers limit then set as limit reached if(i >= maxAttackers) { LimitReached = true; Debug.Log("Limit Reached " + this.gameObject.name); return; } } } //method for removing Attackers public void RemoveAttacker(GameObject removedAttacker) { //look through all array slots for (int i = 0; i < Attackers.Length; i++) { if (Attackers[i] == removedAttacker) { LimitReached = false; Attackers[i] = null; Debug.Log("Removed Attacker " + this.gameObject.name); return; } } } }