WaitForSpineEvent.cs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. /******************************************************************************
  2. * Spine Runtimes License Agreement
  3. * Last updated January 1, 2020. Replaces all prior versions.
  4. *
  5. * Copyright (c) 2013-2020, Esoteric Software LLC
  6. *
  7. * Integration of the Spine Runtimes into software or otherwise creating
  8. * derivative works of the Spine Runtimes is permitted under the terms and
  9. * conditions of Section 2 of the Spine Editor License Agreement:
  10. * http://esotericsoftware.com/spine-editor-license
  11. *
  12. * Otherwise, it is permitted to integrate the Spine Runtimes into software
  13. * or otherwise create derivative works of the Spine Runtimes (collectively,
  14. * "Products"), provided that each user of the Products must obtain their own
  15. * Spine Editor license and redistribution of the Products in any form must
  16. * include this license and copyright notice.
  17. *
  18. * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
  19. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  20. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  21. * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
  22. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  23. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
  24. * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
  25. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  27. * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. *****************************************************************************/
  29. using UnityEngine;
  30. using System.Collections;
  31. using Spine;
  32. namespace Spine.Unity {
  33. /// <summary>
  34. /// Use this as a condition-blocking yield instruction for Unity Coroutines.
  35. /// The routine will pause until the AnimationState fires an event matching the given event name or EventData reference.</summary>
  36. public class WaitForSpineEvent : IEnumerator {
  37. Spine.EventData m_TargetEvent;
  38. string m_EventName;
  39. Spine.AnimationState m_AnimationState;
  40. bool m_WasFired = false;
  41. bool m_unsubscribeAfterFiring = false;
  42. #region Constructors
  43. void Subscribe (Spine.AnimationState state, Spine.EventData eventDataReference, bool unsubscribe) {
  44. if (state == null) {
  45. Debug.LogWarning("AnimationState argument was null. Coroutine will continue immediately.");
  46. m_WasFired = true;
  47. return;
  48. } else if (eventDataReference == null) {
  49. Debug.LogWarning("eventDataReference argument was null. Coroutine will continue immediately.");
  50. m_WasFired = true;
  51. return;
  52. }
  53. m_AnimationState = state;
  54. m_TargetEvent = eventDataReference;
  55. state.Event += HandleAnimationStateEvent;
  56. m_unsubscribeAfterFiring = unsubscribe;
  57. }
  58. void SubscribeByName (Spine.AnimationState state, string eventName, bool unsubscribe) {
  59. if (state == null) {
  60. Debug.LogWarning("AnimationState argument was null. Coroutine will continue immediately.");
  61. m_WasFired = true;
  62. return;
  63. } else if (string.IsNullOrEmpty(eventName)) {
  64. Debug.LogWarning("eventName argument was null. Coroutine will continue immediately.");
  65. m_WasFired = true;
  66. return;
  67. }
  68. m_AnimationState = state;
  69. m_EventName = eventName;
  70. state.Event += HandleAnimationStateEventByName;
  71. m_unsubscribeAfterFiring = unsubscribe;
  72. }
  73. public WaitForSpineEvent (Spine.AnimationState state, Spine.EventData eventDataReference, bool unsubscribeAfterFiring = true) {
  74. Subscribe(state, eventDataReference, unsubscribeAfterFiring);
  75. }
  76. public WaitForSpineEvent (SkeletonAnimation skeletonAnimation, Spine.EventData eventDataReference, bool unsubscribeAfterFiring = true) {
  77. // If skeletonAnimation is invalid, its state will be null. Subscribe handles null states just fine.
  78. Subscribe(skeletonAnimation.state, eventDataReference, unsubscribeAfterFiring);
  79. }
  80. public WaitForSpineEvent (Spine.AnimationState state, string eventName, bool unsubscribeAfterFiring = true) {
  81. SubscribeByName(state, eventName, unsubscribeAfterFiring);
  82. }
  83. public WaitForSpineEvent (SkeletonAnimation skeletonAnimation, string eventName, bool unsubscribeAfterFiring = true) {
  84. // If skeletonAnimation is invalid, its state will be null. Subscribe handles null states just fine.
  85. SubscribeByName(skeletonAnimation.state, eventName, unsubscribeAfterFiring);
  86. }
  87. #endregion
  88. #region Event Handlers
  89. void HandleAnimationStateEventByName (Spine.TrackEntry trackEntry, Spine.Event e) {
  90. m_WasFired |= (e.Data.Name == m_EventName); // Check event name string match.
  91. if (m_WasFired && m_unsubscribeAfterFiring)
  92. m_AnimationState.Event -= HandleAnimationStateEventByName; // Unsubscribe after correct event fires.
  93. }
  94. void HandleAnimationStateEvent (Spine.TrackEntry trackEntry, Spine.Event e) {
  95. m_WasFired |= (e.Data == m_TargetEvent); // Check event data reference match.
  96. if (m_WasFired && m_unsubscribeAfterFiring)
  97. m_AnimationState.Event -= HandleAnimationStateEvent; // Usubscribe after correct event fires.
  98. }
  99. #endregion
  100. #region Reuse
  101. /// <summary>
  102. /// By default, WaitForSpineEvent will unsubscribe from the event immediately after it fires a correct matching event.
  103. /// If you want to reuse this WaitForSpineEvent instance on the same event, you can set this to false.</summary>
  104. public bool WillUnsubscribeAfterFiring { get { return m_unsubscribeAfterFiring; } set { m_unsubscribeAfterFiring = value; } }
  105. public WaitForSpineEvent NowWaitFor (Spine.AnimationState state, Spine.EventData eventDataReference, bool unsubscribeAfterFiring = true) {
  106. ((IEnumerator)this).Reset();
  107. Clear(state);
  108. Subscribe(state, eventDataReference, unsubscribeAfterFiring);
  109. return this;
  110. }
  111. public WaitForSpineEvent NowWaitFor (Spine.AnimationState state, string eventName, bool unsubscribeAfterFiring = true) {
  112. ((IEnumerator)this).Reset();
  113. Clear(state);
  114. SubscribeByName(state, eventName, unsubscribeAfterFiring);
  115. return this;
  116. }
  117. void Clear (Spine.AnimationState state) {
  118. state.Event -= HandleAnimationStateEvent;
  119. state.Event -= HandleAnimationStateEventByName;
  120. }
  121. #endregion
  122. #region IEnumerator
  123. bool IEnumerator.MoveNext () {
  124. if (m_WasFired) {
  125. ((IEnumerator)this).Reset(); // auto-reset for YieldInstruction reuse
  126. return false;
  127. }
  128. return true;
  129. }
  130. void IEnumerator.Reset () { m_WasFired = false; }
  131. object IEnumerator.Current { get { return null; } }
  132. #endregion
  133. }
  134. }