ExitEvent.cs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. // Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 Kybernetik //
  2. using System;
  3. namespace Animancer
  4. {
  5. /// <summary>[Pro-Only]
  6. /// A callback to be triggered after an <see cref="AnimancerNode"/>
  7. /// either starts or finishes fading out to 0 <see cref="AnimancerNode.EffectiveWeight"/>.
  8. /// </summary>
  9. ///
  10. /// <remarks>
  11. /// The <see cref="AnimancerNode.EffectiveWeight"/> is only checked at the end of the animation update
  12. /// so if it's set multiple times in the same frame then the callback might not be triggered.
  13. /// <para></para>
  14. /// Most <see href="https://kybernetik.com.au/animancer/docs/manual/fsm">Finite State Machine</see>
  15. /// systems already have their own mechanism for notifying your code when a state is exited
  16. /// so this system is generally only useful when something like that is not already available.
  17. /// <para></para>
  18. /// <strong>Example:</strong> see the <see cref="ExitEvent(AnimancerNode, Action, bool)"/> constructor.
  19. /// </remarks>
  20. ///
  21. /// https://kybernetik.com.au/animancer/api/Animancer/ExitEvent
  22. ///
  23. public class ExitEvent : Updatable
  24. {
  25. /************************************************************************************************************************/
  26. private Action _Callback;
  27. /// <summary>The method to invoke when this event is triggered.</summary>
  28. public Action Callback
  29. {
  30. get => _Callback;
  31. set
  32. {
  33. _Callback = value;
  34. if (_Callback != null)
  35. EnableIfActive();
  36. else
  37. Disable();
  38. }
  39. }
  40. /************************************************************************************************************************/
  41. private AnimancerNode _Node;
  42. /// <summary>The target node which determines when to trigger this event.</summary>
  43. public AnimancerNode Node
  44. {
  45. get => _Node;
  46. set
  47. {
  48. _Node = value;
  49. if (_Node != null)
  50. EnableIfActive();
  51. else
  52. Disable();
  53. }
  54. }
  55. /************************************************************************************************************************/
  56. /// <summary>
  57. /// Should the <see cref="Callback"/> be invoked when the <see cref="Node"/> starts fading out?
  58. /// Otherwise, it will be invoked after the <see cref="AnimancerNode.EffectiveWeight"/> reaches 0.
  59. /// Default is <c>false</c>.
  60. /// </summary>
  61. public bool InvokeOnStartExiting { get; set; }
  62. /************************************************************************************************************************/
  63. /// <summary>Creates a new <see cref="ExitEvent"/>.</summary>
  64. ///
  65. /// <remarks>
  66. /// <strong>Example:</strong><code>
  67. /// private ExitEvent _OnStateExited;
  68. ///
  69. /// void ExitEventExample(AnimancerComponent animancer, AnimationClip clip)
  70. /// {
  71. /// var state = animancer.Play(clip);
  72. ///
  73. /// // One line initialization:
  74. /// (_OnClipExit ??= new(state, OnStateExited)).Enable();
  75. ///
  76. /// // Or two lines:
  77. /// _OnClipExit ??= new(state, OnStateExited);
  78. /// _OnClipExit.Enable();
  79. /// }
  80. ///
  81. /// private void OnStateExited()
  82. /// {
  83. /// Debug.Log(_OnClipExit.State + " Exited");
  84. /// }
  85. /// </code></remarks>
  86. ///
  87. public ExitEvent(
  88. AnimancerNode node,
  89. Action callback,
  90. bool invokeOnStartExiting = false)
  91. {
  92. _Node = node;
  93. _Callback = Callback;
  94. InvokeOnStartExiting = invokeOnStartExiting;
  95. }
  96. /************************************************************************************************************************/
  97. /// <summary>Registers this event to start receiving updates.</summary>
  98. public void Enable()
  99. {
  100. if (_Callback != null)
  101. _Node?.Graph?.RequirePostUpdate(this);
  102. }
  103. /// <summary>
  104. /// Registers this event to start receiving updates if the
  105. /// <see cref="AnimancerNode.TargetWeight"/> is above 0 (i.e. it's not fading out).
  106. /// </summary>
  107. public void EnableIfActive()
  108. {
  109. if (_Callback != null &&
  110. _Node != null &&
  111. _Node.Graph != null &&
  112. _Node.TargetWeight > 0)
  113. _Node.Graph.RequirePostUpdate(this);
  114. }
  115. /************************************************************************************************************************/
  116. /// <summary>Cancels this event to stop receiving updates.</summary>
  117. public void Disable()
  118. {
  119. _Node?.Graph?.CancelPostUpdate(this);
  120. }
  121. /************************************************************************************************************************/
  122. /// <inheritdoc/>
  123. public override void Update()
  124. {
  125. if (!_Node.IsValid())
  126. return;
  127. if (InvokeOnStartExiting)
  128. {
  129. if (_Node.TargetWeight != 0)
  130. return;
  131. }
  132. else
  133. {
  134. if (_Node.EffectiveWeight > 0)
  135. return;
  136. }
  137. _Callback();
  138. Disable();
  139. }
  140. /************************************************************************************************************************/
  141. }
  142. }