源战役客户端
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

154 行
5.9 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 System.Collections;
  31. using System.Collections.Generic;
  32. using UnityEngine;
  33. namespace Spine.Unity {
  34. [ExecuteInEditMode]
  35. [AddComponentMenu("Spine/Point Follower")]
  36. public class PointFollower : MonoBehaviour, IHasSkeletonRenderer, IHasSkeletonComponent {
  37. [SerializeField] public SkeletonRenderer skeletonRenderer;
  38. public SkeletonRenderer SkeletonRenderer { get { return this.skeletonRenderer; } }
  39. public ISkeletonComponent SkeletonComponent { get { return skeletonRenderer as ISkeletonComponent; } }
  40. [SpineSlot(dataField:"skeletonRenderer", includeNone: true)]
  41. public string slotName;
  42. [SpineAttachment(slotField:"slotName", dataField: "skeletonRenderer", fallbackToTextField:true, includeNone: true)]
  43. public string pointAttachmentName;
  44. public bool followRotation = true;
  45. public bool followSkeletonFlip = true;
  46. public bool followSkeletonZPosition = false;
  47. Transform skeletonTransform;
  48. bool skeletonTransformIsParent;
  49. PointAttachment point;
  50. Bone bone;
  51. bool valid;
  52. public bool IsValid { get { return valid; } }
  53. public void Initialize () {
  54. valid = skeletonRenderer != null && skeletonRenderer.valid;
  55. if (!valid)
  56. return;
  57. UpdateReferences();
  58. #if UNITY_EDITOR
  59. if (Application.isEditor) LateUpdate();
  60. #endif
  61. }
  62. private void HandleRebuildRenderer (SkeletonRenderer skeletonRenderer) {
  63. Initialize();
  64. }
  65. void UpdateReferences () {
  66. skeletonTransform = skeletonRenderer.transform;
  67. skeletonRenderer.OnRebuild -= HandleRebuildRenderer;
  68. skeletonRenderer.OnRebuild += HandleRebuildRenderer;
  69. skeletonTransformIsParent = Transform.ReferenceEquals(skeletonTransform, transform.parent);
  70. bone = null;
  71. point = null;
  72. if (!string.IsNullOrEmpty(pointAttachmentName)) {
  73. var skeleton = skeletonRenderer.skeleton;
  74. int slotIndex = skeleton.FindSlotIndex(slotName);
  75. if (slotIndex >= 0) {
  76. var slot = skeleton.slots.Items[slotIndex];
  77. bone = slot.bone;
  78. point = skeleton.GetAttachment(slotIndex, pointAttachmentName) as PointAttachment;
  79. }
  80. }
  81. }
  82. public void LateUpdate () {
  83. #if UNITY_EDITOR
  84. if (!Application.isPlaying) skeletonTransformIsParent = Transform.ReferenceEquals(skeletonTransform, transform.parent);
  85. #endif
  86. if (point == null) {
  87. if (string.IsNullOrEmpty(pointAttachmentName)) return;
  88. UpdateReferences();
  89. if (point == null) return;
  90. }
  91. Vector2 worldPos;
  92. point.ComputeWorldPosition(bone, out worldPos.x, out worldPos.y);
  93. float rotation = point.ComputeWorldRotation(bone);
  94. Transform thisTransform = this.transform;
  95. if (skeletonTransformIsParent) {
  96. // Recommended setup: Use local transform properties if Spine GameObject is the immediate parent
  97. thisTransform.localPosition = new Vector3(worldPos.x, worldPos.y, followSkeletonZPosition ? 0f : thisTransform.localPosition.z);
  98. if (followRotation) {
  99. float halfRotation = rotation * 0.5f * Mathf.Deg2Rad;
  100. var q = default(Quaternion);
  101. q.z = Mathf.Sin(halfRotation);
  102. q.w = Mathf.Cos(halfRotation);
  103. thisTransform.localRotation = q;
  104. }
  105. } else {
  106. // For special cases: Use transform world properties if transform relationship is complicated
  107. Vector3 targetWorldPosition = skeletonTransform.TransformPoint(new Vector3(worldPos.x, worldPos.y, 0f));
  108. if (!followSkeletonZPosition)
  109. targetWorldPosition.z = thisTransform.position.z;
  110. Transform transformParent = thisTransform.parent;
  111. if (transformParent != null) {
  112. Matrix4x4 m = transformParent.localToWorldMatrix;
  113. if (m.m00 * m.m11 - m.m01 * m.m10 < 0) // Determinant2D is negative
  114. rotation = -rotation;
  115. }
  116. if (followRotation) {
  117. Vector3 transformWorldRotation = skeletonTransform.rotation.eulerAngles;
  118. thisTransform.SetPositionAndRotation(targetWorldPosition, Quaternion.Euler(transformWorldRotation.x, transformWorldRotation.y, transformWorldRotation.z + rotation));
  119. } else {
  120. thisTransform.position = targetWorldPosition;
  121. }
  122. }
  123. if (followSkeletonFlip) {
  124. Vector3 localScale = thisTransform.localScale;
  125. localScale.y = Mathf.Abs(localScale.y) * (bone.skeleton.flipX ^ bone.skeleton.flipY ? -1f : 1f);
  126. thisTransform.localScale = localScale;
  127. }
  128. }
  129. }
  130. }