[unity] BoneFollowerGraphic Component.

This commit is contained in:
pharan 2017-07-06 06:42:00 +08:00
parent 9223881909
commit 16821f0bf7
7 changed files with 567 additions and 42 deletions

View File

@ -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

View File

@ -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);

View File

@ -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;
/// <summary>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.</summary>
[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;
/// <summary>
/// Sets the target bone by its bone name. Returns false if no bone was found.</summary>
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;
}
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: b42a195b47491d34b9bcbc40898bcb29
timeCreated: 1499211965
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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<BoneFollowerGraphic>();
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<SkeletonGraphic>();
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();
}
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: da44a8561fd243c43a1f77bda36de0eb
timeCreated: 1499279157
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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));
}
/// <summary>Gets a skeleton space UnityEngine.Quaternion representation of bone.WorldRotationX.</summary>
public static Quaternion GetQuaternion (this Bone bone) {
var halfRotation = Mathf.Atan2(bone.c, bone.a) * 0.5f;