BehaviorSelection.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Text.RegularExpressions;
  5. using BehaviorDesigner.Runtime;
  6. public class BehaviorSelection : MonoBehaviour
  7. {
  8. public GameObject marker;
  9. public GameObject mainBot;
  10. public GameObject flockGroup;
  11. public GameObject followGroup;
  12. public GameObject queueGroup;
  13. public GameObject[] waypoints;
  14. public GameObject[] waypointsA;
  15. public GUISkin descriptionGUISkin;
  16. private Vector3[] flockGroupPosition;
  17. private Vector3[] followGroupPosition;
  18. private Vector3[] queueGroupPosition;
  19. private Quaternion[] flockGroupRotation;
  20. private Quaternion[] followGroupRotation;
  21. private Quaternion[] queueGroupRotation;
  22. private Dictionary<int, BehaviorTree> behaviorTreeGroup = new Dictionary<int, BehaviorTree>();
  23. private enum BehaviorSelectionType { MoveTowards, RotateTowards, Seek, Flee, Pursue, Evade, Patrol, Cover, Wander, Search, WithinDistance, CanSeeObject, CanHearObject, Flock, LeaderFollow, Queue, Last }
  24. private BehaviorSelectionType selectionType = BehaviorSelectionType.MoveTowards;
  25. private BehaviorSelectionType prevSelectionType = BehaviorSelectionType.MoveTowards;
  26. public void Start()
  27. {
  28. var behaviorTrees = mainBot.GetComponents<BehaviorTree>();
  29. for (int i = 0; i < behaviorTrees.Length; ++i) {
  30. behaviorTreeGroup.Add(behaviorTrees[i].Group, behaviorTrees[i]);
  31. }
  32. behaviorTrees = Camera.main.GetComponents<BehaviorTree>();
  33. for (int i = 0; i < behaviorTrees.Length; ++i) {
  34. behaviorTreeGroup.Add(behaviorTrees[i].Group, behaviorTrees[i]);
  35. }
  36. flockGroupPosition = new Vector3[flockGroup.transform.childCount];
  37. flockGroupRotation = new Quaternion[flockGroup.transform.childCount];
  38. for (int i = 0; i < flockGroup.transform.childCount; ++i) {
  39. flockGroup.transform.GetChild(i).gameObject.SetActive(false);
  40. flockGroupPosition[i] = flockGroup.transform.GetChild(i).transform.position;
  41. flockGroupRotation[i] = flockGroup.transform.GetChild(i).transform.rotation;
  42. }
  43. followGroupPosition = new Vector3[followGroup.transform.childCount];
  44. followGroupRotation = new Quaternion[followGroup.transform.childCount];
  45. for (int i = 0; i < followGroup.transform.childCount; ++i) {
  46. followGroup.transform.GetChild(i).gameObject.SetActive(false);
  47. followGroupPosition[i] = followGroup.transform.GetChild(i).transform.position;
  48. followGroupRotation[i] = followGroup.transform.GetChild(i).transform.rotation;
  49. }
  50. queueGroupPosition = new Vector3[queueGroup.transform.childCount];
  51. queueGroupRotation = new Quaternion[queueGroup.transform.childCount];
  52. for (int i = 0; i < queueGroup.transform.childCount; ++i) {
  53. queueGroup.transform.GetChild(i).gameObject.SetActive(false);
  54. queueGroupPosition[i] = queueGroup.transform.GetChild(i).transform.position;
  55. queueGroupRotation[i] = queueGroup.transform.GetChild(i).transform.rotation;
  56. }
  57. SelectionChanged();
  58. }
  59. public void OnGUI()
  60. {
  61. GUILayout.BeginVertical(GUILayout.Width(300));
  62. GUILayout.BeginHorizontal();
  63. if (GUILayout.Button("<-")) {
  64. prevSelectionType = selectionType;
  65. selectionType = (BehaviorSelectionType)(((int)selectionType - 1) % (int)BehaviorSelectionType.Last);
  66. if ((int)selectionType < 0) selectionType = BehaviorSelectionType.Queue;
  67. SelectionChanged();
  68. }
  69. GUILayout.Box(SplitCamelCase(selectionType.ToString()), GUILayout.Width(220));
  70. if (GUILayout.Button("->")) {
  71. prevSelectionType = selectionType;
  72. selectionType = (BehaviorSelectionType)(((int)selectionType + 1) % (int)BehaviorSelectionType.Last);
  73. SelectionChanged();
  74. }
  75. GUILayout.EndHorizontal();
  76. GUILayout.Box(Description(), descriptionGUISkin.box);
  77. if (selectionType == BehaviorSelectionType.CanHearObject) {
  78. if (GUILayout.Button("Play Sound")) {
  79. marker.GetComponent<AudioSource>().Play();
  80. }
  81. }
  82. GUILayout.EndVertical();
  83. }
  84. private string Description()
  85. {
  86. string desc = "";
  87. switch (selectionType) {
  88. case BehaviorSelectionType.MoveTowards:
  89. desc = "The Move Towards task will move the agent towards the target (without pathfinding). In this example the green agent is moving towards the red dot.";
  90. break;
  91. case BehaviorSelectionType.RotateTowards:
  92. desc = "The Rotate Towards task rotate the agent towards the target. In this example the green agent is rotating towards the red dot.";
  93. break;
  94. case BehaviorSelectionType.Seek:
  95. desc = "The Seek task will move the agent towards the target with pathfinding. In this example the green agent is seeking the red dot (which moves).";
  96. break;
  97. case BehaviorSelectionType.Flee:
  98. desc = "The Flee task will move the agent away from the target with pathfinding. In this example the green agent is fleeing from red dot (which moves).";
  99. break;
  100. case BehaviorSelectionType.Pursue:
  101. desc = "The Pursue task is similar to the Seek task except the Pursue task predicts where the target is going to be in the future. This allows the agent to arrive at the target earlier than it would have with the Seek task.";
  102. break;
  103. case BehaviorSelectionType.Evade:
  104. desc = "The Evade task is similar to the Flee task except the Evade task predicts where the target is going to be in the future. This allows the agent to flee from the target earlier than it would have with the Flee task.";
  105. break;
  106. case BehaviorSelectionType.Patrol:
  107. desc = "The Patrol task moves from waypoint to waypint. In this example the green agent is patrolling with four different waypoints (the white dots).";
  108. break;
  109. case BehaviorSelectionType.Cover:
  110. desc = "The Cover task will move the agent into cover from its current position. In this example the agent sees cover in front of it so takes cover behind the wall.";
  111. break;
  112. case BehaviorSelectionType.Wander:
  113. desc = "The Wander task moves the agent randomly throughout the map with pathfinding.";
  114. break;
  115. case BehaviorSelectionType.Search:
  116. desc = "The Search task will search the map by wandering until it finds the target. It can find the target by seeing or hearing the target. In this example the Search task is looking for the red dot.";
  117. break;
  118. case BehaviorSelectionType.WithinDistance:
  119. desc = "The Within Distance task is a conditional task that returns success when another object comes within distance of the current agent. In this example the Within Distance task is paired with the Seek task so the agent will move towards the target as soon as the target within distance.";
  120. break;
  121. case BehaviorSelectionType.CanSeeObject:
  122. desc = "The Can See Object task is a conditional task that returns success when it sees an object in front of the current agent. In this example the Can See Object task is paired with the Seek task so the agent will move towards the target as soon as the target is seen.";
  123. break;
  124. case BehaviorSelectionType.CanHearObject:
  125. desc = "The Can Hear Object task is a conditional task that returns success when it hears another object. Press the \"Play\" button to emit a sound from the red dot. If the red dot is within range of the agent when the sound is played then the agent will move towards the red dot with the Seek task.";
  126. break;
  127. case BehaviorSelectionType.Flock:
  128. desc = "The Flock task moves a group of objects together in a pattern (which can be adjusted). In this example the Flock task is controlling all 30 objects. There are no colliders on the objects - the Flock task is completing managing the position of all of the objects";
  129. break;
  130. case BehaviorSelectionType.LeaderFollow:
  131. desc = "The Leader Follow task moves a group of objects behind a leader object. There are two behavior trees running in this example - one for the leader (who is patrolling the area) and one for the group of objects. Again, there is are no colliders on the objects.";
  132. break;
  133. case BehaviorSelectionType.Queue:
  134. desc = "The Queue task will move a group of objects through a small space in an organized way. In this example the Queue task is controlling all of the objects. Another way to move all of the objects through the doorway is with the seek task, however with this approach the objects would group up at the doorway.";
  135. break;
  136. }
  137. return desc;
  138. }
  139. private static string SplitCamelCase(string s)
  140. {
  141. var r = new Regex(@"(?<=[A-Z])(?=[A-Z][a-z])|(?<=[^A-Z])(?=[A-Z])|(?<=[A-Za-z])(?=[^A-Za-z])", RegexOptions.IgnorePatternWhitespace);
  142. s = r.Replace(s, " ");
  143. return (char.ToUpper(s[0]) + s.Substring(1)).Trim();
  144. }
  145. private void SelectionChanged()
  146. {
  147. DisableAll();
  148. switch (selectionType) {
  149. case BehaviorSelectionType.MoveTowards:
  150. marker.transform.position = new Vector3(20, 1, -20);
  151. marker.SetActive(true);
  152. mainBot.transform.position = new Vector3(-20, 1, -20);
  153. mainBot.transform.eulerAngles = new Vector3(0, 180, 0);
  154. mainBot.SetActive(true);
  155. break;
  156. case BehaviorSelectionType.RotateTowards:
  157. marker.transform.position = new Vector3(20, 1, 10);
  158. marker.SetActive(true);
  159. mainBot.transform.position = new Vector3(0, 1, -20);
  160. mainBot.transform.eulerAngles = new Vector3(0, 180, 0);
  161. mainBot.SetActive(true);
  162. break;
  163. case BehaviorSelectionType.Seek:
  164. marker.transform.position = new Vector3(20, 1, 20);
  165. marker.SetActive(true);
  166. marker.GetComponent<Animation>()["MarkerSeek"].time = 0;
  167. marker.GetComponent<Animation>()["MarkerSeek"].speed = 1;
  168. marker.GetComponent<Animation>().Play("MarkerSeek");
  169. mainBot.transform.position = new Vector3(-20, 1, -20);
  170. mainBot.transform.eulerAngles = new Vector3(0, 180, 0);
  171. mainBot.SetActive(true);
  172. break;
  173. case BehaviorSelectionType.Flee:
  174. marker.transform.position = new Vector3(20, 1, 20);
  175. marker.SetActive(true);
  176. marker.GetComponent<Animation>()["MarkerFlee"].time = 0;
  177. marker.GetComponent<Animation>()["MarkerFlee"].speed = 1;
  178. marker.GetComponent<Animation>().Play("MarkerFlee");
  179. mainBot.transform.position = new Vector3(10, 1, 18);
  180. mainBot.transform.eulerAngles = new Vector3(0, 180, 0);
  181. mainBot.SetActive(true);
  182. break;
  183. case BehaviorSelectionType.Pursue:
  184. marker.transform.position = new Vector3(20, 1, 20);
  185. marker.SetActive(true);
  186. marker.GetComponent<Animation>()["MarkerPersue"].time = 0;
  187. marker.GetComponent<Animation>()["MarkerPersue"].speed = 1;
  188. marker.GetComponent<Animation>().Play("MarkerPersue");
  189. mainBot.transform.position = new Vector3(-20, 1, 0);
  190. mainBot.transform.eulerAngles = new Vector3(0, 90, 0);
  191. mainBot.SetActive(true);
  192. break;
  193. case BehaviorSelectionType.Evade:
  194. marker.transform.position = new Vector3(20, 1, 20);
  195. marker.SetActive(true);
  196. marker.GetComponent<Animation>()["MarkerEvade"].time = 0;
  197. marker.GetComponent<Animation>()["MarkerEvade"].speed = 1;
  198. marker.GetComponent<Animation>().Play("MarkerEvade");
  199. mainBot.transform.position = new Vector3(0, 1, 18);
  200. mainBot.transform.eulerAngles = new Vector3(0, 180, 0);
  201. mainBot.SetActive(true);
  202. break;
  203. case BehaviorSelectionType.Patrol:
  204. for (int i = 0; i < waypoints.Length; ++i) {
  205. waypoints[i].SetActive(true);
  206. }
  207. mainBot.transform.position = new Vector3(-20, 1, 20);
  208. mainBot.transform.eulerAngles = new Vector3(0, 180, 0);
  209. mainBot.SetActive(true);
  210. break;
  211. case BehaviorSelectionType.Cover:
  212. mainBot.transform.position = new Vector3(-5, 1, -10);
  213. mainBot.transform.eulerAngles = new Vector3(0, 0, 0);
  214. mainBot.SetActive(true);
  215. break;
  216. case BehaviorSelectionType.Wander:
  217. mainBot.transform.position = new Vector3(-20, 1, -20);
  218. mainBot.transform.eulerAngles = new Vector3(0, 0, 0);
  219. mainBot.SetActive(true);
  220. break;
  221. case BehaviorSelectionType.Search:
  222. marker.transform.position = new Vector3(20, 1, 20);
  223. marker.SetActive(true);
  224. mainBot.transform.position = new Vector3(-20, 1, -20);
  225. mainBot.transform.eulerAngles = new Vector3(0, 0, 0);
  226. mainBot.SetActive(true);
  227. break;
  228. case BehaviorSelectionType.WithinDistance:
  229. marker.transform.position = new Vector3(20, 1, 20);
  230. marker.GetComponent<Animation>()["MarkerPersue"].time = 0;
  231. marker.GetComponent<Animation>()["MarkerPersue"].speed = 1;
  232. marker.GetComponent<Animation>().Play("MarkerPersue");
  233. marker.SetActive(true);
  234. mainBot.transform.position = new Vector3(-15, 1, 2);
  235. mainBot.transform.eulerAngles = new Vector3(0, 0, 0);
  236. mainBot.SetActive(true);
  237. break;
  238. case BehaviorSelectionType.CanSeeObject:
  239. marker.transform.position = new Vector3(20, 1, 20);
  240. marker.GetComponent<Animation>()["MarkerPersue"].time = 0;
  241. marker.GetComponent<Animation>()["MarkerPersue"].speed = 1;
  242. marker.GetComponent<Animation>().Play("MarkerPersue");
  243. marker.SetActive(true);
  244. mainBot.transform.position = new Vector3(-15, 1, -10);
  245. mainBot.transform.eulerAngles = new Vector3(0, 0, 0);
  246. mainBot.SetActive(true);
  247. break;
  248. case BehaviorSelectionType.CanHearObject:
  249. marker.transform.position = new Vector3(20, 1, 20);
  250. marker.GetComponent<Animation>()["MarkerPersue"].time = 0;
  251. marker.GetComponent<Animation>()["MarkerPersue"].speed = 1;
  252. marker.GetComponent<Animation>().Play("MarkerPersue");
  253. marker.SetActive(true);
  254. mainBot.transform.position = new Vector3(-15, 1, -10);
  255. mainBot.transform.eulerAngles = new Vector3(0, 0, 0);
  256. mainBot.SetActive(true);
  257. break;
  258. case BehaviorSelectionType.Flock:
  259. Camera.main.transform.position = new Vector3(0, 90, -150);
  260. for (int i = 0; i < flockGroup.transform.childCount; ++i) {
  261. flockGroup.transform.GetChild(i).gameObject.SetActive(true);
  262. }
  263. break;
  264. case BehaviorSelectionType.LeaderFollow:
  265. for (int i = 0; i < waypointsA.Length; ++i) {
  266. waypointsA[i].SetActive(true);
  267. }
  268. mainBot.transform.position = new Vector3(0, 1, -130);
  269. mainBot.SetActive(true);
  270. Camera.main.transform.position = new Vector3(0, 90, -150);
  271. for (int i = 0; i < followGroup.transform.childCount; ++i) {
  272. followGroup.transform.GetChild(i).gameObject.SetActive(true);
  273. }
  274. break;
  275. case BehaviorSelectionType.Queue:
  276. marker.transform.position = new Vector3(45, 1, 0);
  277. for (int i = 0; i < queueGroup.transform.childCount; ++i) {
  278. queueGroup.transform.GetChild(i).gameObject.SetActive(true);
  279. }
  280. break;
  281. }
  282. StartCoroutine("EnableBehavior");
  283. }
  284. private void DisableAll()
  285. {
  286. StopCoroutine("EnableBehavior");
  287. behaviorTreeGroup[(int)prevSelectionType].DisableBehavior();
  288. // enable the leader as well
  289. if (prevSelectionType == BehaviorSelectionType.LeaderFollow) {
  290. behaviorTreeGroup[(int)BehaviorSelectionType.Last].DisableBehavior();
  291. }
  292. marker.GetComponent<Animation>().Stop();
  293. marker.SetActive(false);
  294. mainBot.SetActive(false);
  295. Camera.main.transform.position = new Vector3(0, 90, 0);
  296. for (int i = 0; i < flockGroup.transform.childCount; ++i) {
  297. flockGroup.transform.GetChild(i).gameObject.SetActive(false);
  298. flockGroup.transform.GetChild(i).transform.position = flockGroupPosition[i];
  299. flockGroup.transform.GetChild(i).transform.rotation = flockGroupRotation[i];
  300. }
  301. for (int i = 0; i < followGroup.transform.childCount; ++i) {
  302. followGroup.transform.GetChild(i).gameObject.SetActive(false);
  303. followGroup.transform.GetChild(i).transform.position = followGroupPosition[i];
  304. followGroup.transform.GetChild(i).transform.rotation = followGroupRotation[i];
  305. }
  306. for (int i = 0; i < queueGroup.transform.childCount; ++i) {
  307. queueGroup.transform.GetChild(i).gameObject.SetActive(false);
  308. queueGroup.transform.GetChild(i).transform.position = queueGroupPosition[i];
  309. queueGroup.transform.GetChild(i).transform.rotation = queueGroupRotation[i];
  310. }
  311. for (int i = 0; i < waypoints.Length; ++i) {
  312. waypoints[i].SetActive(false);
  313. }
  314. for (int i = 0; i < waypointsA.Length; ++i) {
  315. waypointsA[i].SetActive(false);
  316. }
  317. }
  318. private IEnumerator EnableBehavior()
  319. {
  320. yield return new WaitForSeconds(0.5f);
  321. behaviorTreeGroup[(int)selectionType].EnableBehavior();
  322. // enable the leader as well
  323. if (selectionType == BehaviorSelectionType.LeaderFollow) {
  324. behaviorTreeGroup[(int)BehaviorSelectionType.Last].EnableBehavior();
  325. }
  326. }
  327. }