diff --git a/spine-unity/Assets/spine-unity/BoneFollower.cs b/spine-unity/Assets/spine-unity/BoneFollower.cs index b1b740281..49ff44b27 100644 --- a/spine-unity/Assets/spine-unity/BoneFollower.cs +++ b/spine-unity/Assets/spine-unity/BoneFollower.cs @@ -138,7 +138,7 @@ namespace Spine.Unity { // Recommended setup: Use local transform properties if Spine GameObject is the immediate parent thisTransform.localPosition = new Vector3(bone.worldX, bone.worldY, followZPosition ? 0f : thisTransform.localPosition.z); if (followBoneRotation) { - var halfRotation = Mathf.Atan2(bone.c, bone.a) * 0.5f; + float halfRotation = Mathf.Atan2(bone.c, bone.a) * 0.5f; if (followLocalScale && bone.scaleX < 0) // Negate rotation from negative scaleX. Don't use negative determinant. local scaleY doesn't factor into used rotation. halfRotation += Mathf.PI * 0.5f; diff --git a/spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs b/spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs index 55d1f3ae8..ca11f4269 100644 --- a/spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs +++ b/spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs @@ -79,10 +79,10 @@ namespace Spine.Unity.Editor { var objectReferenceValue = dataField.objectReferenceValue; if (objectReferenceValue is SkeletonDataAsset) { skeletonDataAsset = (SkeletonDataAsset)objectReferenceValue; - } else if (objectReferenceValue is ISkeletonComponent) { - var skeletonComponent = (ISkeletonComponent)objectReferenceValue; - if (skeletonComponent != null) - skeletonDataAsset = skeletonComponent.SkeletonDataAsset; + } else if (objectReferenceValue is IHasSkeletonDataAsset) { + var hasSkeletonDataAsset = (IHasSkeletonDataAsset)objectReferenceValue; + if (hasSkeletonDataAsset != null) + skeletonDataAsset = hasSkeletonDataAsset.SkeletonDataAsset; } else if (objectReferenceValue != null) { EditorGUI.LabelField(position, "ERROR:", "Invalid reference type"); return; @@ -90,9 +90,9 @@ namespace Spine.Unity.Editor { } else if (property.serializedObject.targetObject is Component) { var component = (Component)property.serializedObject.targetObject; - var skeletonComponent = component.GetComponentInChildren(typeof(ISkeletonComponent)) as ISkeletonComponent; - if (skeletonComponent != null) - skeletonDataAsset = skeletonComponent.SkeletonDataAsset; + var hasSkeletonDataAsset = component.GetComponentInChildren(typeof(IHasSkeletonDataAsset)) as IHasSkeletonDataAsset; + if (hasSkeletonDataAsset != null) + skeletonDataAsset = hasSkeletonDataAsset.SkeletonDataAsset; } if (skeletonDataAsset == null) { diff --git a/spine-unity/Assets/spine-unity/Editor/SpineInspectorUtility.cs b/spine-unity/Assets/spine-unity/Editor/SpineInspectorUtility.cs index 49889d3ea..d6b46271e 100644 --- a/spine-unity/Assets/spine-unity/Editor/SpineInspectorUtility.cs +++ b/spine-unity/Assets/spine-unity/Editor/SpineInspectorUtility.cs @@ -220,9 +220,9 @@ namespace Spine.Unity.Editor { public static bool TargetsUseSameData (SerializedObject so) { if (so.isEditingMultipleObjects) { int n = so.targetObjects.Length; - var first = so.targetObjects[0] as ISkeletonComponent; + var first = so.targetObjects[0] as IHasSkeletonDataAsset; for (int i = 1; i < n; i++) { - var sr = so.targetObjects[i] as ISkeletonComponent; + var sr = so.targetObjects[i] as IHasSkeletonDataAsset; if (sr != null && sr.SkeletonDataAsset != first.SkeletonDataAsset) return false; } diff --git a/spine-unity/Assets/spine-unity/ISkeletonAnimation.cs b/spine-unity/Assets/spine-unity/ISkeletonAnimation.cs index f5e423adf..ebacb56fc 100644 --- a/spine-unity/Assets/spine-unity/ISkeletonAnimation.cs +++ b/spine-unity/Assets/spine-unity/ISkeletonAnimation.cs @@ -42,7 +42,7 @@ namespace Spine.Unity { } /// Holds a reference to a SkeletonDataAsset. - public interface ISkeletonDataAssetComponent { + public interface IHasSkeletonDataAsset { /// Gets the SkeletonDataAsset of the Spine Component. SkeletonDataAsset SkeletonDataAsset { get; } } diff --git a/spine-unity/Assets/spine-unity/Modules/Shaders/Spine-Skeleton-Fill.shader b/spine-unity/Assets/spine-unity/Modules/Shaders/Spine-Skeleton-Fill.shader index 653351778..262b90e5e 100644 --- a/spine-unity/Assets/spine-unity/Modules/Shaders/Spine-Skeleton-Fill.shader +++ b/spine-unity/Assets/spine-unity/Modules/Shaders/Spine-Skeleton-Fill.shader @@ -9,7 +9,7 @@ Shader "Spine/Skeleton Fill" { [NoScaleOffset]_MainTex ("MainTex", 2D) = "white" {} } SubShader { - Tags { "IgnoreProjector"="True" "Queue"="Transparent" "RenderType"="Transparent" "PreviewType"="Plane" } + Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "PreviewType"="Plane" } Blend One OneMinusSrcAlpha Cull Off ZWrite Off diff --git a/spine-unity/Assets/spine-unity/Modules/Shaders/Spine-Skeleton-Tint.shader b/spine-unity/Assets/spine-unity/Modules/Shaders/Spine-Skeleton-Tint.shader index 117ae495e..79bacb5cd 100644 --- a/spine-unity/Assets/spine-unity/Modules/Shaders/Spine-Skeleton-Tint.shader +++ b/spine-unity/Assets/spine-unity/Modules/Shaders/Spine-Skeleton-Tint.shader @@ -13,7 +13,7 @@ Shader "Spine/Skeleton Tint" { } SubShader { - Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" } + Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "PreviewType"="Plane" } Fog { Mode Off } Cull Off diff --git a/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/SkeletonGraphic.cs b/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/SkeletonGraphic.cs index 25e4d688c..3e04344b0 100644 --- a/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/SkeletonGraphic.cs +++ b/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/SkeletonGraphic.cs @@ -35,7 +35,7 @@ using Spine; namespace Spine.Unity { [ExecuteInEditMode, RequireComponent(typeof(CanvasRenderer), typeof(RectTransform)), DisallowMultipleComponent] [AddComponentMenu("Spine/SkeletonGraphic (Unity UI Canvas)")] - public class SkeletonGraphic : MaskableGraphic, ISkeletonComponent, IAnimationStateComponent, ISkeletonAnimation, ISkeletonDataAssetComponent { + public class SkeletonGraphic : MaskableGraphic, ISkeletonComponent, IAnimationStateComponent, ISkeletonAnimation, IHasSkeletonDataAsset { #region Inspector public SkeletonDataAsset skeletonDataAsset; diff --git a/spine-unity/Assets/spine-unity/Shaders/Spine-Skeleton.shader b/spine-unity/Assets/spine-unity/Shaders/Spine-Skeleton.shader index 2741ba504..7b5c00d90 100644 --- a/spine-unity/Assets/spine-unity/Shaders/Spine-Skeleton.shader +++ b/spine-unity/Assets/spine-unity/Shaders/Spine-Skeleton.shader @@ -5,7 +5,7 @@ Shader "Spine/Skeleton" { } SubShader { - Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" } + Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "PreviewType"="Plane"} Fog { Mode Off } Cull Off diff --git a/spine-unity/Assets/spine-unity/SkeletonRenderer.cs b/spine-unity/Assets/spine-unity/SkeletonRenderer.cs index 356cbd21f..17d851384 100644 --- a/spine-unity/Assets/spine-unity/SkeletonRenderer.cs +++ b/spine-unity/Assets/spine-unity/SkeletonRenderer.cs @@ -38,7 +38,7 @@ namespace Spine.Unity { /// Renders a skeleton. [ExecuteInEditMode, RequireComponent(typeof(MeshFilter), typeof(MeshRenderer)), DisallowMultipleComponent] [HelpURL("http://esotericsoftware.com/spine-unity-documentation#Rendering")] - public class SkeletonRenderer : MonoBehaviour, ISkeletonComponent, ISkeletonDataAssetComponent { + public class SkeletonRenderer : MonoBehaviour, ISkeletonComponent, IHasSkeletonDataAsset { public delegate void SkeletonRendererDelegate (SkeletonRenderer skeletonRenderer); public event SkeletonRendererDelegate OnRebuild; diff --git a/spine-unity/Assets/spine-unity/SkeletonUtility/Editor/SkeletonUtilityBoneInspector.cs b/spine-unity/Assets/spine-unity/SkeletonUtility/Editor/SkeletonUtilityBoneInspector.cs index 0a6632e11..de58f122b 100644 --- a/spine-unity/Assets/spine-unity/SkeletonUtility/Editor/SkeletonUtilityBoneInspector.cs +++ b/spine-unity/Assets/spine-unity/SkeletonUtility/Editor/SkeletonUtilityBoneInspector.cs @@ -28,8 +28,10 @@ * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ +//#define HINGECHAIN2D // Contributed by: Mitch Thompson + using UnityEngine; using UnityEditor; using System.Collections.Generic; @@ -277,6 +279,54 @@ namespace Spine.Unity.Editor { EditorGUIUtility.PingObject(go); } + +#if HINGECHAIN2D + bool CanCreateHingeChain () { + if (utilityBone == null) return false; + if (utilityBone.GetComponent() != null) return false; + if (utilityBone.bone != null && utilityBone.bone.Children.Count == 0) return false; + var rigidbodies = utilityBone.GetComponentsInChildren(); + return rigidbodies.Length <= 0; + } + + void CreateHingeChain () { + var utilBoneArr = utilityBone.GetComponentsInChildren(); + + foreach (var utilBone in utilBoneArr) { + if (utilBone.GetComponent() == null) { + if (utilBone.bone.Data.Length == 0) { + var sphere = utilBone.gameObject.AddComponent(); + sphere.radius = 0.1f; + } else { + float length = utilBone.bone.Data.Length; + var box = utilBone.gameObject.AddComponent(); + box.size = new Vector3(length, length / 3f, 0.2f); + box.offset = new Vector3(length / 2f, 0, 0); + } + } + + utilBone.gameObject.AddComponent(); + } + + utilityBone.GetComponent().isKinematic = true; + + foreach (var utilBone in utilBoneArr) { + if (utilBone == utilityBone) + continue; + + utilBone.mode = SkeletonUtilityBone.Mode.Override; + + var joint = utilBone.gameObject.AddComponent(); + joint.connectedBody = utilBone.transform.parent.GetComponent(); + joint.useLimits = true; + joint.limits = new JointAngleLimits2D { + min = -20, + max = 20 + }; + utilBone.GetComponent().mass = utilBone.transform.parent.GetComponent().mass * 0.75f; + } + } +#else bool CanCreateHingeChain () { if (utilityBone == null) return false; @@ -285,7 +335,7 @@ namespace Spine.Unity.Editor { if (utilityBone.bone != null && utilityBone.bone.Children.Count == 0) return false; - Rigidbody[] rigidbodies = utilityBone.GetComponentsInChildren(); + var rigidbodies = utilityBone.GetComponentsInChildren(); return rigidbodies.Length <= 0; } @@ -332,6 +382,7 @@ namespace Spine.Unity.Editor { utilBone.gameObject.AddComponent(); } +#endif } } diff --git a/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtility.cs b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtility.cs index 9765e4b66..8280a05d3 100644 --- a/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtility.cs +++ b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtility.cs @@ -267,27 +267,27 @@ namespace Spine.Unity { for (int i = 0, n = utilityBones.Count; i < n; i++) utilityBones[i].transformLerpComplete = false; - UpdateAllBones(); + UpdateAllBones(SkeletonUtilityBone.UpdatePhase.Local); } void UpdateWorld (ISkeletonAnimation anim) { - UpdateAllBones(); + UpdateAllBones(SkeletonUtilityBone.UpdatePhase.World); for (int i = 0, n = utilityConstraints.Count; i < n; i++) utilityConstraints[i].DoUpdate(); } void UpdateComplete (ISkeletonAnimation anim) { - UpdateAllBones(); + UpdateAllBones(SkeletonUtilityBone.UpdatePhase.Complete); } - void UpdateAllBones () { + void UpdateAllBones (SkeletonUtilityBone.UpdatePhase phase) { if (boneRoot == null) CollectBones(); var utilityBones = this.utilityBones; if (utilityBones == null) return; for (int i = 0, n = utilityBones.Count; i < n; i++) - utilityBones[i].DoUpdate(); + utilityBones[i].DoUpdate(phase); } public Transform GetBoneRoot () { diff --git a/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityBone.cs b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityBone.cs index f4670d8f1..1cec0264b 100644 --- a/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityBone.cs +++ b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityBone.cs @@ -43,6 +43,12 @@ namespace Spine.Unity { Override } + public enum UpdatePhase { + Local, + World, + Complete + } + #region Inspector /// If a bone isn't set, boneName is used to find the bone. public string boneName; @@ -71,7 +77,7 @@ namespace Spine.Unity { skeletonTransform = skeletonUtility.transform; skeletonUtility.OnReset -= HandleOnReset; skeletonUtility.OnReset += HandleOnReset; - DoUpdate(); + DoUpdate(UpdatePhase.Local); } void OnEnable () { @@ -95,7 +101,7 @@ namespace Spine.Unity { } } - public void DoUpdate () { + public void DoUpdate (UpdatePhase phase) { if (!valid) { Reset(); return; @@ -112,46 +118,72 @@ namespace Spine.Unity { } } + var thisTransform = cachedTransform; float skeletonFlipRotation = (skeleton.flipX ^ skeleton.flipY) ? -1f : 1f; if (mode == Mode.Follow) { - if (!bone.appliedValid) - bone.UpdateAppliedTransform(); + switch (phase) { + case UpdatePhase.Local: + if (position) + thisTransform.localPosition = new Vector3(bone.x, bone.y, 0); - if (position) - cachedTransform.localPosition = new Vector3(bone.ax, bone.ay, 0); + if (rotation) { + if (bone.data.transformMode.InheritsRotation()) { + thisTransform.localRotation = Quaternion.Euler(0, 0, bone.rotation); + } else { + Vector3 euler = skeletonTransform.rotation.eulerAngles; + thisTransform.rotation = Quaternion.Euler(euler.x, euler.y, euler.z + (bone.WorldRotationX * skeletonFlipRotation)); + } + } + + if (scale) { + thisTransform.localScale = new Vector3(bone.scaleX, bone.scaleY, 1f); + incompatibleTransformMode = BoneTransformModeIncompatible(bone); + } + break; + case UpdatePhase.World: + case UpdatePhase.Complete: + // Use Applied transform values (ax, ay, AppliedRotation, ascale) if world values were modified by constraints. + if (!bone.appliedValid) { + bone.UpdateAppliedTransform(); + if (position) + thisTransform.localPosition = new Vector3(bone.ax, bone.ay, 0); + + if (rotation) { + if (bone.data.transformMode.InheritsRotation()) { + thisTransform.localRotation = Quaternion.Euler(0, 0, bone.AppliedRotation); + } else { + Vector3 euler = skeletonTransform.rotation.eulerAngles; + thisTransform.rotation = Quaternion.Euler(euler.x, euler.y, euler.z + (bone.WorldRotationX * skeletonFlipRotation)); + } + } + + if (scale) { + thisTransform.localScale = new Vector3(bone.ascaleX, bone.ascaleY, 1f); + incompatibleTransformMode = BoneTransformModeIncompatible(bone); + } + } + break; + } - if (rotation) { - if (bone.data.transformMode.InheritsRotation()) { - cachedTransform.localRotation = Quaternion.Euler(0, 0, bone.AppliedRotation); - } else { - Vector3 euler = skeletonTransform.rotation.eulerAngles; - cachedTransform.rotation = Quaternion.Euler(euler.x, euler.y, euler.z + (bone.WorldRotationX * skeletonFlipRotation)); - } - } - - if (scale) { - cachedTransform.localScale = new Vector3(bone.ascaleX, bone.ascaleY, 1f); - incompatibleTransformMode = BoneTransformModeIncompatible(bone); - } } else if (mode == Mode.Override) { if (transformLerpComplete) return; if (parentReference == null) { if (position) { - Vector3 clp = cachedTransform.localPosition; + Vector3 clp = thisTransform.localPosition; bone.x = Mathf.Lerp(bone.x, clp.x, overrideAlpha); bone.y = Mathf.Lerp(bone.y, clp.y, overrideAlpha); } if (rotation) { - float angle = Mathf.LerpAngle(bone.Rotation, cachedTransform.localRotation.eulerAngles.z, overrideAlpha); + float angle = Mathf.LerpAngle(bone.Rotation, thisTransform.localRotation.eulerAngles.z, overrideAlpha); bone.Rotation = angle; bone.AppliedRotation = angle; } if (scale) { - Vector3 cls = cachedTransform.localScale; + Vector3 cls = thisTransform.localScale; bone.scaleX = Mathf.Lerp(bone.scaleX, cls.x, overrideAlpha); bone.scaleY = Mathf.Lerp(bone.scaleY, cls.y, overrideAlpha); } @@ -161,19 +193,19 @@ namespace Spine.Unity { return; if (position) { - Vector3 pos = parentReference.InverseTransformPoint(cachedTransform.position); + Vector3 pos = parentReference.InverseTransformPoint(thisTransform.position); bone.x = Mathf.Lerp(bone.x, pos.x, overrideAlpha); bone.y = Mathf.Lerp(bone.y, pos.y, overrideAlpha); } if (rotation) { - float angle = Mathf.LerpAngle(bone.Rotation, Quaternion.LookRotation(Vector3.forward, parentReference.InverseTransformDirection(cachedTransform.up)).eulerAngles.z, overrideAlpha); + float angle = Mathf.LerpAngle(bone.Rotation, Quaternion.LookRotation(Vector3.forward, parentReference.InverseTransformDirection(thisTransform.up)).eulerAngles.z, overrideAlpha); bone.Rotation = angle; bone.AppliedRotation = angle; } if (scale) { - Vector3 cls = cachedTransform.localScale; + Vector3 cls = thisTransform.localScale; bone.scaleX = Mathf.Lerp(bone.scaleX, cls.x, overrideAlpha); bone.scaleY = Mathf.Lerp(bone.scaleY, cls.y, overrideAlpha); }