EnemyManager.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. /// <summary>
  5. /// Spawns the specified prefab and positions it when a NavMeshSurface reports there's
  6. /// a new NavMesh it can walk on. Used in the ZED spatial mapping sample scene to spawn a bunny
  7. /// to walk around your environment once you're done scanning it.
  8. /// </summary>
  9. public class EnemyManager : MonoBehaviour
  10. {
  11. /// <summary>
  12. /// The prefab used to spawn the enemy. Should contain a NavMeshAgent component.
  13. /// </summary>
  14. [Tooltip("The prefab used to spawn the enemy. Should contain a NavMeshAgent component. ")]
  15. public GameObject enemyPrefab;
  16. /// <summary>
  17. /// Whether or not the NavMesh from the NavMeshSurface is ready.
  18. /// </summary>
  19. private bool isReady = false;
  20. /// <summary>
  21. /// Number of tries the script has attempted to place the prefab on the NavMesh. It stops trying at 20.
  22. /// </summary>
  23. private int noNavMeshCount = 0;
  24. /// <summary>
  25. /// Center of the current navMesh.
  26. /// </summary>
  27. private Vector3 centerNavMesh;
  28. /// <summary>
  29. /// ID of agent type accepted by the NavMesh. Agent IDs are defined in the Navigation window.
  30. /// </summary>
  31. private int agentTypeNavMeshID = 0;
  32. /// <summary>
  33. /// ID of the agent type from the prefab's NavMeshAgent component. Agent IDs are defined in the Navigation window.
  34. /// </summary>
  35. private int agentType = 0;
  36. /// <summary>
  37. /// List of all instantiated enemies.
  38. /// </summary>
  39. static List<GameObject> enemies = new List<GameObject>();
  40. void Update()
  41. {
  42. //Try to create an enemy on the NavMesh.
  43. if (isReady && enemies.Count == 0 && noNavMeshCount < 20)
  44. {
  45. Create();
  46. }
  47. //Clear all the empty items
  48. if (enemies.Count > 0)
  49. {
  50. enemies.RemoveAll(item => item == null);
  51. }
  52. }
  53. /// <summary>
  54. /// Called when ZEDSpatialMapping begins making a new mesh, to clear existing enemies
  55. /// and prevent the script from trying to place enemies.
  56. /// Subscribed to ZEDSpatialMapping.OnMeshStarted in OnEnable().
  57. /// </summary>
  58. void StartNavMesh()
  59. {
  60. //Clear all the enemies
  61. Clear();
  62. isReady = false;
  63. }
  64. private void OnEnable()
  65. {
  66. NavMeshSurface.OnNavMeshReady += Ready;
  67. //Set the ZEDLight component on the object if a light is active
  68. Component[] lights = enemyPrefab.GetComponentsInChildren(typeof(Light));
  69. foreach (Light l in lights)
  70. {
  71. if (!l.gameObject.GetComponent<ZEDLight>())
  72. {
  73. l.gameObject.AddComponent<ZEDLight>();
  74. }
  75. }
  76. }
  77. private void Start()
  78. {
  79. StartNavMesh ();
  80. UnityEngine.AI.NavMeshAgent c;
  81. if ((c = enemyPrefab.GetComponent<UnityEngine.AI.NavMeshAgent>()) != null)
  82. {
  83. agentType = c.agentTypeID;
  84. }
  85. }
  86. private void OnDisable()
  87. {
  88. //Unsubscribe from the events.
  89. NavMeshSurface.OnNavMeshReady -= Ready;
  90. }
  91. /// <summary>
  92. /// Called when the NavMesh is finished being created, to clear existing data
  93. /// and begin trying to place the enemy.
  94. /// Subscribed to NavMeshSurface.OnNavMeshReady in OnEnable().
  95. /// </summary>
  96. /// <param name="sender"></param>
  97. /// <param name="e"></param>
  98. void Ready(object sender, NavMeshSurface.PositionEventArgs e)
  99. {
  100. centerNavMesh = e.position;
  101. isReady = e.valid;
  102. agentTypeNavMeshID = e.agentTypeID;
  103. Clear();
  104. }
  105. public void Ready()
  106. {
  107. isReady = true;
  108. Clear();
  109. }
  110. /// <summary>
  111. /// Destroy all the enemies and clear its container
  112. /// </summary>
  113. void Clear()
  114. {
  115. foreach (GameObject o in enemies)
  116. {
  117. Destroy(o);
  118. }
  119. enemies.Clear();
  120. }
  121. /// <summary>
  122. /// Remove a particular GameObject
  123. /// </summary>
  124. /// <param name="o"></param>
  125. static void Destroyed(GameObject o)
  126. {
  127. enemies.Remove(o);
  128. }
  129. /// <summary>
  130. /// Try to create an agent on the NavMesh.
  131. /// </summary>
  132. public void Create()
  133. {
  134. //If the agent and the NavMesh have different agent IDs, don't assign it.
  135. if (agentType != agentTypeNavMeshID)
  136. {
  137. Debug.LogWarning("The agent ID differs from the NavMesh");
  138. return;
  139. }
  140. //Instantiate the prefab and try to place it on the NavMesh.
  141. enemies.Add(Instantiate(enemyPrefab, centerNavMesh, Quaternion.identity));
  142. List<GameObject> notActivated = new List<GameObject>();
  143. //For each enemy created, move it on the NavMesh.
  144. foreach (GameObject o in enemies)
  145. {
  146. NavMeshAgentController a = o.GetComponent<NavMeshAgentController>();
  147. if (a.Move())
  148. {
  149. a.GetComponent<RandomWalk>().Activate();
  150. noNavMeshCount = 0;
  151. }
  152. else
  153. {
  154. notActivated.Add(a.gameObject);
  155. noNavMeshCount++;
  156. }
  157. }
  158. //Destroy any objects that were not properly added to the NavMesh.
  159. foreach (GameObject o in notActivated)
  160. {
  161. Destroy(o);
  162. enemies.Remove(o);
  163. }
  164. }
  165. }