From b86333b11adf9607707b537d2c52c67a4f9b2090 Mon Sep 17 00:00:00 2001 From: Harald Csaszar Date: Wed, 11 Mar 2020 15:29:02 +0100 Subject: [PATCH 1/2] [unity] Fixed drag&drop instantiation using last hierarchy node as parent when dopping over empty hierarchy area below last item. Closes #1641. Also fixed a null reference exception in TextureModificationWarningProcessor reported by a user. --- .../Editor/Utility/SpineEditorUtilities.cs | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Utility/SpineEditorUtilities.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Utility/SpineEditorUtilities.cs index a4b590261..877cd3ae6 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Utility/SpineEditorUtilities.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Utility/SpineEditorUtilities.cs @@ -327,6 +327,9 @@ namespace Spine.Unity.Editor { } else if (isDropEvent) { var parentGameObject = DragAndDrop.GetGenericData(GenericDataTargetID) as UnityEngine.GameObject; Transform parent = parentGameObject != null ? parentGameObject.transform : null; + // when dragging into empty space in hierarchy below last node, last node would be parent. + if (IsLastNodeInHierarchy(parent)) + parent = null; DragAndDropInstantiation.ShowInstantiateContextMenu(skeletonDataAsset, Vector3.zero, parent); UnityEditor.DragAndDrop.AcceptDrag(); current.Use(); @@ -338,6 +341,21 @@ namespace Spine.Unity.Editor { } } } + + internal static bool IsLastNodeInHierarchy (Transform node) { + if (node == null) + return false; + + while (node.parent != null) { + if (node.GetSiblingIndex() != node.parent.childCount - 1) + return false; + node = node.parent; + } + + var rootNodes = UnityEngine.SceneManagement.SceneManager.GetActiveScene().GetRootGameObjects(); + bool isLastNode = (rootNodes.Length > 0 && rootNodes[rootNodes.Length - 1].transform == node); + return isLastNode; + } } } @@ -347,8 +365,9 @@ namespace Spine.Unity.Editor { { if (SpineEditorUtilities.Preferences.textureImporterWarning) { foreach (string path in paths) { - if (path.EndsWith(".png.meta", System.StringComparison.Ordinal) || - path.EndsWith(".jpg.meta", System.StringComparison.Ordinal)) { + if ((path != null) && + (path.EndsWith(".png.meta", System.StringComparison.Ordinal) || + path.EndsWith(".jpg.meta", System.StringComparison.Ordinal))) { string texturePath = System.IO.Path.ChangeExtension(path, null); // .meta removed string atlasPath = System.IO.Path.ChangeExtension(texturePath, "atlas.txt"); From 016f438d59dcaf62c4ad9abb68351884c7c7cb72 Mon Sep 17 00:00:00 2001 From: Harald Csaszar Date: Wed, 11 Mar 2020 20:07:25 +0100 Subject: [PATCH 2/2] [unity] `SkeletonGraphic` now fully supports `SkeletonUtility` for generating a hierarchy of `SkeletonUtilityBones`. Closes #1637. --- CHANGELOG.md | 1 + .../SkeletonUtilityEyeConstraint.cs | 3 +- .../SkeletonUtilityGroundConstraint.cs | 14 ++- .../Components/SkeletonGraphicInspector.cs | 40 +++++++ .../SkeletonUtilityBoneInspector.cs | 25 +++-- .../Components/SkeletonUtilityInspector.cs | 28 +++-- .../spine-unity/Components/SkeletonGraphic.cs | 8 ++ .../ActivateBasedOnFlipDirection.cs | 4 +- .../SkeletonUtility/SkeletonUtility.cs | 106 +++++++++++++++--- .../SkeletonUtility/SkeletonUtilityBone.cs | 14 ++- 10 files changed, 191 insertions(+), 52 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ef091dbdf..fb84742d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -217,6 +217,7 @@ * Spine Preferences now provide an **`Atlas Texture Settings`** parameter for applying customizable texture import settings at all newly imported Spine atlas textures. When exporting atlas textures from Spine with `Premultiply alpha` enabled (the default), you can leave it at `PMATexturePreset`. If you have disabled `Premultiply alpha`, set it to the included `StraightAlphaTexturePreset` asset. You can also create your own `TextureImporter` `Preset` asset and assign it here (include `PMA` or `Straight` in the name). In Unity versions before 2018.3 you can use `Texture2D` template assets instead of the newer `Preset` assets. Materials created for imported textures will also have the `Straight Alpha Texture` parameter configured accordingly. * All `Sprite` shaders (including URP and LWRP extension packages) now provide an additional `Fixed Normal Space` option `World-Space`. PReviously options were limited to `View-Space` and `Model-Space`. + * `SkeletonGraphic` now fully supports [`SkeletonUtility`](http://esotericsoftware.com/spine-unity#SkeletonUtility) for generating a hierarchy of [`SkeletonUtilityBones`](http://esotericsoftware.com/spine-unity#SkeletonUtilityBone) in both modes `Follow` and `Override`. This also enables creating hinge chain physics rigs and using `SkeletonUtilityConstraints` such as `SkeletonUtilityGroundConstraint` and `SkeletonUtilityEyeConstraint` on `SkeletonGraphic`. * **Changes of default values** * `SkeletonMecanim`'s `Layer Mix Mode` now defaults to `MixMode.MixNext` instead of `MixMode.MixAlways`. diff --git a/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonUtility Modules/SkeletonUtilityEyeConstraint.cs b/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonUtility Modules/SkeletonUtilityEyeConstraint.cs index f75fbe5a3..ab481fc26 100644 --- a/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonUtility Modules/SkeletonUtilityEyeConstraint.cs +++ b/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonUtility Modules/SkeletonUtilityEyeConstraint.cs @@ -75,7 +75,8 @@ namespace Spine.Unity.Examples { for (int i = 0; i < eyes.Length; i++) { center = transform.TransformPoint(origins[i]); - eyes[i].position = Vector3.MoveTowards(eyes[i].position, center + (dir * radius), speed * Time.deltaTime); + eyes[i].position = Vector3.MoveTowards(eyes[i].position, center + (dir * radius * hierarchy.PositionScale), + speed * hierarchy.PositionScale * Time.deltaTime); } } diff --git a/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonUtility Modules/SkeletonUtilityGroundConstraint.cs b/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonUtility Modules/SkeletonUtilityGroundConstraint.cs index 5306fd81a..3a0193455 100644 --- a/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonUtility Modules/SkeletonUtilityGroundConstraint.cs +++ b/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonUtility Modules/SkeletonUtilityGroundConstraint.cs @@ -73,6 +73,8 @@ namespace Spine.Unity.Examples { public override void DoUpdate () { rayOrigin = transform.position + new Vector3(castOffset, castDistance, 0); + float positionScale = hierarchy.PositionScale; + float adjustDistanceThisFrame = adjustSpeed * positionScale * Time.deltaTime; hitY = float.MinValue; if (use2D) { RaycastHit2D hit; @@ -85,10 +87,10 @@ namespace Spine.Unity.Examples { if (hit.collider != null) { hitY = hit.point.y + groundOffset; if (Application.isPlaying) - hitY = Mathf.MoveTowards(lastHitY, hitY, adjustSpeed * Time.deltaTime); + hitY = Mathf.MoveTowards(lastHitY, hitY, adjustDistanceThisFrame); } else { if (Application.isPlaying) - hitY = Mathf.MoveTowards(lastHitY, transform.position.y, adjustSpeed * Time.deltaTime); + hitY = Mathf.MoveTowards(lastHitY, transform.position.y, adjustDistanceThisFrame); } } else { RaycastHit hit; @@ -102,11 +104,11 @@ namespace Spine.Unity.Examples { if (validHit) { hitY = hit.point.y + groundOffset; if (Application.isPlaying) - hitY = Mathf.MoveTowards(lastHitY, hitY, adjustSpeed * Time.deltaTime); + hitY = Mathf.MoveTowards(lastHitY, hitY, adjustDistanceThisFrame); } else { if (Application.isPlaying) - hitY = Mathf.MoveTowards(lastHitY, transform.position.y, adjustSpeed * Time.deltaTime); + hitY = Mathf.MoveTowards(lastHitY, transform.position.y, adjustDistanceThisFrame); } } @@ -114,8 +116,8 @@ namespace Spine.Unity.Examples { v.y = Mathf.Clamp(v.y, Mathf.Min(lastHitY, hitY), float.MaxValue); transform.position = v; - bone.bone.X = transform.localPosition.x; - bone.bone.Y = transform.localPosition.y; + bone.bone.X = transform.localPosition.x / hierarchy.PositionScale; + bone.bone.Y = transform.localPosition.y / hierarchy.PositionScale; lastHitY = hitY; } diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonGraphicInspector.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonGraphicInspector.cs index 4811d9627..5c44cba74 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonGraphicInspector.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonGraphicInspector.cs @@ -27,11 +27,16 @@ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ +#if UNITY_2018_3 || UNITY_2019 || UNITY_2018_3_OR_NEWER +#define NEW_PREFAB_SYSTEM +#endif + using UnityEngine; using UnityEditor; using Spine; namespace Spine.Unity.Editor { + using Icons = SpineEditorUtilities.Icons; [InitializeOnLoad] [CustomEditor(typeof(SkeletonGraphic))] @@ -45,8 +50,32 @@ namespace Spine.Unity.Editor { SerializedProperty raycastTarget; SkeletonGraphic thisSkeletonGraphic; + protected bool isInspectingPrefab; + + protected bool TargetIsValid { + get { + if (serializedObject.isEditingMultipleObjects) { + foreach (var o in targets) { + var component = (SkeletonGraphic)o; + if (!component.IsValid) + return false; + } + return true; + } + else { + var component = (SkeletonGraphic)target; + return component.IsValid; + } + } + } void OnEnable () { +#if NEW_PREFAB_SYSTEM + isInspectingPrefab = false; +#else + isInspectingPrefab = (PrefabUtility.GetPrefabType(target) == PrefabType.Prefab); +#endif + var so = this.serializedObject; thisSkeletonGraphic = target as SkeletonGraphic; @@ -124,6 +153,17 @@ namespace Spine.Unity.Editor { } EditorGUILayout.EndHorizontal(); + if (TargetIsValid && !isInspectingPrefab) { + EditorGUILayout.Space(); + if (SpineInspectorUtility.CenteredButton(new GUIContent("Add Skeleton Utility", Icons.skeletonUtility), 21, true, 200f)) + foreach (var t in targets) { + var component = t as Component; + if (component.GetComponent() == null) { + component.gameObject.AddComponent(); + } + } + } + bool wasChanged = EditorGUI.EndChangeCheck(); if (wasChanged) diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonUtilityBoneInspector.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonUtilityBoneInspector.cs index 44333caf8..090dab130 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonUtilityBoneInspector.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonUtilityBoneInspector.cs @@ -72,8 +72,12 @@ namespace Spine.Unity.Editor { skeletonUtility = utilityBone.hierarchy; EvaluateFlags(); - if (!utilityBone.valid && skeletonUtility != null && skeletonUtility.skeletonRenderer != null) - skeletonUtility.skeletonRenderer.Initialize(false); + if (!utilityBone.valid && skeletonUtility != null) { + if (skeletonUtility.skeletonRenderer != null) + skeletonUtility.skeletonRenderer.Initialize(false); + if (skeletonUtility.skeletonGraphic != null) + skeletonUtility.skeletonGraphic.Initialize(false); + } canCreateHingeChain = CanCreateHingeChain(); boundingBoxTable.Clear(); @@ -88,7 +92,7 @@ namespace Spine.Unity.Editor { skin = skeleton.Data.DefaultSkin; for(int i = 0; i < slotCount; i++){ - Slot slot = skeletonUtility.skeletonRenderer.skeleton.Slots.Items[i]; + Slot slot = skeletonUtility.Skeleton.Slots.Items[i]; if (slot.Bone == utilityBone.bone) { var slotAttachments = new List(); int slotIndex = skeleton.FindSlotIndex(slot.Data.Name); @@ -105,7 +109,6 @@ namespace Spine.Unity.Editor { boundingBoxTable.Add(slot, boundingBoxes); } } - } void EvaluateFlags () { @@ -150,7 +153,7 @@ namespace Spine.Unity.Editor { using (new GUILayout.HorizontalScope()) { EditorGUILayout.PrefixLabel("Bone"); if (GUILayout.Button(str, EditorStyles.popup)) { - BoneSelectorContextMenu(str, ((SkeletonUtilityBone)target).hierarchy.skeletonRenderer.skeleton.Bones, "", TargetBoneSelected); + BoneSelectorContextMenu(str, ((SkeletonUtilityBone)target).hierarchy.Skeleton.Bones, "", TargetBoneSelected); } } } @@ -316,7 +319,7 @@ namespace Spine.Unity.Editor { GameObject commonParentObject = new GameObject(skeletonUtility.name + " HingeChain Parent " + utilityBone.name); var commonParentActivateOnFlip = commonParentObject.AddComponent(); - commonParentActivateOnFlip.skeletonRenderer = skeletonUtility.skeletonRenderer; + commonParentActivateOnFlip.skeletonRenderer = skeletonUtility.SkeletonComponent; // HingeChain Parent // Needs to be on top hierarchy level (not attached to the moving skeleton at least) for physics to apply proper momentum. @@ -391,7 +394,7 @@ namespace Spine.Unity.Editor { GameObject mirroredChain = GameObject.Instantiate(normalChainParentObject, normalChainParentObject.transform.position, normalChainParentObject.transform.rotation, commonParentActivateOnFlip.transform); mirroredChain.name = normalChainParentObject.name + " FlippedX"; - + commonParentActivateOnFlip.activeOnFlippedX = mirroredChain; var followerKinematicObject = mirroredChain.GetComponentInChildren(); @@ -405,7 +408,7 @@ namespace Spine.Unity.Editor { var joint = childBoneJoints[i]; FlipBone2DHorizontal(joint.transform, skeletonUtilityRoot); ApplyJoint2DAngleLimits(joint, rotationLimit, parentTransformForAngles, joint.transform); - + GameObject rotatedChild = GameObject.Instantiate(joint.gameObject, joint.transform, true); rotatedChild.name = joint.name + " rotated"; var rotationEulerAngles = rotatedChild.transform.localEulerAngles; @@ -446,9 +449,9 @@ namespace Spine.Unity.Editor { UnityEditor.EditorUtility.DisplayDialog("No parent SkeletonUtilityBone found!", "Please select the first physically moving chain node, having a parent GameObject with a SkeletonUtilityBone component attached.", "OK"); return; } - + SetSkeletonUtilityToFlipByRotation(); - + kinematicParentUtilityBone.mode = SkeletonUtilityBone.Mode.Follow; kinematicParentUtilityBone.position = kinematicParentUtilityBone.rotation = kinematicParentUtilityBone.scale = kinematicParentUtilityBone.zPosition = true; @@ -476,7 +479,7 @@ namespace Spine.Unity.Editor { childBone.transform.SetParent(chainParentObject.transform, true); // we need a flat hierarchy of all Joint objects in Unity. AttachRigidbodyAndCollider(childBone); childBone.mode = SkeletonUtilityBone.Mode.Override; - + HingeJoint joint = childBone.gameObject.AddComponent(); joint.axis = Vector3.forward; joint.connectedBody = childBoneParentReference.GetComponent(); diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonUtilityInspector.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonUtilityInspector.cs index c7f92c4e4..d20f00fbb 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonUtilityInspector.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonUtilityInspector.cs @@ -47,8 +47,9 @@ namespace Spine.Unity.Editor { SkeletonUtility skeletonUtility; Skeleton skeleton; SkeletonRenderer skeletonRenderer; + SkeletonGraphic skeletonGraphic; - #if !NEW_PREFAB_SYSTEM +#if !NEW_PREFAB_SYSTEM bool isPrefab; #endif @@ -56,16 +57,24 @@ namespace Spine.Unity.Editor { void OnEnable () { skeletonUtility = (SkeletonUtility)target; - skeletonRenderer = skeletonUtility.GetComponent(); - skeleton = skeletonRenderer.Skeleton; + skeletonRenderer = skeletonUtility.skeletonRenderer; + skeletonGraphic = skeletonUtility.skeletonGraphic; + skeleton = skeletonUtility.Skeleton; if (skeleton == null) { - skeletonRenderer.Initialize(false); - skeletonRenderer.LateUpdate(); - skeleton = skeletonRenderer.skeleton; + if (skeletonRenderer != null) { + skeletonRenderer.Initialize(false); + skeletonRenderer.LateUpdate(); + } + else if (skeletonGraphic != null) { + skeletonGraphic.Initialize(false); + skeletonGraphic.LateUpdate(); + } + skeleton = skeletonUtility.Skeleton; } - if (!skeletonRenderer.valid) return; + if ((skeletonRenderer != null && !skeletonRenderer.valid) || + (skeletonGraphic != null && !skeletonGraphic.IsValid)) return; #if !NEW_PREFAB_SYSTEM isPrefab |= PrefabUtility.GetPrefabType(this.target) == PrefabType.Prefab; @@ -83,7 +92,8 @@ namespace Spine.Unity.Editor { serializedObject.Update(); - if (!skeletonRenderer.valid) { + if ((skeletonRenderer != null && !skeletonRenderer.valid) || + (skeletonGraphic != null && !skeletonGraphic.IsValid)) { GUILayout.Label(new GUIContent("Spine Component invalid. Check Skeleton Data Asset.", Icons.warning)); return; } @@ -131,7 +141,7 @@ namespace Spine.Unity.Editor { } public static void AttachIcon (SkeletonUtilityBone boneComponent) { - Skeleton skeleton = boneComponent.hierarchy.skeletonRenderer.skeleton; + Skeleton skeleton = boneComponent.hierarchy.Skeleton; Texture2D icon = boneComponent.bone.Data.Length == 0 ? Icons.nullBone : Icons.boneNib; foreach (IkConstraint c in skeleton.IkConstraints) diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs index 28ec5b141..0579fee2a 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs @@ -227,6 +227,11 @@ namespace Spine.Unity { public SkeletonData SkeletonData { get { return skeleton == null ? null : skeleton.data; } } public bool IsValid { get { return skeleton != null; } } + public delegate void SkeletonRendererDelegate (SkeletonGraphic skeletonGraphic); + + /// OnRebuild is raised after the Skeleton is successfully initialized. + public event SkeletonRendererDelegate OnRebuild; + protected Spine.AnimationState state; public Spine.AnimationState AnimationState { get { return state; } } @@ -320,6 +325,9 @@ namespace Spine.Unity { Update(0f); } } + + if (OnRebuild != null) + OnRebuild(this); } public void UpdateMesh () { diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonUtility/ActivateBasedOnFlipDirection.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonUtility/ActivateBasedOnFlipDirection.cs index a025187fd..4d98ce16e 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonUtility/ActivateBasedOnFlipDirection.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonUtility/ActivateBasedOnFlipDirection.cs @@ -38,8 +38,8 @@ namespace Spine.Unity { /// do not attempt to use this component for other purposes. /// public class ActivateBasedOnFlipDirection : MonoBehaviour { - - public SkeletonRenderer skeletonRenderer; + + public ISkeletonComponent skeletonRenderer; public GameObject activeOnNormalX; public GameObject activeOnFlippedX; HingeJoint2D[] jointsNormalX; diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonUtility/SkeletonUtility.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonUtility/SkeletonUtility.cs index aab8ccd77..09606dc0e 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonUtility/SkeletonUtility.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonUtility/SkeletonUtility.cs @@ -139,7 +139,7 @@ namespace Spine.Unity { public bool flipBy180DegreeRotation = false; void Update () { - var skeleton = skeletonRenderer.skeleton; + var skeleton = skeletonComponent.Skeleton; if (skeleton != null && boneRoot != null) { if (flipBy180DegreeRotation) { @@ -151,14 +151,51 @@ namespace Spine.Unity { else { boneRoot.localScale = new Vector3(skeleton.ScaleX, skeleton.ScaleY, 1f); } - } + } + + if (canvas != null) { + positionScale = canvas.referencePixelsPerUnit; + } } [HideInInspector] public SkeletonRenderer skeletonRenderer; - [HideInInspector] public ISkeletonAnimation skeletonAnimation; + [HideInInspector] public SkeletonGraphic skeletonGraphic; + private Canvas canvas; + [System.NonSerialized] public ISkeletonAnimation skeletonAnimation; + + private ISkeletonComponent skeletonComponent; [System.NonSerialized] public List boneComponents = new List(); [System.NonSerialized] public List constraintComponents = new List(); + + public ISkeletonComponent SkeletonComponent { + get { + if (skeletonComponent == null) { + skeletonComponent = skeletonRenderer != null ? skeletonRenderer.GetComponent() : + skeletonGraphic != null ? skeletonGraphic.GetComponent() : + GetComponent(); + } + return skeletonComponent; + } + } + public Skeleton Skeleton { + get { + if (SkeletonComponent == null) + return null; + return skeletonComponent.Skeleton; + } + } + + public bool IsValid { + get { + return (skeletonRenderer != null && skeletonRenderer.valid) || + (skeletonGraphic != null && skeletonGraphic.IsValid); + } + } + + public float PositionScale { get { return positionScale; } } + + float positionScale = 1.0f; bool hasOverrideBones; bool hasConstraints; bool needToReprocessBones; @@ -167,18 +204,38 @@ namespace Spine.Unity { OnDisable(); OnEnable(); } - + void OnEnable () { if (skeletonRenderer == null) { skeletonRenderer = GetComponent(); } - + if (skeletonGraphic == null) { + skeletonGraphic = GetComponent(); + } if (skeletonAnimation == null) { - skeletonAnimation = GetComponent(typeof(ISkeletonAnimation)) as ISkeletonAnimation; + skeletonAnimation = skeletonRenderer != null ? skeletonRenderer.GetComponent() : + skeletonGraphic != null ? skeletonGraphic.GetComponent() : + GetComponent(); + } + if (skeletonComponent == null) { + skeletonComponent = skeletonRenderer != null ? skeletonRenderer.GetComponent() : + skeletonGraphic != null ? skeletonGraphic.GetComponent() : + GetComponent(); } - skeletonRenderer.OnRebuild -= HandleRendererReset; - skeletonRenderer.OnRebuild += HandleRendererReset; + if (skeletonRenderer != null) { + skeletonRenderer.OnRebuild -= HandleRendererReset; + skeletonRenderer.OnRebuild += HandleRendererReset; + } + else if (skeletonGraphic != null) { + skeletonGraphic.OnRebuild -= HandleRendererReset; + skeletonGraphic.OnRebuild += HandleRendererReset; + canvas = skeletonGraphic.canvas; + if (canvas == null) + canvas = skeletonGraphic.GetComponentInParent(); + if (canvas == null) + positionScale = 100.0f; + } if (skeletonAnimation != null) { skeletonAnimation.UpdateLocal -= UpdateLocal; @@ -194,7 +251,10 @@ namespace Spine.Unity { } void OnDisable () { - skeletonRenderer.OnRebuild -= HandleRendererReset; + if (skeletonRenderer != null) + skeletonRenderer.OnRebuild -= HandleRendererReset; + if (skeletonGraphic != null) + skeletonGraphic.OnRebuild -= HandleRendererReset; if (skeletonAnimation != null) { skeletonAnimation.UpdateLocal -= UpdateLocal; @@ -208,6 +268,11 @@ namespace Spine.Unity { CollectBones(); } + void HandleRendererReset (SkeletonGraphic g) { + if (OnReset != null) OnReset(); + CollectBones(); + } + public void RegisterBone (SkeletonUtilityBone bone) { if (boneComponents.Contains(bone)) { return; @@ -235,7 +300,7 @@ namespace Spine.Unity { } public void CollectBones () { - var skeleton = skeletonRenderer.skeleton; + var skeleton = skeletonComponent.Skeleton; if (skeleton == null) return; if (boneRoot != null) { @@ -315,12 +380,16 @@ namespace Spine.Unity { if (boneRoot != null) return boneRoot; - boneRoot = new GameObject("SkeletonUtility-SkeletonRoot").transform; + var boneRootObject = new GameObject("SkeletonUtility-SkeletonRoot"); #if UNITY_EDITOR if (!Application.isPlaying) - UnityEditor.Undo.RegisterCreatedObjectUndo(boneRoot.gameObject, "Spawn Bone"); + UnityEditor.Undo.RegisterCreatedObjectUndo(boneRootObject, "Spawn Bone"); #endif - boneRoot.parent = transform; + if (skeletonGraphic != null) + boneRootObject.AddComponent(); + + boneRoot = boneRootObject.transform; + boneRoot.SetParent(transform); boneRoot.localPosition = Vector3.zero; boneRoot.localRotation = Quaternion.identity; boneRoot.localScale = Vector3.one; @@ -330,7 +399,7 @@ namespace Spine.Unity { public GameObject SpawnRoot (SkeletonUtilityBone.Mode mode, bool pos, bool rot, bool sca) { GetBoneRoot(); - Skeleton skeleton = this.skeletonRenderer.skeleton; + Skeleton skeleton = this.skeletonComponent.Skeleton; GameObject go = SpawnBone(skeleton.RootBone, boneRoot, mode, pos, rot, sca); CollectBones(); @@ -339,7 +408,7 @@ namespace Spine.Unity { public GameObject SpawnHierarchy (SkeletonUtilityBone.Mode mode, bool pos, bool rot, bool sca) { GetBoneRoot(); - Skeleton skeleton = this.skeletonRenderer.skeleton; + Skeleton skeleton = this.skeletonComponent.Skeleton; GameObject go = SpawnBoneRecursively(skeleton.RootBone, boneRoot, mode, pos, rot, sca); CollectBones(); return go; @@ -363,8 +432,11 @@ namespace Spine.Unity { if (!Application.isPlaying) UnityEditor.Undo.RegisterCreatedObjectUndo(go, "Spawn Bone"); #endif + if (skeletonGraphic != null) + go.AddComponent(); + var goTransform = go.transform; - goTransform.parent = parent; + goTransform.SetParent(parent); SkeletonUtilityBone b = go.AddComponent(); b.hierarchy = this; @@ -380,7 +452,7 @@ namespace Spine.Unity { if (mode == SkeletonUtilityBone.Mode.Override) { if (rot) goTransform.localRotation = Quaternion.Euler(0, 0, b.bone.AppliedRotation); - if (pos) goTransform.localPosition = new Vector3(b.bone.X, b.bone.Y, 0); + if (pos) goTransform.localPosition = new Vector3(b.bone.X * positionScale, b.bone.Y * positionScale, 0); goTransform.localScale = new Vector3(b.bone.scaleX, b.bone.scaleY, 0); } diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonUtility/SkeletonUtilityBone.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonUtility/SkeletonUtilityBone.cs index e86ed62ac..b2595c745 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonUtility/SkeletonUtilityBone.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonUtility/SkeletonUtilityBone.cs @@ -75,7 +75,7 @@ namespace Spine.Unity { public void Reset () { bone = null; cachedTransform = transform; - valid = hierarchy != null && hierarchy.skeletonRenderer != null && hierarchy.skeletonRenderer.valid; + valid = hierarchy != null && hierarchy.IsValid; if (!valid) return; skeletonTransform = hierarchy.transform; @@ -109,7 +109,7 @@ namespace Spine.Unity { return; } - var skeleton = hierarchy.skeletonRenderer.skeleton; + var skeleton = hierarchy.Skeleton; if (bone == null) { if (string.IsNullOrEmpty(boneName)) return; @@ -121,13 +121,15 @@ namespace Spine.Unity { } if (!bone.Active) return; + float positionScale = hierarchy.PositionScale; + var thisTransform = cachedTransform; float skeletonFlipRotation = Mathf.Sign(skeleton.ScaleX * skeleton.ScaleY); if (mode == Mode.Follow) { switch (phase) { case UpdatePhase.Local: if (position) - thisTransform.localPosition = new Vector3(bone.x, bone.y, 0); + thisTransform.localPosition = new Vector3(bone.x * positionScale, bone.y * positionScale, 0); if (rotation) { if (bone.data.transformMode.InheritsRotation()) { @@ -151,7 +153,7 @@ namespace Spine.Unity { } if (position) - thisTransform.localPosition = new Vector3(bone.ax, bone.ay, 0); + thisTransform.localPosition = new Vector3(bone.ax * positionScale, bone.ay * positionScale, 0); if (rotation) { if (bone.data.transformMode.InheritsRotation()) { @@ -175,7 +177,7 @@ namespace Spine.Unity { if (parentReference == null) { if (position) { - Vector3 clp = thisTransform.localPosition; + Vector3 clp = thisTransform.localPosition / positionScale; bone.x = Mathf.Lerp(bone.x, clp.x, overrideAlpha); bone.y = Mathf.Lerp(bone.y, clp.y, overrideAlpha); } @@ -197,7 +199,7 @@ namespace Spine.Unity { return; if (position) { - Vector3 pos = parentReference.InverseTransformPoint(thisTransform.position); + Vector3 pos = parentReference.InverseTransformPoint(thisTransform.position) / positionScale; bone.x = Mathf.Lerp(bone.x, pos.x, overrideAlpha); bone.y = Mathf.Lerp(bone.y, pos.y, overrideAlpha); }