瀏覽代碼

[unity] `SkeletonGraphic` now fully supports `SkeletonUtility` for generating a hierarchy of `SkeletonUtilityBones`. Closes #1637.

Harald Csaszar 5 年之前
父節點
當前提交
016f438d59

+ 1 - 0
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.
   * 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.
     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`.
   * 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**
 * **Changes of default values**
   * `SkeletonMecanim`'s `Layer Mix Mode` now defaults to `MixMode.MixNext` instead of `MixMode.MixAlways`.
   * `SkeletonMecanim`'s `Layer Mix Mode` now defaults to `MixMode.MixNext` instead of `MixMode.MixAlways`.

+ 2 - 1
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++) {
 			for (int i = 0; i < eyes.Length; i++) {
 				center = transform.TransformPoint(origins[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);
 			}
 			}
 
 
 		}
 		}

+ 8 - 6
spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonUtility Modules/SkeletonUtilityGroundConstraint.cs

@@ -73,6 +73,8 @@ namespace Spine.Unity.Examples {
 		public override void DoUpdate () {
 		public override void DoUpdate () {
 			rayOrigin = transform.position + new Vector3(castOffset, castDistance, 0);
 			rayOrigin = transform.position + new Vector3(castOffset, castDistance, 0);
 
 
+			float positionScale = hierarchy.PositionScale;
+			float adjustDistanceThisFrame = adjustSpeed * positionScale * Time.deltaTime;
 			hitY = float.MinValue;
 			hitY = float.MinValue;
 			if (use2D) {
 			if (use2D) {
 				RaycastHit2D hit;
 				RaycastHit2D hit;
@@ -85,10 +87,10 @@ namespace Spine.Unity.Examples {
 				if (hit.collider != null) {
 				if (hit.collider != null) {
 					hitY = hit.point.y + groundOffset;
 					hitY = hit.point.y + groundOffset;
 					if (Application.isPlaying)
 					if (Application.isPlaying)
-						hitY = Mathf.MoveTowards(lastHitY, hitY, adjustSpeed * Time.deltaTime);
+						hitY = Mathf.MoveTowards(lastHitY, hitY, adjustDistanceThisFrame);
 				} else {
 				} else {
 					if (Application.isPlaying)
 					if (Application.isPlaying)
-						hitY = Mathf.MoveTowards(lastHitY, transform.position.y, adjustSpeed * Time.deltaTime);
+						hitY = Mathf.MoveTowards(lastHitY, transform.position.y, adjustDistanceThisFrame);
 				}
 				}
 			} else {
 			} else {
 				RaycastHit hit;
 				RaycastHit hit;
@@ -102,11 +104,11 @@ namespace Spine.Unity.Examples {
 				if (validHit) {
 				if (validHit) {
 					hitY = hit.point.y + groundOffset;
 					hitY = hit.point.y + groundOffset;
 					if (Application.isPlaying)
 					if (Application.isPlaying)
-						hitY = Mathf.MoveTowards(lastHitY, hitY, adjustSpeed * Time.deltaTime);
+						hitY = Mathf.MoveTowards(lastHitY, hitY, adjustDistanceThisFrame);
 
 
 				} else {
 				} else {
 					if (Application.isPlaying)
 					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);
 			v.y = Mathf.Clamp(v.y, Mathf.Min(lastHitY, hitY), float.MaxValue);
 			transform.position = v;
 			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;
 			lastHitY = hitY;
 		}
 		}

+ 40 - 0
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.
  * 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 UnityEngine;
 using UnityEditor;
 using UnityEditor;
 using Spine;
 using Spine;
 
 
 namespace Spine.Unity.Editor {
 namespace Spine.Unity.Editor {
+	using Icons = SpineEditorUtilities.Icons;
 
 
 	[InitializeOnLoad]
 	[InitializeOnLoad]
 	[CustomEditor(typeof(SkeletonGraphic))]
 	[CustomEditor(typeof(SkeletonGraphic))]
@@ -45,8 +50,32 @@ namespace Spine.Unity.Editor {
 		SerializedProperty raycastTarget;
 		SerializedProperty raycastTarget;
 
 
 		SkeletonGraphic thisSkeletonGraphic;
 		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 () {
 		void OnEnable () {
+#if NEW_PREFAB_SYSTEM
+			isInspectingPrefab = false;
+#else
+			isInspectingPrefab = (PrefabUtility.GetPrefabType(target) == PrefabType.Prefab);
+#endif
+
 			var so = this.serializedObject;
 			var so = this.serializedObject;
 			thisSkeletonGraphic = target as SkeletonGraphic;
 			thisSkeletonGraphic = target as SkeletonGraphic;
 
 
@@ -124,6 +153,17 @@ namespace Spine.Unity.Editor {
 			}
 			}
 			EditorGUILayout.EndHorizontal();
 			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<SkeletonUtility>() == null) {
+						component.gameObject.AddComponent<SkeletonUtility>();
+					}
+				}
+			}
+
 			bool wasChanged = EditorGUI.EndChangeCheck();
 			bool wasChanged = EditorGUI.EndChangeCheck();
 
 
 			if (wasChanged)
 			if (wasChanged)

+ 14 - 11
spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonUtilityBoneInspector.cs

@@ -72,8 +72,12 @@ namespace Spine.Unity.Editor {
 			skeletonUtility = utilityBone.hierarchy;
 			skeletonUtility = utilityBone.hierarchy;
 			EvaluateFlags();
 			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();
 			canCreateHingeChain = CanCreateHingeChain();
 			boundingBoxTable.Clear();
 			boundingBoxTable.Clear();
@@ -88,7 +92,7 @@ namespace Spine.Unity.Editor {
 				skin = skeleton.Data.DefaultSkin;
 				skin = skeleton.Data.DefaultSkin;
 
 
 			for(int i = 0; i < slotCount; i++){
 			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) {
 				if (slot.Bone == utilityBone.bone) {
 					var slotAttachments = new List<Skin.SkinEntry>();
 					var slotAttachments = new List<Skin.SkinEntry>();
 					int slotIndex = skeleton.FindSlotIndex(slot.Data.Name);
 					int slotIndex = skeleton.FindSlotIndex(slot.Data.Name);
@@ -105,7 +109,6 @@ namespace Spine.Unity.Editor {
 						boundingBoxTable.Add(slot, boundingBoxes);
 						boundingBoxTable.Add(slot, boundingBoxes);
 				}
 				}
 			}
 			}
-
 		}
 		}
 
 
 		void EvaluateFlags () {
 		void EvaluateFlags () {
@@ -150,7 +153,7 @@ namespace Spine.Unity.Editor {
 				using (new GUILayout.HorizontalScope()) {
 				using (new GUILayout.HorizontalScope()) {
 					EditorGUILayout.PrefixLabel("Bone");
 					EditorGUILayout.PrefixLabel("Bone");
 					if (GUILayout.Button(str, EditorStyles.popup)) {
 					if (GUILayout.Button(str, EditorStyles.popup)) {
-						BoneSelectorContextMenu(str, ((SkeletonUtilityBone)target).hierarchy.skeletonRenderer.skeleton.Bones, "<None>", TargetBoneSelected);
+						BoneSelectorContextMenu(str, ((SkeletonUtilityBone)target).hierarchy.Skeleton.Bones, "<None>", TargetBoneSelected);
 					}
 					}
 				}
 				}
 			}
 			}
@@ -316,7 +319,7 @@ namespace Spine.Unity.Editor {
 
 
 			GameObject commonParentObject = new GameObject(skeletonUtility.name + " HingeChain Parent " + utilityBone.name);
 			GameObject commonParentObject = new GameObject(skeletonUtility.name + " HingeChain Parent " + utilityBone.name);
 			var commonParentActivateOnFlip = commonParentObject.AddComponent<ActivateBasedOnFlipDirection>();
 			var commonParentActivateOnFlip = commonParentObject.AddComponent<ActivateBasedOnFlipDirection>();
-			commonParentActivateOnFlip.skeletonRenderer = skeletonUtility.skeletonRenderer;
+			commonParentActivateOnFlip.skeletonRenderer = skeletonUtility.SkeletonComponent;
 
 
 			// HingeChain Parent
 			// HingeChain Parent
 			// Needs to be on top hierarchy level (not attached to the moving skeleton at least) for physics to apply proper momentum.
 			// 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,
 			GameObject mirroredChain = GameObject.Instantiate(normalChainParentObject, normalChainParentObject.transform.position,
 				normalChainParentObject.transform.rotation, commonParentActivateOnFlip.transform);
 				normalChainParentObject.transform.rotation, commonParentActivateOnFlip.transform);
 			mirroredChain.name = normalChainParentObject.name + " FlippedX";
 			mirroredChain.name = normalChainParentObject.name + " FlippedX";
-			
+
 			commonParentActivateOnFlip.activeOnFlippedX = mirroredChain;
 			commonParentActivateOnFlip.activeOnFlippedX = mirroredChain;
 
 
 			var followerKinematicObject = mirroredChain.GetComponentInChildren<FollowLocationRigidbody2D>();
 			var followerKinematicObject = mirroredChain.GetComponentInChildren<FollowLocationRigidbody2D>();
@@ -405,7 +408,7 @@ namespace Spine.Unity.Editor {
 				var joint = childBoneJoints[i];
 				var joint = childBoneJoints[i];
 				FlipBone2DHorizontal(joint.transform, skeletonUtilityRoot);
 				FlipBone2DHorizontal(joint.transform, skeletonUtilityRoot);
 				ApplyJoint2DAngleLimits(joint, rotationLimit, parentTransformForAngles, joint.transform);
 				ApplyJoint2DAngleLimits(joint, rotationLimit, parentTransformForAngles, joint.transform);
-				
+
 				GameObject rotatedChild = GameObject.Instantiate(joint.gameObject, joint.transform, true);
 				GameObject rotatedChild = GameObject.Instantiate(joint.gameObject, joint.transform, true);
 				rotatedChild.name = joint.name + " rotated";
 				rotatedChild.name = joint.name + " rotated";
 				var rotationEulerAngles = rotatedChild.transform.localEulerAngles;
 				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");
 				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;
 				return;
 			}
 			}
-			
+
 			SetSkeletonUtilityToFlipByRotation();
 			SetSkeletonUtilityToFlipByRotation();
-			
+
 			kinematicParentUtilityBone.mode = SkeletonUtilityBone.Mode.Follow;
 			kinematicParentUtilityBone.mode = SkeletonUtilityBone.Mode.Follow;
 			kinematicParentUtilityBone.position = kinematicParentUtilityBone.rotation = kinematicParentUtilityBone.scale = kinematicParentUtilityBone.zPosition = true;
 			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.
 				childBone.transform.SetParent(chainParentObject.transform, true); // we need a flat hierarchy of all Joint objects in Unity.
 				AttachRigidbodyAndCollider(childBone);
 				AttachRigidbodyAndCollider(childBone);
 				childBone.mode = SkeletonUtilityBone.Mode.Override;
 				childBone.mode = SkeletonUtilityBone.Mode.Override;
-				
+
 				HingeJoint joint = childBone.gameObject.AddComponent<HingeJoint>();
 				HingeJoint joint = childBone.gameObject.AddComponent<HingeJoint>();
 				joint.axis = Vector3.forward;
 				joint.axis = Vector3.forward;
 				joint.connectedBody = childBoneParentReference.GetComponent<Rigidbody>();
 				joint.connectedBody = childBoneParentReference.GetComponent<Rigidbody>();

+ 19 - 9
spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonUtilityInspector.cs

@@ -47,8 +47,9 @@ namespace Spine.Unity.Editor {
 		SkeletonUtility skeletonUtility;
 		SkeletonUtility skeletonUtility;
 		Skeleton skeleton;
 		Skeleton skeleton;
 		SkeletonRenderer skeletonRenderer;
 		SkeletonRenderer skeletonRenderer;
+		SkeletonGraphic skeletonGraphic;
 
 
-		#if !NEW_PREFAB_SYSTEM
+#if !NEW_PREFAB_SYSTEM
 		bool isPrefab;
 		bool isPrefab;
 		#endif
 		#endif
 
 
@@ -56,16 +57,24 @@ namespace Spine.Unity.Editor {
 
 
 		void OnEnable () {
 		void OnEnable () {
 			skeletonUtility = (SkeletonUtility)target;
 			skeletonUtility = (SkeletonUtility)target;
-			skeletonRenderer = skeletonUtility.GetComponent<SkeletonRenderer>();
-			skeleton = skeletonRenderer.Skeleton;
+			skeletonRenderer = skeletonUtility.skeletonRenderer;
+			skeletonGraphic = skeletonUtility.skeletonGraphic;
+			skeleton = skeletonUtility.Skeleton;
 
 
 			if (skeleton == null) {
 			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
 			#if !NEW_PREFAB_SYSTEM
 			isPrefab |= PrefabUtility.GetPrefabType(this.target) == PrefabType.Prefab;
 			isPrefab |= PrefabUtility.GetPrefabType(this.target) == PrefabType.Prefab;
@@ -83,7 +92,8 @@ namespace Spine.Unity.Editor {
 
 
 			serializedObject.Update();
 			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));
 				GUILayout.Label(new GUIContent("Spine Component invalid. Check Skeleton Data Asset.", Icons.warning));
 				return;
 				return;
 			}
 			}
@@ -131,7 +141,7 @@ namespace Spine.Unity.Editor {
 		}
 		}
 
 
 		public static void AttachIcon (SkeletonUtilityBone boneComponent) {
 		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;
 			Texture2D icon = boneComponent.bone.Data.Length == 0 ? Icons.nullBone : Icons.boneNib;
 
 
 			foreach (IkConstraint c in skeleton.IkConstraints)
 			foreach (IkConstraint c in skeleton.IkConstraints)

+ 8 - 0
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 SkeletonData SkeletonData { get { return skeleton == null ? null : skeleton.data; } }
 		public bool IsValid { get { return skeleton != null; } }
 		public bool IsValid { get { return skeleton != null; } }
 
 
+		public delegate void SkeletonRendererDelegate (SkeletonGraphic skeletonGraphic);
+
+		/// <summary>OnRebuild is raised after the Skeleton is successfully initialized.</summary>
+		public event SkeletonRendererDelegate OnRebuild;
+
 		protected Spine.AnimationState state;
 		protected Spine.AnimationState state;
 		public Spine.AnimationState AnimationState { get { return state; } }
 		public Spine.AnimationState AnimationState { get { return state; } }
 
 
@@ -320,6 +325,9 @@ namespace Spine.Unity {
 						Update(0f);
 						Update(0f);
 				}
 				}
 			}
 			}
+
+			if (OnRebuild != null)
+				OnRebuild(this);
 		}
 		}
 
 
 		public void UpdateMesh () {
 		public void UpdateMesh () {

+ 2 - 2
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.
 	/// do not attempt to use this component for other purposes.
 	/// </summary>
 	/// </summary>
 	public class ActivateBasedOnFlipDirection : MonoBehaviour {
 	public class ActivateBasedOnFlipDirection : MonoBehaviour {
-	
-		public SkeletonRenderer skeletonRenderer;
+
+		public ISkeletonComponent skeletonRenderer;
 		public GameObject activeOnNormalX;
 		public GameObject activeOnNormalX;
 		public GameObject activeOnFlippedX;
 		public GameObject activeOnFlippedX;
 		HingeJoint2D[] jointsNormalX;
 		HingeJoint2D[] jointsNormalX;

+ 89 - 17
spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonUtility/SkeletonUtility.cs

@@ -139,7 +139,7 @@ namespace Spine.Unity {
 		public bool flipBy180DegreeRotation = false;
 		public bool flipBy180DegreeRotation = false;
 
 
 		void Update () {
 		void Update () {
-			var skeleton = skeletonRenderer.skeleton;
+			var skeleton = skeletonComponent.Skeleton;
 			if (skeleton != null && boneRoot != null) {
 			if (skeleton != null && boneRoot != null) {
 
 
 				if (flipBy180DegreeRotation) {
 				if (flipBy180DegreeRotation) {
@@ -151,14 +151,51 @@ namespace Spine.Unity {
 				else {
 				else {
 					boneRoot.localScale = new Vector3(skeleton.ScaleX, skeleton.ScaleY, 1f);
 					boneRoot.localScale = new Vector3(skeleton.ScaleX, skeleton.ScaleY, 1f);
 				}
 				}
-			 }
+			}
+
+			if (canvas != null) {
+				positionScale = canvas.referencePixelsPerUnit;
+			}
 		}
 		}
 
 
 		[HideInInspector] public SkeletonRenderer skeletonRenderer;
 		[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<SkeletonUtilityBone> boneComponents = new List<SkeletonUtilityBone>();
 		[System.NonSerialized] public List<SkeletonUtilityBone> boneComponents = new List<SkeletonUtilityBone>();
 		[System.NonSerialized] public List<SkeletonUtilityConstraint> constraintComponents = new List<SkeletonUtilityConstraint>();
 		[System.NonSerialized] public List<SkeletonUtilityConstraint> constraintComponents = new List<SkeletonUtilityConstraint>();
 
 
+
+		public ISkeletonComponent SkeletonComponent {
+			get {
+				if (skeletonComponent == null) {
+					skeletonComponent = skeletonRenderer != null ? skeletonRenderer.GetComponent<ISkeletonComponent>() :
+										skeletonGraphic != null ? skeletonGraphic.GetComponent<ISkeletonComponent>() :
+										GetComponent<ISkeletonComponent>();
+				}
+				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 hasOverrideBones;
 		bool hasConstraints;
 		bool hasConstraints;
 		bool needToReprocessBones;
 		bool needToReprocessBones;
@@ -167,18 +204,38 @@ namespace Spine.Unity {
 			OnDisable();
 			OnDisable();
 			OnEnable();
 			OnEnable();
 		}
 		}
-		
+
 		void OnEnable () {
 		void OnEnable () {
 			if (skeletonRenderer == null) {
 			if (skeletonRenderer == null) {
 				skeletonRenderer = GetComponent<SkeletonRenderer>();
 				skeletonRenderer = GetComponent<SkeletonRenderer>();
 			}
 			}
-
+			if (skeletonGraphic == null) {
+				skeletonGraphic = GetComponent<SkeletonGraphic>();
+			}
 			if (skeletonAnimation == null) {
 			if (skeletonAnimation == null) {
-				skeletonAnimation = GetComponent(typeof(ISkeletonAnimation)) as ISkeletonAnimation;
+				skeletonAnimation = skeletonRenderer != null ? skeletonRenderer.GetComponent<ISkeletonAnimation>() :
+									skeletonGraphic != null ? skeletonGraphic.GetComponent<ISkeletonAnimation>() :
+									GetComponent<ISkeletonAnimation>();
+			}
+			if (skeletonComponent == null) {
+				skeletonComponent = skeletonRenderer != null ? skeletonRenderer.GetComponent<ISkeletonComponent>() :
+									skeletonGraphic != null ? skeletonGraphic.GetComponent<ISkeletonComponent>() :
+									GetComponent<ISkeletonComponent>();
 			}
 			}
 
 
-			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<Canvas>();
+				if (canvas == null)
+					positionScale = 100.0f;
+			}
 
 
 			if (skeletonAnimation != null) {
 			if (skeletonAnimation != null) {
 				skeletonAnimation.UpdateLocal -= UpdateLocal;
 				skeletonAnimation.UpdateLocal -= UpdateLocal;
@@ -194,7 +251,10 @@ namespace Spine.Unity {
 		}
 		}
 
 
 		void OnDisable () {
 		void OnDisable () {
-			skeletonRenderer.OnRebuild -= HandleRendererReset;
+			if (skeletonRenderer != null)
+				skeletonRenderer.OnRebuild -= HandleRendererReset;
+			if (skeletonGraphic != null)
+				skeletonGraphic.OnRebuild -= HandleRendererReset;
 
 
 			if (skeletonAnimation != null) {
 			if (skeletonAnimation != null) {
 				skeletonAnimation.UpdateLocal -= UpdateLocal;
 				skeletonAnimation.UpdateLocal -= UpdateLocal;
@@ -208,6 +268,11 @@ namespace Spine.Unity {
 			CollectBones();
 			CollectBones();
 		}
 		}
 
 
+		void HandleRendererReset (SkeletonGraphic g) {
+			if (OnReset != null) OnReset();
+			CollectBones();
+		}
+
 		public void RegisterBone (SkeletonUtilityBone bone) {
 		public void RegisterBone (SkeletonUtilityBone bone) {
 			if (boneComponents.Contains(bone)) {
 			if (boneComponents.Contains(bone)) {
 				return;
 				return;
@@ -235,7 +300,7 @@ namespace Spine.Unity {
 		}
 		}
 
 
 		public void CollectBones () {
 		public void CollectBones () {
-			var skeleton = skeletonRenderer.skeleton;
+			var skeleton = skeletonComponent.Skeleton;
 			if (skeleton == null) return;
 			if (skeleton == null) return;
 
 
 			if (boneRoot != null) {
 			if (boneRoot != null) {
@@ -315,12 +380,16 @@ namespace Spine.Unity {
 			if (boneRoot != null)
 			if (boneRoot != null)
 				return boneRoot;
 				return boneRoot;
 
 
-			boneRoot = new GameObject("SkeletonUtility-SkeletonRoot").transform;
+			var boneRootObject = new GameObject("SkeletonUtility-SkeletonRoot");
 #if UNITY_EDITOR
 #if UNITY_EDITOR
 			if (!Application.isPlaying)
 			if (!Application.isPlaying)
-				UnityEditor.Undo.RegisterCreatedObjectUndo(boneRoot.gameObject, "Spawn Bone");
+				UnityEditor.Undo.RegisterCreatedObjectUndo(boneRootObject, "Spawn Bone");
 #endif
 #endif
-			boneRoot.parent = transform;
+			if (skeletonGraphic != null)
+				boneRootObject.AddComponent<RectTransform>();
+
+			boneRoot = boneRootObject.transform;
+			boneRoot.SetParent(transform);
 			boneRoot.localPosition = Vector3.zero;
 			boneRoot.localPosition = Vector3.zero;
 			boneRoot.localRotation = Quaternion.identity;
 			boneRoot.localRotation = Quaternion.identity;
 			boneRoot.localScale = Vector3.one;
 			boneRoot.localScale = Vector3.one;
@@ -330,7 +399,7 @@ namespace Spine.Unity {
 
 
 		public GameObject SpawnRoot (SkeletonUtilityBone.Mode mode, bool pos, bool rot, bool sca) {
 		public GameObject SpawnRoot (SkeletonUtilityBone.Mode mode, bool pos, bool rot, bool sca) {
 			GetBoneRoot();
 			GetBoneRoot();
-			Skeleton skeleton = this.skeletonRenderer.skeleton;
+			Skeleton skeleton = this.skeletonComponent.Skeleton;
 
 
 			GameObject go = SpawnBone(skeleton.RootBone, boneRoot, mode, pos, rot, sca);
 			GameObject go = SpawnBone(skeleton.RootBone, boneRoot, mode, pos, rot, sca);
 			CollectBones();
 			CollectBones();
@@ -339,7 +408,7 @@ namespace Spine.Unity {
 
 
 		public GameObject SpawnHierarchy (SkeletonUtilityBone.Mode mode, bool pos, bool rot, bool sca) {
 		public GameObject SpawnHierarchy (SkeletonUtilityBone.Mode mode, bool pos, bool rot, bool sca) {
 			GetBoneRoot();
 			GetBoneRoot();
-			Skeleton skeleton = this.skeletonRenderer.skeleton;
+			Skeleton skeleton = this.skeletonComponent.Skeleton;
 			GameObject go = SpawnBoneRecursively(skeleton.RootBone, boneRoot, mode, pos, rot, sca);
 			GameObject go = SpawnBoneRecursively(skeleton.RootBone, boneRoot, mode, pos, rot, sca);
 			CollectBones();
 			CollectBones();
 			return go;
 			return go;
@@ -363,8 +432,11 @@ namespace Spine.Unity {
 			if (!Application.isPlaying)
 			if (!Application.isPlaying)
 				UnityEditor.Undo.RegisterCreatedObjectUndo(go, "Spawn Bone");
 				UnityEditor.Undo.RegisterCreatedObjectUndo(go, "Spawn Bone");
 		#endif
 		#endif
+			if (skeletonGraphic != null)
+				go.AddComponent<RectTransform>();
+
 			var goTransform = go.transform;
 			var goTransform = go.transform;
-			goTransform.parent = parent;
+			goTransform.SetParent(parent);
 
 
 			SkeletonUtilityBone b = go.AddComponent<SkeletonUtilityBone>();
 			SkeletonUtilityBone b = go.AddComponent<SkeletonUtilityBone>();
 			b.hierarchy = this;
 			b.hierarchy = this;
@@ -380,7 +452,7 @@ namespace Spine.Unity {
 
 
 			if (mode == SkeletonUtilityBone.Mode.Override) {
 			if (mode == SkeletonUtilityBone.Mode.Override) {
 				if (rot) goTransform.localRotation = Quaternion.Euler(0, 0, b.bone.AppliedRotation);
 				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);
 				goTransform.localScale = new Vector3(b.bone.scaleX, b.bone.scaleY, 0);
 			}
 			}
 
 

+ 8 - 6
spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonUtility/SkeletonUtilityBone.cs

@@ -75,7 +75,7 @@ namespace Spine.Unity {
 		public void Reset () {
 		public void Reset () {
 			bone = null;
 			bone = null;
 			cachedTransform = transform;
 			cachedTransform = transform;
-			valid = hierarchy != null && hierarchy.skeletonRenderer != null && hierarchy.skeletonRenderer.valid;
+			valid = hierarchy != null && hierarchy.IsValid;
 			if (!valid)
 			if (!valid)
 				return;
 				return;
 			skeletonTransform = hierarchy.transform;
 			skeletonTransform = hierarchy.transform;
@@ -109,7 +109,7 @@ namespace Spine.Unity {
 				return;
 				return;
 			}
 			}
 
 
-			var skeleton = hierarchy.skeletonRenderer.skeleton;
+			var skeleton = hierarchy.Skeleton;
 
 
 			if (bone == null) {
 			if (bone == null) {
 				if (string.IsNullOrEmpty(boneName)) return;
 				if (string.IsNullOrEmpty(boneName)) return;
@@ -121,13 +121,15 @@ namespace Spine.Unity {
 			}
 			}
 			if (!bone.Active) return;
 			if (!bone.Active) return;
 
 
+			float positionScale = hierarchy.PositionScale;
+
 			var thisTransform = cachedTransform;
 			var thisTransform = cachedTransform;
 			float skeletonFlipRotation = Mathf.Sign(skeleton.ScaleX * skeleton.ScaleY);
 			float skeletonFlipRotation = Mathf.Sign(skeleton.ScaleX * skeleton.ScaleY);
 			if (mode == Mode.Follow) {
 			if (mode == Mode.Follow) {
 				switch (phase) {
 				switch (phase) {
 					case UpdatePhase.Local:
 					case UpdatePhase.Local:
 						if (position)
 						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 (rotation) {
 							if (bone.data.transformMode.InheritsRotation()) {
 							if (bone.data.transformMode.InheritsRotation()) {
@@ -151,7 +153,7 @@ namespace Spine.Unity {
 						}
 						}
 
 
 						if (position)
 						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 (rotation) {
 							if (bone.data.transformMode.InheritsRotation()) {
 							if (bone.data.transformMode.InheritsRotation()) {
@@ -175,7 +177,7 @@ namespace Spine.Unity {
 
 
 				if (parentReference == null) {
 				if (parentReference == null) {
 					if (position) {
 					if (position) {
-						Vector3 clp = thisTransform.localPosition;
+						Vector3 clp = thisTransform.localPosition / positionScale;
 						bone.x = Mathf.Lerp(bone.x, clp.x, overrideAlpha);
 						bone.x = Mathf.Lerp(bone.x, clp.x, overrideAlpha);
 						bone.y = Mathf.Lerp(bone.y, clp.y, overrideAlpha);
 						bone.y = Mathf.Lerp(bone.y, clp.y, overrideAlpha);
 					}
 					}
@@ -197,7 +199,7 @@ namespace Spine.Unity {
 						return;
 						return;
 
 
 					if (position) {
 					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.x = Mathf.Lerp(bone.x, pos.x, overrideAlpha);
 						bone.y = Mathf.Lerp(bone.y, pos.y, overrideAlpha);
 						bone.y = Mathf.Lerp(bone.y, pos.y, overrideAlpha);
 					}
 					}