RandomSelector.cs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. using UnityEngine;
  2. using System.Collections.Generic;
  3. namespace BehaviorDesigner.Runtime.Tasks
  4. {
  5. [TaskDescription("Similar to the selector task, the random selector task will return success as soon as a child task returns success. " +
  6. "The difference is that the random selector class will run its children in a random order. The selector task is deterministic " +
  7. "in that it will always run the tasks from left to right within the tree. The random selector task shuffles the child tasks up and then begins " +
  8. "execution in a random order. Other than that the random selector class is the same as the selector class. It will continue running tasks " +
  9. "until a task completes successfully. If no child tasks return success then it will return failure.")]
  10. [TaskIcon("{SkinColor}RandomSelectorIcon.png")]
  11. public class RandomSelector : Composite
  12. {
  13. [Tooltip("Seed the random number generator to make things easier to debug")]
  14. public int seed = 0;
  15. [Tooltip("Do we want to use the seed?")]
  16. public bool useSeed = false;
  17. // A list of indexes of every child task. This list is used by the Fischer-Yates shuffle algorithm.
  18. private List<int> childIndexList = new List<int>();
  19. // The random child index execution order.
  20. private Stack<int> childrenExecutionOrder = new Stack<int>();
  21. // The task status of the last child ran.
  22. private TaskStatus executionStatus = TaskStatus.Inactive;
  23. public override void OnAwake()
  24. {
  25. // If specified, use the seed provided.
  26. if (useSeed) {
  27. Random.InitState(seed);
  28. }
  29. // Add the index of each child to a list to make the Fischer-Yates shuffle possible.
  30. childIndexList.Clear();
  31. for (int i = 0; i < children.Count; ++i) {
  32. childIndexList.Add(i);
  33. }
  34. }
  35. public override void OnStart()
  36. {
  37. // Randomize the indecies
  38. ShuffleChilden();
  39. }
  40. public override int CurrentChildIndex()
  41. {
  42. // Peek will return the index at the top of the stack.
  43. return childrenExecutionOrder.Peek();
  44. }
  45. public override bool CanExecute()
  46. {
  47. // Continue exectuion if no task has return success and indexes still exist on the stack.
  48. return childrenExecutionOrder.Count > 0 && executionStatus != TaskStatus.Success;
  49. }
  50. public override void OnChildExecuted(TaskStatus childStatus)
  51. {
  52. // Pop the top index from the stack and set the execution status.
  53. if (childrenExecutionOrder.Count > 0) {
  54. childrenExecutionOrder.Pop();
  55. }
  56. executionStatus = childStatus;
  57. }
  58. public override void OnConditionalAbort(int childIndex)
  59. {
  60. // Start from the beginning on an abort
  61. childrenExecutionOrder.Clear();
  62. executionStatus = TaskStatus.Inactive;
  63. ShuffleChilden();
  64. }
  65. public override void OnEnd()
  66. {
  67. // All of the children have run. Reset the variables back to their starting values.
  68. executionStatus = TaskStatus.Inactive;
  69. childrenExecutionOrder.Clear();
  70. }
  71. public override void OnReset()
  72. {
  73. // Reset the public properties back to their original values
  74. seed = 0;
  75. useSeed = false;
  76. }
  77. private void ShuffleChilden()
  78. {
  79. // Use Fischer-Yates shuffle to randomize the child index order.
  80. for (int i = childIndexList.Count; i > 0; --i) {
  81. int j = Random.Range(0, i);
  82. int index = childIndexList[j];
  83. childrenExecutionOrder.Push(index);
  84. childIndexList[j] = childIndexList[i - 1];
  85. childIndexList[i - 1] = index;
  86. }
  87. }
  88. }
  89. }