WanderingAI.cs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. using System.Collections.Generic;
  2. using UnityEngine;
  3. using UnityEngine.AI;
  4. [DefaultExecutionOrder(10)]
  5. [RequireComponent(typeof(InstantiatePrefab))]
  6. public class WanderingAI : MonoBehaviour
  7. {
  8. [Header("Only for Debugging (do not set from here)")]
  9. public Transform[] waypoints;
  10. public List<Transform> waypointsList;
  11. public float[] wanderTimer;
  12. [Header("Scattering around the target")]
  13. public float targetScattering = 5.0f; //Streuung
  14. [Header("Leave Settings")]
  15. public float leaveTimer = 120f;
  16. public Vector3 leavePosition;
  17. // Leave Settings
  18. private float offsetx = 0;
  19. private float offsetz = 0;
  20. private int inRow = 4; // incl 0 - 4
  21. private float[] timer;
  22. private float globalTimer;
  23. private bool leaveMarket = false;
  24. private Vector3[][] target;
  25. private int[][] humansPrio;
  26. // Settings WP and Waiting time
  27. private int maxWPCount;
  28. private List<List<int>> waitingTimer;
  29. private List<int> waitingList;
  30. private float[] currentWait;
  31. private int countFilling = 0;
  32. private GameObject[][] humansGO;
  33. private NavMeshAgent[][] humansNMA;
  34. private Animator[][] humansA;
  35. private const string isWalking = "isWalking";
  36. // Use this for initialization
  37. void Start()
  38. {
  39. // Get initialized Variables from InstantiatePrefab
  40. humansGO = gameObject.GetComponent<InstantiatePrefab>().humanGameObject;
  41. humansNMA = gameObject.GetComponent<InstantiatePrefab>().humanNavMeshAgent;
  42. humansA = gameObject.GetComponent<InstantiatePrefab>().humanAnimator;
  43. wanderTimer = gameObject.GetComponent<InstantiatePrefab>().wanderTimer;
  44. //waitingTimer = gameObject.GetComponent<InstantiatePrefab>().waitingTimer;
  45. waypoints = gameObject.GetComponent<InstantiatePrefab>().waypointsArray;
  46. humansPrio = gameObject.GetComponent<InstantiatePrefab>().humanPriorities;
  47. // Set length of variables to humanGo.Length
  48. target = new Vector3[humansGO.Length][];
  49. timer = new float[humansGO.Length];
  50. waypointsList = new List<Transform>(waypoints);
  51. maxWPCount = waypointsList.Count;
  52. waitingTimer = new List<List<int>>(gameObject.GetComponent<InstantiatePrefab>().waitingTimer);
  53. waitingList = new List<int>(waitingTimer[0]);
  54. currentWait = new float[humansGO.Length];
  55. // Initialize size and content
  56. for (int i = 0; i < humansGO.Length; i++)
  57. {
  58. target[i] = new Vector3[humansGO[i].Length];
  59. timer[i] = 0;
  60. }
  61. globalTimer = 0;
  62. }
  63. private void FixedUpdate()
  64. {
  65. if(globalTimer >= leaveTimer)
  66. leaveMarket = true;
  67. for (int i = 0; i < humansGO.Length; ++i)
  68. {
  69. if (waypoints.Length == 0) return;
  70. if (timer[i] >= currentWait[i])
  71. {
  72. for (int j = 0; j < humansGO[i].Length; ++j)
  73. {
  74. if (target[i][j] == Vector3.zero ||
  75. humansNMA[i][j].velocity.magnitude <= 0.01f ||
  76. humansNMA[i][j].remainingDistance <= humansNMA[i][j].stoppingDistance ||
  77. humansNMA[i][j].pathStatus == NavMeshPathStatus.PathComplete ||
  78. !humansNMA[i][j].hasPath)
  79. {
  80. if (maxWPCount <= 0) maxWPCount = waypointsList.Count;
  81. int currentWPIndex = Random.Range(0, maxWPCount);
  82. target[i][j] = CheckTarget(waypointsList[currentWPIndex].transform.position, targetScattering);
  83. int currentWaitingIndex = Random.Range(0, waitingTimer[currentWPIndex].Count);
  84. currentWait[i] = waitingTimer[currentWPIndex][currentWaitingIndex];
  85. RemoveIndexFromWaitingTimer(currentWPIndex, currentWaitingIndex);
  86. // fill waiting Timer, bc preparation for next iteration
  87. if (waitingTimer[i].Count <= 0)
  88. {
  89. waitingTimer[i] = new List<int>(waitingList);
  90. countFilling++;
  91. }
  92. if (target[i][0].x != float.PositiveInfinity)
  93. {
  94. if (humansNMA[i][j].isActiveAndEnabled)
  95. humansNMA[i][j].SetDestination(target[i][j]);
  96. humansA[i][j].SetBool(isWalking, humansNMA[i][j].velocity.magnitude > 0.01f);
  97. }
  98. // remove from list to ensure that all WP are visited at the frequency indicated; if list empty fill list with initial WPs
  99. AppendIndexToEndWP(currentWPIndex);
  100. AppendIndexToEndWT(currentWPIndex);
  101. maxWPCount--;
  102. timer[i] = 0;
  103. }
  104. }
  105. }
  106. else
  107. {
  108. for (int j = 0; j < humansGO[i].Length; ++j)
  109. {
  110. humansA[i][j].SetBool(isWalking, humansNMA[i][j].velocity.magnitude > 0.01f);
  111. if (humansNMA[i][j].remainingDistance <= humansNMA[i][j].stoppingDistance)
  112. timer[i] += Time.deltaTime;
  113. // if humans are not walking, then set priority to 0 so that the other humans dont disturb them
  114. if (humansNMA[i][j].velocity.magnitude <= 0.01f)
  115. {
  116. humansNMA[i][j].avoidancePriority = 0;
  117. }
  118. else
  119. humansNMA[i][j].avoidancePriority = humansPrio[i][j];
  120. }
  121. }
  122. }
  123. globalTimer += Time.deltaTime;
  124. }
  125. public static Vector3 CheckTarget(Vector3 target, float dist)
  126. {
  127. Vector3 modifiedTarget = Random.insideUnitSphere * dist + target;
  128. // SamplePosition also checks the y axis. However, this is not relevant for me, so valid positions (x & z) are also discarded.
  129. // 0.0f is the only valid entry for y
  130. modifiedTarget = new Vector3(modifiedTarget.x, 0f, modifiedTarget.z);
  131. NavMeshHit navHit;
  132. NavMesh.SamplePosition(modifiedTarget, out navHit, 1.0f, -1);
  133. return navHit.position;
  134. }
  135. public void AppendIndexToEndWP(int index)
  136. {
  137. waypointsList.Add(waypointsList[index]);
  138. waypointsList.RemoveAt(index);
  139. }
  140. public void AppendIndexToEndWT(int index)
  141. {
  142. waitingTimer.Add(waitingTimer[index]);
  143. waitingTimer.RemoveAt(index);
  144. }
  145. public void RemoveIndexFromWaitingTimer(int i, int removeIndex)
  146. {
  147. waitingTimer[i].RemoveAt(removeIndex);
  148. }
  149. public void LeaveMarket(int i)
  150. {
  151. for (int j = 0; j < humansGO[i].Length; ++j)
  152. {
  153. target[i][j] = new Vector3(leavePosition.x + offsetx, 0, leavePosition.z + offsetz);
  154. // Calculate offset
  155. if (offsetz < inRow * 2)
  156. offsetz += 2;
  157. else
  158. {
  159. offsetz = 0;
  160. offsetx += 2;
  161. }
  162. }
  163. }
  164. private void LateUpdate()
  165. {
  166. for (int i = 0; i < humansGO.Length; ++i)
  167. {
  168. for (int j = 0; j < humansGO[i].Length; ++j)
  169. {
  170. humansA[i][j].speed = 0.5f + (humansNMA[i][j].velocity.magnitude / gameObject.GetComponent<InstantiatePrefab>().speedMinMax.y);
  171. }
  172. }
  173. }
  174. }