StateGraph.cs 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using UnityEngine;
  5. namespace Unity.VisualScripting
  6. {
  7. [SerializationVersion("A")]
  8. public sealed class StateGraph : Graph, IGraphEventListener
  9. {
  10. public StateGraph()
  11. {
  12. states = new GraphElementCollection<IState>(this);
  13. transitions = new GraphConnectionCollection<IStateTransition, IState, IState>(this);
  14. groups = new GraphElementCollection<GraphGroup>(this);
  15. elements.Include(states);
  16. elements.Include(transitions);
  17. elements.Include(groups);
  18. }
  19. public override IGraphData CreateData()
  20. {
  21. return new StateGraphData(this);
  22. }
  23. public void StartListening(GraphStack stack)
  24. {
  25. stack.GetGraphData<StateGraphData>().isListening = true;
  26. var activeStates = GetActiveStatesNoAlloc(stack);
  27. foreach (var state in activeStates)
  28. {
  29. (state as IGraphEventListener)?.StartListening(stack);
  30. }
  31. activeStates.Free();
  32. }
  33. public void StopListening(GraphStack stack)
  34. {
  35. var activeStates = GetActiveStatesNoAlloc(stack);
  36. foreach (var state in activeStates)
  37. {
  38. (state as IGraphEventListener)?.StopListening(stack);
  39. }
  40. activeStates.Free();
  41. stack.GetGraphData<StateGraphData>().isListening = false;
  42. }
  43. public bool IsListening(GraphPointer pointer)
  44. {
  45. return pointer.GetGraphData<StateGraphData>().isListening;
  46. }
  47. #region Elements
  48. [DoNotSerialize]
  49. public GraphElementCollection<IState> states { get; internal set; }
  50. [DoNotSerialize]
  51. public GraphConnectionCollection<IStateTransition, IState, IState> transitions { get; internal set; }
  52. [DoNotSerialize]
  53. public GraphElementCollection<GraphGroup> groups { get; internal set; }
  54. #endregion
  55. #region Lifecycle
  56. // Active state detection happens twice:
  57. //
  58. // 1. Before the enumeration, because any state
  59. // that becomes active during an update shouldn't
  60. // be updated until the next update
  61. //
  62. // 2. Inside the update method, because a state
  63. // that was active during enumeration and no longer
  64. // is shouldn't be updated.
  65. private HashSet<IState> GetActiveStatesNoAlloc(GraphPointer pointer)
  66. {
  67. var activeStates = HashSetPool<IState>.New();
  68. foreach (var state in states)
  69. {
  70. var stateData = pointer.GetElementData<State.Data>(state);
  71. if (stateData.isActive)
  72. {
  73. activeStates.Add(state);
  74. }
  75. }
  76. return activeStates;
  77. }
  78. public void Start(Flow flow)
  79. {
  80. flow.stack.GetGraphData<StateGraphData>().isListening = true;
  81. foreach (var state in states.Where(s => s.isStart))
  82. {
  83. try
  84. {
  85. state.OnEnter(flow, StateEnterReason.Start);
  86. }
  87. catch (Exception ex)
  88. {
  89. state.HandleException(flow.stack, ex);
  90. throw;
  91. }
  92. }
  93. }
  94. public void Stop(Flow flow)
  95. {
  96. var activeStates = GetActiveStatesNoAlloc(flow.stack);
  97. foreach (var state in activeStates)
  98. {
  99. try
  100. {
  101. state.OnExit(flow, StateExitReason.Stop);
  102. }
  103. catch (Exception ex)
  104. {
  105. state.HandleException(flow.stack, ex);
  106. throw;
  107. }
  108. }
  109. activeStates.Free();
  110. flow.stack.GetGraphData<StateGraphData>().isListening = false;
  111. }
  112. #endregion
  113. public static StateGraph WithStart()
  114. {
  115. var stateGraph = new StateGraph();
  116. var startState = FlowState.WithEnterUpdateExit();
  117. startState.isStart = true;
  118. startState.nest.embed.title = "Start";
  119. startState.position = new Vector2(-86, -15);
  120. stateGraph.states.Add(startState);
  121. return stateGraph;
  122. }
  123. }
  124. }