diff --git a/spine-csharp/src/Skeleton.cs b/spine-csharp/src/Skeleton.cs index 896d0a4ad..fbe17c76f 100644 --- a/spine-csharp/src/Skeleton.cs +++ b/spine-csharp/src/Skeleton.cs @@ -502,14 +502,16 @@ namespace Spine { var regionAttachment = attachment as RegionAttachment; if (regionAttachment != null) { verticesLength = 8; - if (temp.Length < 8) temp = new float[8]; + vertices = temp; + if (vertices.Length < 8) vertices = temp = new float[8]; regionAttachment.ComputeWorldVertices(slot.bone, temp, 0); } else { var meshAttachment = attachment as MeshAttachment; if (meshAttachment != null) { MeshAttachment mesh = meshAttachment; verticesLength = mesh.WorldVerticesLength; - if (temp.Length < verticesLength) temp = new float[verticesLength]; + vertices = temp; + if (vertices.Length < verticesLength) vertices = temp = new float[verticesLength]; mesh.ComputeWorldVertices(slot, 0, verticesLength, temp, 0); } } diff --git a/spine-csharp/src/SkeletonJson.cs b/spine-csharp/src/SkeletonJson.cs index 3cfbdc76f..848adb4a5 100644 --- a/spine-csharp/src/SkeletonJson.cs +++ b/spine-csharp/src/SkeletonJson.cs @@ -420,10 +420,17 @@ namespace Spine { ClippingAttachment clip = attachmentLoader.NewClippingAttachment(skin, name); if (clip == null) return null; - SlotData slot = skeletonData.FindSlot(GetString(map, "end", null)); - if (slot == null) throw new Exception("Clipping end slot not found: " + GetString(map, "end", null)); - clip.endSlot = slot; + string end = GetString(map, "end", null); + if (end != null) { + SlotData slot = skeletonData.FindSlot(end); + if (slot == null) throw new Exception("Clipping end slot not found: " + end); + clip.EndSlot = slot; + } + ReadVertices(map, clip, GetInt(map, "vertexCount", 0) << 1); + + //string color = GetString(map, "color", null); + // if (color != null) clip.color = color; return clip; } } diff --git a/spine-lua/Skin.lua b/spine-lua/Skin.lua index c0090af53..f0c1c5fda 100644 --- a/spine-lua/Skin.lua +++ b/spine-lua/Skin.lua @@ -63,21 +63,24 @@ function Skin:getAttachment (slotIndex, name) end function Skin:attachAll(skeleton, oldSkin) - local slotIndex = 0 for i, slot in ipairs(skeleton.slots) do local slotAttachment = slot.attachment - if slotAttachment and slotIndex <= #oldSkin.attachments then - local dictionary = oldSkin.attachments[slotIndex] - for key, value in dictionary do - local skinAttachment = value - if slotAttachment == skinAttachment then - local attachment = getAttachment(slotIndex, key) - if attachment then slot.attachment = attachment end - break + if slotAttachment then + local dictionary = oldSkin.attachments[i] + if (dictionary) then + for key, value in pairs(dictionary) do + local skinAttachment = value + if slotAttachment == skinAttachment then + local attachment = self:getAttachment(i, key) + if attachment then + print("Set attachment " .. attachment.name .. " on slot " .. slot.data.name) + slot:setAttachment(attachment) + end + break + end end end end - slotIndex = slotIndex + 1 end end diff --git a/spine-lua/attachments/MeshAttachment.lua b/spine-lua/attachments/MeshAttachment.lua index dee325a01..400aa665e 100644 --- a/spine-lua/attachments/MeshAttachment.lua +++ b/spine-lua/attachments/MeshAttachment.lua @@ -103,6 +103,7 @@ function MeshAttachment:setParentMesh (parentMesh) if parentMesh then self.bones = parentMesh.bones self.vertices = parentMesh.vertices + self.worldVerticesLength = parentMesh.worldVerticesLength self.regionUVs = parentMesh.regionUVs self.triangles = parentMesh.triangles self.hullLength = parentMesh.hullLength diff --git a/spine-unity/Assets/Examples/Getting Started/6 SkeletonGraphic.unity b/spine-unity/Assets/Examples/Getting Started/6 SkeletonGraphic.unity index 527adc097..0e6c167c3 100644 --- a/spine-unity/Assets/Examples/Getting Started/6 SkeletonGraphic.unity +++ b/spine-unity/Assets/Examples/Getting Started/6 SkeletonGraphic.unity @@ -135,13 +135,14 @@ RectTransform: m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: + - {fileID: 759111375} - {fileID: 189134935} m_Father: {fileID: 289700665} - m_RootOrder: 0 + m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: -13.605, y: 239} + m_AnchoredPosition: {x: -13.604996, y: 239} m_SizeDelta: {x: 491, y: 708} m_Pivot: {x: 0.5, y: 0.14047737} --- !u!114 &57002145 @@ -165,6 +166,8 @@ MonoBehaviour: Version=1.0.0.0, Culture=neutral, PublicKeyToken=null skeletonDataAsset: {fileID: 11400000, guid: 3c48535ae5679204c950a22a7caaa5a4, type: 2} initialSkinName: default + initialFlipX: 0 + initialFlipY: 0 startingAnimation: main startingLoop: 1 timeScale: 1 @@ -185,6 +188,99 @@ CanvasRenderer: m_PrefabParentObject: {fileID: 0} m_PrefabInternal: {fileID: 0} m_GameObject: {fileID: 57002143} +--- !u!1 &140863499 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + serializedVersion: 5 + m_Component: + - component: {fileID: 140863500} + - component: {fileID: 140863503} + - component: {fileID: 140863502} + - component: {fileID: 140863501} + m_Layer: 5 + m_Name: Detached BoneFollowerGraphic + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &140863500 +RectTransform: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 140863499} + m_LocalRotation: {x: -0, y: -0, z: 0.6421143, w: 0.766609} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 289700665} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -11.670258, y: 578.2387} + m_SizeDelta: {x: 100, y: 54.64} + m_Pivot: {x: -0.15, y: -2.04} +--- !u!114 &140863501 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 140863499} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 708705254, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI, + Version=1.0.0.0, Culture=neutral, PublicKeyToken=null + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 50 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 5 + m_MaxSize: 50 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 1 + m_VerticalOverflow: 1 + m_LineSpacing: 1 + m_Text: Hello +--- !u!222 &140863502 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 140863499} +--- !u!114 &140863503 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 140863499} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b42a195b47491d34b9bcbc40898bcb29, type: 3} + m_Name: + m_EditorClassIdentifier: + skeletonGraphic: {fileID: 57002145} + initializeOnAwake: 1 + boneName: head + followBoneRotation: 1 + followSkeletonFlip: 1 + followLocalScale: 0 + followZPosition: 1 --- !u!1 &189134934 GameObject: m_ObjectHideFlags: 0 @@ -213,7 +309,7 @@ RectTransform: m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 57002144} - m_RootOrder: 0 + m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 1} m_AnchorMax: {x: 0.5, y: 1} @@ -379,6 +475,7 @@ RectTransform: m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: + - {fileID: 140863500} - {fileID: 57002144} - {fileID: 1384013133} m_Father: {fileID: 2133858527} @@ -478,6 +575,99 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &759111374 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + serializedVersion: 5 + m_Component: + - component: {fileID: 759111375} + - component: {fileID: 759111378} + - component: {fileID: 759111377} + - component: {fileID: 759111376} + m_Layer: 5 + m_Name: Child BoneFollowerGraphic + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &759111375 +RectTransform: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 759111374} + m_LocalRotation: {x: 0, y: 0, z: 0.012748675, w: 0.99991876} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 57002144} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 214.28879, y: 127.327515} + m_SizeDelta: {x: 35.7, y: 54.1} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &759111376 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 759111374} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 708705254, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI, + Version=1.0.0.0, Culture=neutral, PublicKeyToken=null + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 24 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 50 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 1 + m_VerticalOverflow: 1 + m_LineSpacing: 1 + m_Text: World! +--- !u!222 &759111377 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 759111374} +--- !u!114 &759111378 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 759111374} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b42a195b47491d34b9bcbc40898bcb29, type: 3} + m_Name: + m_EditorClassIdentifier: + skeletonGraphic: {fileID: 57002145} + initializeOnAwake: 1 + boneName: handL + followBoneRotation: 1 + followSkeletonFlip: 1 + followLocalScale: 0 + followZPosition: 1 --- !u!1 &774800193 GameObject: m_ObjectHideFlags: 0 @@ -912,7 +1102,7 @@ RectTransform: m_Children: - {fileID: 1066372096} m_Father: {fileID: 289700665} - m_RootOrder: 1 + m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} @@ -940,6 +1130,8 @@ MonoBehaviour: Version=1.0.0.0, Culture=neutral, PublicKeyToken=null skeletonDataAsset: {fileID: 11400000, guid: a467507a4ffb1d542a558739b2fede77, type: 2} initialSkinName: base + initialFlipX: 0 + initialFlipY: 0 startingAnimation: run startingLoop: 1 timeScale: 1 diff --git a/spine-unity/Assets/Examples/Other Examples/Mix and Match.unity b/spine-unity/Assets/Examples/Other Examples/Mix and Match.unity index 5f9aa6cc5..5d65e1420 100644 --- a/spine-unity/Assets/Examples/Other Examples/Mix and Match.unity +++ b/spine-unity/Assets/Examples/Other Examples/Mix and Match.unity @@ -1299,3 +1299,65 @@ SpriteRenderer: m_AdaptiveModeThreshold: 0.5 m_SpriteTileMode: 0 m_WasSpriteAssigned: 1 +--- !u!1 &2010453060 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + serializedVersion: 5 + m_Component: + - component: {fileID: 2010453063} + - component: {fileID: 2010453062} + - component: {fileID: 2010453061} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &2010453061 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 2010453060} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1077351063, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalAxis: Horizontal + m_VerticalAxis: Vertical + m_SubmitButton: Submit + m_CancelButton: Cancel + m_InputActionsPerSecond: 10 + m_RepeatDelay: 0.5 + m_ForceModuleActive: 0 +--- !u!114 &2010453062 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 2010453060} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -619905303, guid: f70555f144d8491a825f0804e09c671c, type: 3} + m_Name: + m_EditorClassIdentifier: + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 5 +--- !u!4 &2010453063 +Transform: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 2010453060} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} diff --git a/spine-unity/Assets/Examples/Scripts/MixAndMatch.cs b/spine-unity/Assets/Examples/Scripts/MixAndMatch.cs index e48427cd2..9f0e69ea9 100644 --- a/spine-unity/Assets/Examples/Scripts/MixAndMatch.cs +++ b/spine-unity/Assets/Examples/Scripts/MixAndMatch.cs @@ -54,6 +54,7 @@ namespace Spine.Unity.Examples { [Header("Runtime Repack")] public bool repack = true; + public BoundingBoxFollower bbFollower; [Header("Do not assign")] public Texture2D runtimeAtlas; @@ -122,6 +123,7 @@ namespace Spine.Unity.Examples { repackedSkin.Append(customSkin); repackedSkin = repackedSkin.GetRepackedSkin("repacked skin", sourceMaterial, out runtimeMaterial, out runtimeAtlas); skeleton.SetSkin(repackedSkin); + if (bbFollower != null) bbFollower.Initialize(true); } else { skeleton.SetSkin(customSkin); } diff --git a/spine-unity/Assets/Examples/Scripts/Sample Components/Legacy/AtlasRegionAttacher.cs b/spine-unity/Assets/Examples/Scripts/Sample Components/Legacy/AtlasRegionAttacher.cs index 319f1bea9..253f62ecf 100644 --- a/spine-unity/Assets/Examples/Scripts/Sample Components/Legacy/AtlasRegionAttacher.cs +++ b/spine-unity/Assets/Examples/Scripts/Sample Components/Legacy/AtlasRegionAttacher.cs @@ -62,6 +62,7 @@ namespace Spine.Unity.Modules { if (!this.enabled) return; atlas = atlasAsset.GetAtlas(); + if (atlas == null) return; float scale = skeletonRenderer.skeletonDataAsset.scale; foreach (var entry in attachments) { diff --git a/spine-unity/Assets/spine-unity/Asset Types/SkeletonDataAsset.cs b/spine-unity/Assets/spine-unity/Asset Types/SkeletonDataAsset.cs index deaf151b3..f1846e0c8 100644 --- a/spine-unity/Assets/spine-unity/Asset Types/SkeletonDataAsset.cs +++ b/spine-unity/Assets/spine-unity/Asset Types/SkeletonDataAsset.cs @@ -98,7 +98,7 @@ namespace Spine.Unity { return null; } - // Support attachmentless/skinless SkeletonData. + // Disabled to support attachmentless/skinless SkeletonData. // if (atlasAssets == null) { // atlasAssets = new AtlasAsset[0]; // if (!quiet) diff --git a/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs b/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs index ab0d8283d..52a414894 100644 --- a/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs +++ b/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs @@ -1641,21 +1641,21 @@ namespace Spine.Unity.Editor { } } - public static void DrawBoneNames (Transform transform, Skeleton skeleton) { + public static void DrawBoneNames (Transform transform, Skeleton skeleton, float positionScale = 1f) { GUIStyle style = BoneNameStyle; foreach (Bone b in skeleton.Bones) { - var pos = new Vector3(b.WorldX, b.WorldY, 0) + (new Vector3(b.A, b.C) * (b.Data.Length * 0.5f)); + var pos = new Vector3(b.WorldX * positionScale, b.WorldY * positionScale, 0) + (new Vector3(b.A, b.C) * (b.Data.Length * 0.5f)); pos = transform.TransformPoint(pos); Handles.Label(pos, b.Data.Name, style); } } - public static void DrawBones (Transform transform, Skeleton skeleton) { + public static void DrawBones (Transform transform, Skeleton skeleton, float positionScale = 1f) { float boneScale = 1.8f; // Draw the root bone largest; - DrawCrosshairs2D(skeleton.Bones.Items[0].GetWorldPosition(transform), 0.08f); + DrawCrosshairs2D(skeleton.Bones.Items[0].GetWorldPosition(transform), 0.08f, positionScale); foreach (Bone b in skeleton.Bones) { - DrawBone(transform, b, boneScale); + DrawBone(transform, b, boneScale, positionScale); boneScale = 1f; } } @@ -1668,45 +1668,45 @@ namespace Spine.Unity.Editor { _boneWireBuffer[4] = _boneWireBuffer[0]; // closed polygon. return _boneWireBuffer; } - public static void DrawBoneWireframe (Transform transform, Bone b, Color color) { + public static void DrawBoneWireframe (Transform transform, Bone b, Color color, float skeletonRenderScale = 1f) { Handles.color = color; - var pos = new Vector3(b.WorldX, b.WorldY, 0); + var pos = new Vector3(b.WorldX * skeletonRenderScale, b.WorldY * skeletonRenderScale, 0); float length = b.Data.Length; if (length > 0) { Quaternion rot = Quaternion.Euler(0, 0, b.WorldRotationX); - Vector3 scale = Vector3.one * length * b.WorldScaleX; + Vector3 scale = Vector3.one * length * b.WorldScaleX * skeletonRenderScale; const float my = 1.5f; - scale.y *= (SpineHandles.handleScale + 1f) * 0.5f; - scale.y = Mathf.Clamp(scale.x, -my, my); + scale.y *= (SpineHandles.handleScale + 1) * 0.5f; + scale.y = Mathf.Clamp(scale.x, -my * skeletonRenderScale, my * skeletonRenderScale); Handles.DrawPolyLine(GetBoneWireBuffer(transform.localToWorldMatrix * Matrix4x4.TRS(pos, rot, scale))); var wp = transform.TransformPoint(pos); - DrawBoneCircle(wp, color, transform.forward); + DrawBoneCircle(wp, color, transform.forward, skeletonRenderScale); } else { var wp = transform.TransformPoint(pos); - DrawBoneCircle(wp, color, transform.forward); + DrawBoneCircle(wp, color, transform.forward, skeletonRenderScale); } } - public static void DrawBone (Transform transform, Bone b, float boneScale) { - var pos = new Vector3(b.WorldX, b.WorldY, 0); + public static void DrawBone (Transform transform, Bone b, float boneScale, float skeletonRenderScale = 1f) { + var pos = new Vector3(b.WorldX * skeletonRenderScale, b.WorldY * skeletonRenderScale, 0); float length = b.Data.Length; if (length > 0) { Quaternion rot = Quaternion.Euler(0, 0, b.WorldRotationX); - Vector3 scale = Vector3.one * length * b.WorldScaleX; + Vector3 scale = Vector3.one * length * b.WorldScaleX * skeletonRenderScale; const float my = 1.5f; scale.y *= (SpineHandles.handleScale + 1f) * 0.5f; - scale.y = Mathf.Clamp(scale.x, -my, my); + scale.y = Mathf.Clamp(scale.x, -my * skeletonRenderScale, my * skeletonRenderScale); SpineHandles.GetBoneMaterial().SetPass(0); Graphics.DrawMeshNow(SpineHandles.BoneMesh, transform.localToWorldMatrix * Matrix4x4.TRS(pos, rot, scale)); } else { var wp = transform.TransformPoint(pos); - DrawBoneCircle(wp, SpineHandles.BoneColor, transform.forward, boneScale); + DrawBoneCircle(wp, SpineHandles.BoneColor, transform.forward, boneScale * skeletonRenderScale); } } - public static void DrawBone (Transform transform, Bone b, float boneScale, Color color) { - var pos = new Vector3(b.WorldX, b.WorldY, 0); + public static void DrawBone (Transform transform, Bone b, float boneScale, Color color, float skeletonRenderScale = 1f) { + var pos = new Vector3(b.WorldX * skeletonRenderScale, b.WorldY * skeletonRenderScale, 0); float length = b.Data.Length; if (length > 0) { Quaternion rot = Quaternion.Euler(0, 0, b.WorldRotationX); @@ -1718,7 +1718,7 @@ namespace Spine.Unity.Editor { Graphics.DrawMeshNow(SpineHandles.BoneMesh, transform.localToWorldMatrix * Matrix4x4.TRS(pos, rot, scale)); } else { var wp = transform.TransformPoint(pos); - DrawBoneCircle(wp, color, transform.forward, boneScale); + DrawBoneCircle(wp, color, transform.forward, boneScale * skeletonRenderScale); } } @@ -1814,7 +1814,7 @@ namespace Spine.Unity.Editor { Handles.DrawLine(lastVert, firstVert); } - public static void DrawConstraints (Transform transform, Skeleton skeleton) { + public static void DrawConstraints (Transform transform, Skeleton skeleton, float skeletonRenderScale = 1f) { Vector3 targetPos; Vector3 pos; bool active; @@ -1826,19 +1826,19 @@ namespace Spine.Unity.Editor { handleColor = SpineHandles.TransformContraintColor; foreach (var tc in skeleton.TransformConstraints) { var targetBone = tc.Target; - targetPos = targetBone.GetWorldPosition(transform); + targetPos = targetBone.GetWorldPosition(transform, skeletonRenderScale); if (tc.TranslateMix > 0) { if (tc.TranslateMix != 1f) { Handles.color = handleColor; foreach (var b in tc.Bones) { - pos = b.GetWorldPosition(transform); + pos = b.GetWorldPosition(transform, skeletonRenderScale); Handles.DrawDottedLine(targetPos, pos, Thickness); } } - SpineHandles.DrawBoneCircle(targetPos, handleColor, normal, 1.3f); + SpineHandles.DrawBoneCircle(targetPos, handleColor, normal, 1.3f * skeletonRenderScale); Handles.color = handleColor; - SpineHandles.DrawCrosshairs(targetPos, 0.2f, targetBone.A, targetBone.B, targetBone.C, targetBone.D, transform); + SpineHandles.DrawCrosshairs(targetPos, 0.2f, targetBone.A, targetBone.B, targetBone.C, targetBone.D, transform, skeletonRenderScale); } } @@ -1846,25 +1846,25 @@ namespace Spine.Unity.Editor { handleColor = SpineHandles.IkColor; foreach (var ikc in skeleton.IkConstraints) { Bone targetBone = ikc.Target; - targetPos = targetBone.GetWorldPosition(transform); + targetPos = targetBone.GetWorldPosition(transform, skeletonRenderScale); var bones = ikc.Bones; active = ikc.Mix > 0; if (active) { - pos = bones.Items[0].GetWorldPosition(transform); + pos = bones.Items[0].GetWorldPosition(transform, skeletonRenderScale); switch (bones.Count) { case 1: { Handles.color = handleColor; Handles.DrawLine(targetPos, pos); SpineHandles.DrawBoneCircle(targetPos, handleColor, normal); var m = bones.Items[0].GetMatrix4x4(); - m.m03 = targetBone.WorldX; - m.m13 = targetBone.WorldY; + m.m03 = targetBone.WorldX * skeletonRenderScale; + m.m13 = targetBone.WorldY * skeletonRenderScale; SpineHandles.DrawArrowhead(transform.localToWorldMatrix * m); break; } case 2: { Bone childBone = bones.Items[1]; - Vector3 child = childBone.GetWorldPosition(transform); + Vector3 child = childBone.GetWorldPosition(transform, skeletonRenderScale); Handles.color = handleColor; Handles.DrawLine(child, pos); Handles.DrawLine(targetPos, child); @@ -1872,8 +1872,8 @@ namespace Spine.Unity.Editor { SpineHandles.DrawBoneCircle(child, handleColor, normal, 0.5f); SpineHandles.DrawBoneCircle(targetPos, handleColor, normal); var m = childBone.GetMatrix4x4(); - m.m03 = targetBone.WorldX; - m.m13 = targetBone.WorldY; + m.m03 = targetBone.WorldX * skeletonRenderScale; + m.m13 = targetBone.WorldY * skeletonRenderScale; SpineHandles.DrawArrowhead(transform.localToWorldMatrix * m); break; } @@ -1888,18 +1888,18 @@ namespace Spine.Unity.Editor { active = pc.TranslateMix > 0; if (active) foreach (var b in pc.Bones) - SpineHandles.DrawBoneCircle(b.GetWorldPosition(transform), handleColor, normal, 1f); + SpineHandles.DrawBoneCircle(b.GetWorldPosition(transform, skeletonRenderScale), handleColor, normal, 1f * skeletonRenderScale); } } - static void DrawCrosshairs2D (Vector3 position, float scale) { - scale *= SpineHandles.handleScale; + static void DrawCrosshairs2D (Vector3 position, float scale, float skeletonRenderScale = 1f) { + scale *= SpineHandles.handleScale * skeletonRenderScale; Handles.DrawLine(position + new Vector3(-scale, 0), position + new Vector3(scale, 0)); Handles.DrawLine(position + new Vector3(0, -scale), position + new Vector3(0, scale)); } - static void DrawCrosshairs (Vector3 position, float scale, float a, float b, float c, float d, Transform transform) { - scale *= SpineHandles.handleScale; + static void DrawCrosshairs (Vector3 position, float scale, float a, float b, float c, float d, Transform transform, float skeletonRenderScale = 1f) { + scale *= SpineHandles.handleScale * skeletonRenderScale; var xOffset = (Vector3)(new Vector2(a, c).normalized * scale); var yOffset = (Vector3)(new Vector2(b, d).normalized * scale); @@ -1941,7 +1941,7 @@ namespace Spine.Unity.Editor { float firstScale = 0.08f * scale; Handles.DrawSolidDisc(pos, normal, firstScale); const float Thickness = 0.03f; - float secondScale = firstScale - (Thickness * SpineHandles.handleScale); + float secondScale = firstScale - (Thickness * SpineHandles.handleScale * scale); if (secondScale > 0f) { Handles.color = new Color(0.3f, 0.3f, 0.3f, 0.5f); diff --git a/spine-unity/Assets/spine-unity/Modules/BoundingBoxFollower/BoundingBoxFollower.cs b/spine-unity/Assets/spine-unity/Modules/BoundingBoxFollower/BoundingBoxFollower.cs index 74c7029df..00e74d18b 100644 --- a/spine-unity/Assets/spine-unity/Modules/BoundingBoxFollower/BoundingBoxFollower.cs +++ b/spine-unity/Assets/spine-unity/Modules/BoundingBoxFollower/BoundingBoxFollower.cs @@ -113,9 +113,10 @@ namespace Spine.Unity { if (this.gameObject.activeInHierarchy) { foreach (var skin in skeleton.Data.Skins) - AddSkin(skin, skeleton, slotIndex); + AddSkin(skin, slotIndex); - AddSkin(skeleton.skin, skeleton, slotIndex); + if (skeleton.skin != null) + AddSkin(skeleton.skin, slotIndex); } if (BoundingBoxFollower.DebugMessages) { @@ -129,7 +130,8 @@ namespace Spine.Unity { } } - void AddSkin (Skin skin, Skeleton skeleton, int slotIndex) { + void AddSkin (Skin skin, int slotIndex) { + if (skin == null) return; var attachmentNames = new List(); skin.FindNamesForSlot(slotIndex, attachmentNames); @@ -141,12 +143,14 @@ namespace Spine.Unity { Debug.Log("BoundingBoxFollower tried to follow a slot that contains non-boundingbox attachments: " + slotName); if (boundingBoxAttachment != null) { - var bbCollider = SkeletonUtility.AddBoundingBoxAsComponent(boundingBoxAttachment, slot, gameObject, isTrigger); - bbCollider.enabled = false; - bbCollider.hideFlags = HideFlags.NotEditable; - bbCollider.isTrigger = IsTrigger; - colliderTable.Add(boundingBoxAttachment, bbCollider); - nameTable.Add(boundingBoxAttachment, skinKey); + if (!colliderTable.ContainsKey(boundingBoxAttachment)) { + var bbCollider = SkeletonUtility.AddBoundingBoxAsComponent(boundingBoxAttachment, slot, gameObject, isTrigger); + bbCollider.enabled = false; + bbCollider.hideFlags = HideFlags.NotEditable; + bbCollider.isTrigger = IsTrigger; + colliderTable.Add(boundingBoxAttachment, bbCollider); + nameTable.Add(boundingBoxAttachment, skinKey); + } } } } diff --git a/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/BoneFollowerGraphic.cs b/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/BoneFollowerGraphic.cs new file mode 100644 index 000000000..dd4e45bce --- /dev/null +++ b/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/BoneFollowerGraphic.cs @@ -0,0 +1,133 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace Spine.Unity { + [ExecuteInEditMode] + [DisallowMultipleComponent] + [AddComponentMenu("Spine/UI/BoneFollowerGraphic")] + public class BoneFollowerGraphic : MonoBehaviour { + public SkeletonGraphic skeletonGraphic; + public SkeletonGraphic SkeletonGraphic { + get { return skeletonGraphic; } + set { + skeletonGraphic = value; + Initialize(); + } + } + + public bool initializeOnAwake = true; + + /// If a bone isn't set in code, boneName is used to find the bone at the beginning. For runtime switching by name, use SetBoneByName. You can also set the BoneFollower.bone field directly. + [SpineBone(dataField: "skeletonGraphic")] + [SerializeField] public string boneName; + + public bool followBoneRotation = true; + [Tooltip("Follows the skeleton's flip state by controlling this Transform's local scale.")] + public bool followSkeletonFlip = true; + [Tooltip("Follows the target bone's local scale. BoneFollower cannot inherit world/skewed scale because of UnityEngine.Transform property limitations.")] + public bool followLocalScale = false; + public bool followZPosition = true; + + [System.NonSerialized] public Bone bone; + + Transform skeletonTransform; + bool skeletonTransformIsParent; + + [System.NonSerialized] public bool valid; + + /// + /// Sets the target bone by its bone name. Returns false if no bone was found. + public bool SetBone (string name) { + bone = skeletonGraphic.Skeleton.FindBone(name); + if (bone == null) { + Debug.LogError("Bone not found: " + name, this); + return false; + } + boneName = name; + return true; + } + + public void Awake () { + if (initializeOnAwake) Initialize(); + } + + public void Initialize () { + bone = null; + valid = skeletonGraphic != null && skeletonGraphic.IsValid; + if (!valid) return; + + skeletonTransform = skeletonGraphic.transform; +// skeletonGraphic.OnRebuild -= HandleRebuildRenderer; +// skeletonGraphic.OnRebuild += HandleRebuildRenderer; + skeletonTransformIsParent = Transform.ReferenceEquals(skeletonTransform, transform.parent); + + if (!string.IsNullOrEmpty(boneName)) + bone = skeletonGraphic.Skeleton.FindBone(boneName); + + #if UNITY_EDITOR + if (Application.isEditor) + LateUpdate(); + #endif + } + + public void LateUpdate () { + if (!valid) { + Initialize(); + return; + } + + #if UNITY_EDITOR + if (!Application.isPlaying) + skeletonTransformIsParent = Transform.ReferenceEquals(skeletonTransform, transform.parent); + #endif + + if (bone == null) { + if (string.IsNullOrEmpty(boneName)) return; + bone = skeletonGraphic.Skeleton.FindBone(boneName); + if (!SetBone(boneName)) return; + } + + var thisTransform = this.transform as RectTransform; + if (thisTransform == null) return; + + float scale = skeletonGraphic.canvas.referencePixelsPerUnit; + + if (skeletonTransformIsParent) { + // Recommended setup: Use local transform properties if Spine GameObject is the immediate parent + thisTransform.localPosition = new Vector3(bone.worldX * scale, bone.worldY * scale, followZPosition ? 0f : thisTransform.localPosition.z); + if (followBoneRotation) thisTransform.localRotation = bone.GetQuaternion(); + } else { + // For special cases: Use transform world properties if transform relationship is complicated + Vector3 targetWorldPosition = skeletonTransform.TransformPoint(new Vector3(bone.worldX * scale, bone.worldY * scale, 0f)); + if (!followZPosition) targetWorldPosition.z = thisTransform.position.z; + + float boneWorldRotation = bone.WorldRotationX; + + Transform transformParent = thisTransform.parent; + if (transformParent != null) { + Matrix4x4 m = transformParent.localToWorldMatrix; + if (m.m00 * m.m11 - m.m01 * m.m10 < 0) // Determinant2D is negative + boneWorldRotation = -boneWorldRotation; + } + + if (followBoneRotation) { + Vector3 worldRotation = skeletonTransform.rotation.eulerAngles; + #if UNITY_5_6_OR_NEWER + thisTransform.SetPositionAndRotation(targetWorldPosition, Quaternion.Euler(worldRotation.x, worldRotation.y, skeletonTransform.rotation.eulerAngles.z + boneWorldRotation)); + #else + thisTransform.position = targetWorldPosition; + thisTransform.rotation = Quaternion.Euler(worldRotation.x, worldRotation.y, skeletonTransform.rotation.eulerAngles.z + bone.WorldRotationX); + #endif + } else { + thisTransform.position = targetWorldPosition; + } + } + + Vector3 localScale = followLocalScale ? new Vector3(bone.scaleX, bone.scaleY, 1f) : new Vector3(1f, 1f, 1f); + if (followSkeletonFlip) localScale.y *= bone.skeleton.flipX ^ bone.skeleton.flipY ? -1f : 1f; + thisTransform.localScale = localScale; + } + + } +} diff --git a/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/BoneFollowerGraphic.cs.meta b/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/BoneFollowerGraphic.cs.meta new file mode 100644 index 000000000..b2279663c --- /dev/null +++ b/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/BoneFollowerGraphic.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: b42a195b47491d34b9bcbc40898bcb29 +timeCreated: 1499211965 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/Editor/BoneFollowerGraphicInspector.cs b/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/Editor/BoneFollowerGraphicInspector.cs new file mode 100644 index 000000000..1d74f0b0c --- /dev/null +++ b/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/Editor/BoneFollowerGraphicInspector.cs @@ -0,0 +1,172 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; + +using Spine.Unity; + +namespace Spine.Unity.Editor { + + using Editor = UnityEditor.Editor; + using Event = UnityEngine.Event; + + [CustomEditor(typeof(BoneFollowerGraphic)), CanEditMultipleObjects] + public class BoneFollowerGraphicInspector : Editor { + + SerializedProperty boneName, skeletonGraphic, followZPosition, followBoneRotation, followLocalScale, followSkeletonFlip; + BoneFollowerGraphic targetBoneFollower; + bool needsReset; + + #region Context Menu Item + [MenuItem ("CONTEXT/SkeletonGraphic/Add BoneFollower GameObject")] + static void AddBoneFollowerGameObject (MenuCommand cmd) { + var skeletonGraphic = cmd.context as SkeletonGraphic; + var go = new GameObject("BoneFollower", typeof(RectTransform)); + var t = go.transform; + t.SetParent(skeletonGraphic.transform); + t.localPosition = Vector3.zero; + + var f = go.AddComponent(); + f.skeletonGraphic = skeletonGraphic; + f.SetBone(skeletonGraphic.Skeleton.RootBone.Data.Name); + + EditorGUIUtility.PingObject(t); + + Undo.RegisterCreatedObjectUndo(go, "Add BoneFollowerGraphic"); + } + + // Validate + [MenuItem ("CONTEXT/SkeletonGraphic/Add BoneFollower GameObject", true)] + static bool ValidateAddBoneFollowerGameObject (MenuCommand cmd) { + var skeletonGraphic = cmd.context as SkeletonGraphic; + return skeletonGraphic.IsValid; + } + #endregion + + void OnEnable () { + skeletonGraphic = serializedObject.FindProperty("skeletonGraphic"); + boneName = serializedObject.FindProperty("boneName"); + followBoneRotation = serializedObject.FindProperty("followBoneRotation"); + followZPosition = serializedObject.FindProperty("followZPosition"); + followLocalScale = serializedObject.FindProperty("followLocalScale"); + followSkeletonFlip = serializedObject.FindProperty("followSkeletonFlip"); + + targetBoneFollower = (BoneFollowerGraphic)target; + if (targetBoneFollower.SkeletonGraphic != null) + targetBoneFollower.SkeletonGraphic.Initialize(false); + + if (!targetBoneFollower.valid || needsReset) { + targetBoneFollower.Initialize(); + targetBoneFollower.LateUpdate(); + needsReset = false; + SceneView.RepaintAll(); + } + } + + public void OnSceneGUI () { + var tbf = target as BoneFollowerGraphic; + var skeletonGraphicComponent = tbf.SkeletonGraphic; + if (skeletonGraphicComponent == null) return; + + var transform = skeletonGraphicComponent.transform; + var skeleton = skeletonGraphicComponent.Skeleton; + var canvas = skeletonGraphicComponent.canvas; + float positionScale = canvas == null ? 1f : skeletonGraphicComponent.canvas.referencePixelsPerUnit; + + if (string.IsNullOrEmpty(boneName.stringValue)) { + SpineHandles.DrawBones(transform, skeleton, positionScale); + SpineHandles.DrawBoneNames(transform, skeleton, positionScale); + Handles.Label(tbf.transform.position, "No bone selected", EditorStyles.helpBox); + } else { + var targetBone = tbf.bone; + if (targetBone == null) return; + + SpineHandles.DrawBoneWireframe(transform, targetBone, SpineHandles.TransformContraintColor, positionScale); + Handles.Label(targetBone.GetWorldPosition(transform, positionScale), targetBone.Data.Name, SpineHandles.BoneNameStyle); + } + } + + override public void OnInspectorGUI () { + if (serializedObject.isEditingMultipleObjects) { + if (needsReset) { + needsReset = false; + foreach (var o in targets) { + var bf = (BoneFollower)o; + bf.Initialize(); + bf.LateUpdate(); + } + SceneView.RepaintAll(); + } + + EditorGUI.BeginChangeCheck(); + DrawDefaultInspector(); + needsReset |= EditorGUI.EndChangeCheck(); + return; + } + + if (needsReset && Event.current.type == EventType.Layout) { + targetBoneFollower.Initialize(); + targetBoneFollower.LateUpdate(); + needsReset = false; + SceneView.RepaintAll(); + } + serializedObject.Update(); + + // Find Renderer + if (skeletonGraphic.objectReferenceValue == null) { + SkeletonGraphic parentRenderer = targetBoneFollower.GetComponentInParent(); + if (parentRenderer != null && parentRenderer.gameObject != targetBoneFollower.gameObject) { + skeletonGraphic.objectReferenceValue = parentRenderer; + Debug.Log("Inspector automatically assigned BoneFollowerGraphic.SkeletonGraphic"); + } + } + + EditorGUILayout.PropertyField(skeletonGraphic); + var skeletonGraphicComponent = skeletonGraphic.objectReferenceValue as SkeletonGraphic; + if (skeletonGraphicComponent != null) { + if (skeletonGraphicComponent.gameObject == targetBoneFollower.gameObject) { + skeletonGraphic.objectReferenceValue = null; + EditorUtility.DisplayDialog("Invalid assignment.", "BoneFollowerGraphic can only follow a skeleton on a separate GameObject.\n\nCreate a new GameObject for your BoneFollower, or choose a SkeletonGraphic from a different GameObject.", "Ok"); + } + } + + if (!targetBoneFollower.valid) { + needsReset = true; + } + + if (targetBoneFollower.valid) { + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(boneName); + needsReset |= EditorGUI.EndChangeCheck(); + + EditorGUILayout.PropertyField(followBoneRotation); + EditorGUILayout.PropertyField(followZPosition); + EditorGUILayout.PropertyField(followLocalScale); + EditorGUILayout.PropertyField(followSkeletonFlip); + + //BoneFollowerInspector.RecommendRigidbodyButton(targetBoneFollower); + } else { + var boneFollowerSkeletonGraphic = targetBoneFollower.skeletonGraphic; + if (boneFollowerSkeletonGraphic == null) { + EditorGUILayout.HelpBox("SkeletonGraphic is unassigned. Please assign a SkeletonRenderer (SkeletonAnimation or SkeletonAnimator).", MessageType.Warning); + } else { + boneFollowerSkeletonGraphic.Initialize(false); + + if (boneFollowerSkeletonGraphic.skeletonDataAsset == null) + EditorGUILayout.HelpBox("Assigned SkeletonGraphic does not have SkeletonData assigned to it.", MessageType.Warning); + + if (!boneFollowerSkeletonGraphic.IsValid) + EditorGUILayout.HelpBox("Assigned SkeletonGraphic is invalid. Check target SkeletonGraphic, its SkeletonDataAsset or the console for other errors.", MessageType.Warning); + } + } + + var current = Event.current; + bool wasUndo = (current.type == EventType.ValidateCommand && current.commandName == "UndoRedoPerformed"); + if (wasUndo) + targetBoneFollower.Initialize(); + + serializedObject.ApplyModifiedProperties(); + } + + } +} \ No newline at end of file diff --git a/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/Editor/BoneFollowerGraphicInspector.cs.meta b/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/Editor/BoneFollowerGraphicInspector.cs.meta new file mode 100644 index 000000000..b3d60a49c --- /dev/null +++ b/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/Editor/BoneFollowerGraphicInspector.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: da44a8561fd243c43a1f77bda36de0eb +timeCreated: 1499279157 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/SkeletonGraphic.cs b/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/SkeletonGraphic.cs index 510928c78..101647ba0 100644 --- a/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/SkeletonGraphic.cs +++ b/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/SkeletonGraphic.cs @@ -126,8 +126,8 @@ namespace Spine.Unity { public Texture OverrideTexture { get { return overrideTexture; } set { - canvasRenderer.SetTexture(value); overrideTexture = value; + canvasRenderer.SetTexture(this.mainTexture); // Refresh canvasRenderer's texture. Make sure it handles null. } } public override Texture mainTexture { @@ -236,6 +236,7 @@ namespace Spine.Unity { }; meshBuffers = new DoubleBuffered(); + canvasRenderer.SetTexture(this.mainTexture); // Needed for overwriting initializations. // Set the initial Skin and Animation if (!string.IsNullOrEmpty(initialSkinName)) diff --git a/spine-unity/Assets/spine-unity/SkeletonAnimator.cs b/spine-unity/Assets/spine-unity/SkeletonAnimator.cs index 68e7780f2..7d76b28ac 100644 --- a/spine-unity/Assets/spine-unity/SkeletonAnimator.cs +++ b/spine-unity/Assets/spine-unity/SkeletonAnimator.cs @@ -120,7 +120,6 @@ namespace Spine.Unity { } public void Apply (Skeleton skeleton) { - if (layerMixModes.Length < animator.layerCount) System.Array.Resize(ref layerMixModes, animator.layerCount); diff --git a/spine-unity/Assets/spine-unity/SkeletonExtensions.cs b/spine-unity/Assets/spine-unity/SkeletonExtensions.cs index 018297e75..0e2dd1f60 100644 --- a/spine-unity/Assets/spine-unity/SkeletonExtensions.cs +++ b/spine-unity/Assets/spine-unity/SkeletonExtensions.cs @@ -134,6 +134,10 @@ namespace Spine.Unity { return spineGameObjectTransform.TransformPoint(new Vector3(bone.worldX, bone.worldY)); } + public static Vector3 GetWorldPosition (this Bone bone, UnityEngine.Transform spineGameObjectTransform, float positionScale) { + return spineGameObjectTransform.TransformPoint(new Vector3(bone.worldX * positionScale, bone.worldY * positionScale)); + } + /// Gets a skeleton space UnityEngine.Quaternion representation of bone.WorldRotationX. public static Quaternion GetQuaternion (this Bone bone) { var halfRotation = Mathf.Atan2(bone.c, bone.a) * 0.5f;