源战役客户端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

210 line
8.8 KiB

  1. /******************************************************************************
  2. * Spine Runtimes Software License v2.5
  3. *
  4. * Copyright (c) 2013-2016, Esoteric Software
  5. * All rights reserved.
  6. *
  7. * You are granted a perpetual, non-exclusive, non-sublicensable, and
  8. * non-transferable license to use, install, execute, and perform the Spine
  9. * Runtimes software and derivative works solely for personal or internal
  10. * use. Without the written permission of Esoteric Software (see Section 2 of
  11. * the Spine Software License Agreement), you may not (a) modify, translate,
  12. * adapt, or develop new applications using the Spine Runtimes or otherwise
  13. * create derivative works or improvements of the Spine Runtimes or (b) remove,
  14. * delete, alter, or obscure any trademarks or any copyright, trademark, patent,
  15. * or other intellectual property or proprietary rights notices on or in the
  16. * Software, including any copy thereof. Redistributions in binary or source
  17. * form must include this license and terms.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
  20. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  21. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
  22. * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  23. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  24. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF
  25. * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
  26. * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  27. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  28. * POSSIBILITY OF SUCH DAMAGE.
  29. *****************************************************************************/
  30. using UnityEngine;
  31. namespace Spine.Unity {
  32. [ExecuteInEditMode]
  33. [AddComponentMenu("Spine/SkeletonAnimation")]
  34. [HelpURL("http://esotericsoftware.com/spine-unity-documentation#Controlling-Animation")]
  35. public class SkeletonAnimation : SkeletonRenderer, ISkeletonAnimation, IAnimationStateComponent {
  36. #region IAnimationStateComponent
  37. /// <summary>
  38. /// This is the Spine.AnimationState object of this SkeletonAnimation. You can control animations through it.
  39. /// Note that this object, like .skeleton, is not guaranteed to exist in Awake. Do all accesses and caching to it in Start</summary>
  40. public Spine.AnimationState state;
  41. /// <summary>
  42. /// This is the Spine.AnimationState object of this SkeletonAnimation. You can control animations through it.
  43. /// Note that this object, like .skeleton, is not guaranteed to exist in Awake. Do all accesses and caching to it in Start</summary>
  44. public Spine.AnimationState AnimationState { get { return this.state; } }
  45. #endregion
  46. #region Bone Callbacks ISkeletonAnimation
  47. protected event UpdateBonesDelegate _UpdateLocal;
  48. protected event UpdateBonesDelegate _UpdateWorld;
  49. protected event UpdateBonesDelegate _UpdateComplete;
  50. /// <summary>
  51. /// Occurs after the animations are applied and before world space values are resolved.
  52. /// Use this callback when you want to set bone local values.
  53. /// </summary>
  54. public event UpdateBonesDelegate UpdateLocal { add { _UpdateLocal += value; } remove { _UpdateLocal -= value; } }
  55. /// <summary>
  56. /// Occurs after the Skeleton's bone world space values are resolved (including all constraints).
  57. /// Using this callback will cause the world space values to be solved an extra time.
  58. /// Use this callback if want to use bone world space values, and also set bone local values.</summary>
  59. public event UpdateBonesDelegate UpdateWorld { add { _UpdateWorld += value; } remove { _UpdateWorld -= value; } }
  60. /// <summary>
  61. /// Occurs after the Skeleton's bone world space values are resolved (including all constraints).
  62. /// Use this callback if you want to use bone world space values, but don't intend to modify bone local values.
  63. /// This callback can also be used when setting world position and the bone matrix.</summary>
  64. public event UpdateBonesDelegate UpdateComplete { add { _UpdateComplete += value; } remove { _UpdateComplete -= value; } }
  65. #endregion
  66. #region Serialized state and Beginner API
  67. [SerializeField]
  68. [SpineAnimation]
  69. private string _animationName;
  70. /// <summary>
  71. /// Setting this property sets the animation of the skeleton. If invalid, it will store the animation name for the next time the skeleton is properly initialized.
  72. /// Getting this property gets the name of the currently playing animation. If invalid, it will return the last stored animation name set through this property.</summary>
  73. public string AnimationName {
  74. get {
  75. if (!valid) {
  76. return _animationName;
  77. } else {
  78. TrackEntry entry = state.GetCurrent(0);
  79. return entry == null ? null : entry.Animation.Name;
  80. }
  81. }
  82. set {
  83. if (_animationName == value)
  84. return;
  85. _animationName = value;
  86. if (string.IsNullOrEmpty(value)) {
  87. state.ClearTrack(0);
  88. } else {
  89. TrySetAnimation(value, loop);
  90. }
  91. }
  92. }
  93. TrackEntry TrySetAnimation (string animationName, bool animationLoop) {
  94. var animationObject = skeletonDataAsset.GetSkeletonData(false).FindAnimation(animationName);
  95. if (animationObject != null)
  96. return state.SetAnimation(0, animationObject, animationLoop);
  97. return null;
  98. }
  99. /// <summary>Whether or not <see cref="AnimationName"/> should loop. This only applies to the initial animation specified in the inspector, or any subsequent Animations played through .AnimationName. Animations set through state.SetAnimation are unaffected.</summary>
  100. public bool loop;
  101. /// <summary>
  102. /// The rate at which animations progress over time. 1 means 100%. 0.5 means 50%.</summary>
  103. /// <remarks>AnimationState and TrackEntry also have their own timeScale. These are combined multiplicatively.</remarks>
  104. public float timeScale = 1;
  105. #endregion
  106. #region Runtime Instantiation
  107. /// <summary>Adds and prepares a SkeletonAnimation component to a GameObject at runtime.</summary>
  108. /// <returns>The newly instantiated SkeletonAnimation</returns>
  109. public static SkeletonAnimation AddToGameObject (GameObject gameObject, SkeletonDataAsset skeletonDataAsset) {
  110. return SkeletonRenderer.AddSpineComponent<SkeletonAnimation>(gameObject, skeletonDataAsset);
  111. }
  112. /// <summary>Instantiates a new UnityEngine.GameObject and adds a prepared SkeletonAnimation component to it.</summary>
  113. /// <returns>The newly instantiated SkeletonAnimation component.</returns>
  114. public static SkeletonAnimation NewSkeletonAnimationGameObject (SkeletonDataAsset skeletonDataAsset) {
  115. return SkeletonRenderer.NewSpineGameObject<SkeletonAnimation>(skeletonDataAsset);
  116. }
  117. #endregion
  118. /// <summary>
  119. /// Clears the previously generated mesh, resets the skeleton's pose, and clears all previously active animations.</summary>
  120. public override void ClearState () {
  121. base.ClearState();
  122. if (state != null) state.ClearTracks();
  123. }
  124. /// <summary>
  125. /// Initialize this component. Attempts to load the SkeletonData and creates the internal Spine objects and buffers.</summary>
  126. /// <param name="overwrite">If set to <c>true</c>, force overwrite an already initialized object.</param>
  127. public override void Initialize (bool overwrite) {
  128. if (valid && !overwrite)
  129. return;
  130. base.Initialize(overwrite);
  131. if (!valid)
  132. return;
  133. state = new Spine.AnimationState(skeletonDataAsset.GetAnimationStateData());
  134. #if UNITY_EDITOR
  135. if (!string.IsNullOrEmpty(_animationName)) {
  136. if (Application.isPlaying) {
  137. TrackEntry startingTrack = TrySetAnimation(_animationName, loop);
  138. if (startingTrack != null)
  139. Update(0);
  140. } else {
  141. // Assume SkeletonAnimation is valid for skeletonData and skeleton. Checked above.
  142. var animationObject = skeletonDataAsset.GetSkeletonData(false).FindAnimation(_animationName);
  143. if (animationObject != null)
  144. animationObject.PoseSkeleton(skeleton, 0f);
  145. }
  146. }
  147. #else
  148. if (!string.IsNullOrEmpty(_animationName)) {
  149. TrackEntry startingTrack = TrySetAnimation(_animationName, loop);
  150. if (startingTrack != null)
  151. Update(0);
  152. }
  153. #endif
  154. }
  155. void Update () {
  156. Update(Time.deltaTime);
  157. }
  158. /// <summary>Progresses the AnimationState according to the given deltaTime, and applies it to the Skeleton. Use Time.deltaTime to update manually. Use deltaTime 0 to update without progressing the time.</summary>
  159. public void Update (float deltaTime) {
  160. if (!valid)
  161. return;
  162. deltaTime *= timeScale;
  163. skeleton.Update(deltaTime);
  164. state.Update(deltaTime);
  165. state.Apply(skeleton);
  166. if (_UpdateLocal != null)
  167. _UpdateLocal(this);
  168. skeleton.UpdateWorldTransform();
  169. if (_UpdateWorld != null) {
  170. _UpdateWorld(this);
  171. skeleton.UpdateWorldTransform();
  172. }
  173. if (_UpdateComplete != null) {
  174. _UpdateComplete(this);
  175. }
  176. }
  177. }
  178. }