using Invector.vCharacterController.AI.FSMBehaviour; using System.Collections; using System.Collections.Generic; using UnityEngine; namespace Invector.vCharacterController.AI { [vClassHeader("AI Spawn System", openClose = false)] public class vAISpawn : vMonoBehaviour { public List spawnPropertiesList; readonly WaitForSeconds waitBetweenSpawnProps = new WaitForSeconds(0.1f); IEnumerator Start() { for (int i = 0; i < spawnPropertiesList.Count; i++) { yield return waitBetweenSpawnProps; StartCoroutine(spawnPropertiesList[i].Spawn(this, OnAISpawned)); } } /// /// Spawn a single AI of specific /// /// Spawn Propertie Name public void Spawn(string spawnName) { var spawnProp = spawnPropertiesList.Find(sp => sp.spawnName.Equals(spawnName)); if (spawnProp != null) { StartCoroutine(spawnProp.Spawn(this, OnAISpawned, true)); } } /// /// Spawn a single AI of specific /// /// Spawn Propertie Index public void Spawn(int index) { if (spawnPropertiesList.Count > 0 && index < spawnPropertiesList.Count) { StartCoroutine(spawnPropertiesList[index].Spawn(this, null, true)); } } /// /// Spawn a single AI of all /// public void SpawnOneOfAll() { StartCoroutine(SpawnOneOfAllRoutine()); } /// /// Start a specific /// /// Spawn Propertie Name public void StartSpawn(string spawnName) { var spawnProp = spawnPropertiesList.Find(sp => sp.spawnName.Equals(spawnName)); if (spawnProp != null) spawnProp.pauseSpawning = false; } /// /// Start a specific /// /// Spawn Propertie Index public void StartSpawn(int index) { if (spawnPropertiesList.Count > 0 && index < spawnPropertiesList.Count) { spawnPropertiesList[index].pauseSpawning = false; } } /// /// Start all /// public void StartSpawnAll() { StartCoroutine(StartAllRoutine()); } /// /// Pause a specific /// /// Spawn Propertie Name public void PauseSpawn(string spawnName) { var spawnProp = spawnPropertiesList.Find(sp => sp.spawnName.Equals(spawnName)); if (spawnProp != null) spawnProp.pauseSpawning = true; } /// /// Pause a specific /// /// Spawn Propertie Index public void PauseSpawn(int index) { if (spawnPropertiesList.Count > 0 && index < spawnPropertiesList.Count) { spawnPropertiesList[index].pauseSpawning = true; } } /// /// Pause all /// public void PauseSpawnAll() { StartCoroutine(PauseAllRoutine()); } IEnumerator SpawnOneOfAllRoutine() { for (int i = 0; i < spawnPropertiesList.Count; i++) { yield return waitBetweenSpawnProps; StartCoroutine(spawnPropertiesList[i].Spawn(this, null, true)); } } IEnumerator StartAllRoutine() { for (int i = 0; i < spawnPropertiesList.Count; i++) { yield return waitBetweenSpawnProps; spawnPropertiesList[i].pauseSpawning = false; } } IEnumerator PauseAllRoutine() { for (int i = 0; i < spawnPropertiesList.Count; i++) { yield return waitBetweenSpawnProps; spawnPropertiesList[i].pauseSpawning = true; } } void OnAISpawned(vAIMotor ai, vAISpawnProperties spawnProperties) { StartCoroutine(spawnProperties.Spawn(this, OnAISpawned)); } [System.Serializable] public class vAISpawnProperties : System.Object { [Header("Spawn Properties")] public string spawnName; public vAIMotor prefab; public vAIMotor[] randomPrefab; public List spawnPoints; [Tooltip("Check this option to Pause the Spawn routine")] public bool pauseSpawning; public float timeToFirstSpawn = 1f; [Tooltip("Enable or Disable the FSM Controller when Spawn")] public bool enableFSMOnSpawn = true; [Tooltip("Delay to Enable the FSM Controller")] public float delayToEnableFSM = 2; public bool randomTimeToSpawn = true; [vHideInInspector("randomTimeToSpawn")] public float minTimeBetweenSpawn = 1, maxTimeBetweenSpawn = 10; public int maxQuantity = 10; public bool keepMaxQuantity = true; [Header("AI Detection Settings")] public bool overrideDetectionSettings; public vTagMask detectionTags; public LayerMask detectionLayer; public vTagMask damageTags; public LayerMask damageLayer; [Header("Spawn Destination")] public List spawnDestinations; public vAIMovementSpeed destinationSpeed = vAIMovementSpeed.Running; public float setWaypointAreaDelay; public vWaypointArea waypointArea; public bool randomDestination; [Header("AIs Spawned")] public List aiSpawnedList; [Header("Spawn Events")] public UnityEngine.Events.UnityEvent onStartSpawn; public UnityEngine.Events.UnityEvent onSpawn; public UnityEngine.Events.UnityEvent onDead; private bool firstSpawnDone; public delegate void OnSpawnAI(vAIMotor ai, vAISpawnProperties spawnProperties); private int spawned; private int indexOfDestination; private bool inSpawn; public IEnumerator Spawn(MonoBehaviour mono, OnSpawnAI callBack = null, bool forceSpawn = false) { aiSpawnedList.RemoveAll(ai => ai == null || ai.isDead); spawnPoints.RemoveAll(sp => sp == null); spawnDestinations.RemoveAll(sd => sd == null); vAIMotor _ai = null; if (forceSpawn) spawned = aiSpawnedList.Count; if (canSpawn && (!pauseSpawning || forceSpawn) && !inSpawn) { inSpawn = true; yield return new WaitForEndOfFrame(); var _spawnPoints = spawnPoints.FindAll(sp => sp.isValid); if (_spawnPoints.Count > 0) { onStartSpawn.Invoke(); yield return new WaitForSeconds(!firstSpawnDone ? timeToFirstSpawn : randomTimeToSpawn ? Random.Range(minTimeBetweenSpawn, maxTimeBetweenSpawn) : maxTimeBetweenSpawn); var randomPoint = Mathf.Clamp(Random.Range(-1, _spawnPoints.Count), 0, _spawnPoints.Count - 1); var point = _spawnPoints[randomPoint]; if (randomPrefab.Length > 0) { var _prefab = randomPrefab[Random.Range(0, randomPrefab.Length - 1)]; if (_prefab) { _ai = Instantiate(_prefab, point.transform.position, point.transform.rotation) as vAIMotor; } } else _ai = Instantiate(prefab, point.transform.position, point.transform.rotation) as vAIMotor; firstSpawnDone = true; if (_ai) { _ai.onDead.AddListener(OnDead); onSpawn.Invoke(); aiSpawnedList.Add(_ai); var aiController = _ai.GetComponent(); yield return new WaitForSeconds(.1f); if (enableFSMOnSpawn) { var fsm = _ai.GetComponent(); if (fsm != null && enableFSMOnSpawn) { fsm.isStopped = true; if (delayToEnableFSM <= 0) fsm.isStopped = false; else mono.StartCoroutine(EnableFSM(fsm)); } } if (aiController != null) { var destination = spawnDestinations.Count == 0 ? aiController.transform.position : GetSpawnDestination(); aiController.selfStartPosition = destination; if (spawnDestinations.Count > 0) { aiController.MoveTo(destination,destinationSpeed); //aiController.RotateTo(); } if (waypointArea) { if (setWaypointAreaDelay <= 0) aiController.waypointArea = waypointArea; else mono.StartCoroutine(SetWaypointAreaToAI(aiController)); } if (overrideDetectionSettings) { aiController.SetDetectionLayer(detectionLayer); aiController.SetDetectionTags(detectionTags); if (aiController is vIControlAIMelee) { var melee = aiController as vIControlAIMelee; melee.SetMeleeHitTags(damageTags); } if (aiController is vIControlAIShooter) { var shooter = aiController as vIControlAIShooter; shooter.SetShooterHitLayer(damageLayer); } } } spawned++; } } } else { yield return new WaitForSeconds(!firstSpawnDone ? timeToFirstSpawn : randomTimeToSpawn ? Random.Range(minTimeBetweenSpawn, maxTimeBetweenSpawn) : maxTimeBetweenSpawn); } inSpawn = false; if (!forceSpawn && callBack != null) callBack.Invoke(_ai, this); } Vector3 GetRandomPoint() { var pointX = Random.Range(-20, 20); var pointZ = Random.Range(-20, 20); return new Vector3(pointX, 0, pointZ); } protected Vector3 GetSpawnDestination() { var destination = Vector3.zero; if (randomDestination) { indexOfDestination = Mathf.Clamp(Random.Range(-1, spawnDestinations.Count), 0, spawnDestinations.Count - 1); destination = spawnDestinations[indexOfDestination].transform.position; } else { if (!(indexOfDestination < spawnDestinations.Count)) { indexOfDestination = 0; } destination = spawnDestinations[indexOfDestination].transform.position; indexOfDestination++; } return destination; } IEnumerator EnableFSM(vIFSMBehaviourController vIFSM) { if (vIFSM != null) { yield return new WaitForSeconds(delayToEnableFSM); vIFSM.isStopped = false; } } IEnumerator SetWaypointAreaToAI(vIControlAI controller) { yield return new WaitForSeconds(setWaypointAreaDelay); controller.waypointArea = waypointArea; } protected void OnDead(GameObject obj) { onDead.Invoke(); } public bool canSpawn { get { return (keepMaxQuantity ? aiSpawnedList.Count : spawned) < maxQuantity && spawnPoints.Count > 0 && (prefab || randomPrefab.Length > 0); } } } } }