RandomSequence.cs 4.1 KB

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