From f4d9a66d568f307d1396a0415b10a1d03f87136d Mon Sep 17 00:00:00 2001 From: pharan Date: Mon, 7 Mar 2016 10:12:12 +0800 Subject: [PATCH 1/9] Cleaned up BoneFollower --- .../Assets/spine-unity/BoneFollower.cs | 58 +++++++++---------- .../Editor/BoneFollowerInspector.cs | 26 ++++----- 2 files changed, 39 insertions(+), 45 deletions(-) diff --git a/spine-unity/Assets/spine-unity/BoneFollower.cs b/spine-unity/Assets/spine-unity/BoneFollower.cs index 5cfb97b51..43c18fac8 100644 --- a/spine-unity/Assets/spine-unity/BoneFollower.cs +++ b/spine-unity/Assets/spine-unity/BoneFollower.cs @@ -40,14 +40,8 @@ using Spine; [AddComponentMenu("Spine/BoneFollower")] public class BoneFollower : MonoBehaviour { - [System.NonSerialized] - public bool - valid; + #region Inspector public SkeletonRenderer skeletonRenderer; - public Bone bone; - public bool followZPosition = true; - public bool followBoneRotation = true; - public SkeletonRenderer SkeletonRenderer { get { return skeletonRenderer; } set { @@ -55,15 +49,21 @@ public class BoneFollower : MonoBehaviour { Reset(); } } - - /// If a bone isn't set, boneName is used to find the bone. - [SpineBone(dataField: "skeletonRenderer")] public String boneName; + + public bool followZPosition = true; + public bool followBoneRotation = true; public bool resetOnAwake = true; - protected Transform cachedTransform; - protected Transform skeletonTransform; + #endregion + + [NonSerialized] + public bool valid; + + [NonSerialized] + public Bone bone; + Transform skeletonTransform; public void HandleResetRenderer (SkeletonRenderer skeletonRenderer) { Reset(); @@ -71,21 +71,21 @@ public class BoneFollower : MonoBehaviour { public void Reset () { bone = null; - cachedTransform = transform; valid = skeletonRenderer != null && skeletonRenderer.valid; - if (!valid) - return; - skeletonTransform = skeletonRenderer.transform; + if (!valid) return; + + skeletonTransform = skeletonRenderer.transform; skeletonRenderer.OnRebuild -= HandleResetRenderer; skeletonRenderer.OnRebuild += HandleResetRenderer; + #if UNITY_EDITOR if (Application.isEditor) DoUpdate(); + #endif } void OnDestroy () { - //cleanup if (skeletonRenderer != null) skeletonRenderer.OnRebuild -= HandleResetRenderer; } @@ -112,33 +112,33 @@ public class BoneFollower : MonoBehaviour { if (bone == null) { Debug.LogError("Bone not found: " + boneName, this); return; - } else { - } } - Spine.Skeleton skeleton = skeletonRenderer.skeleton; + Skeleton skeleton = skeletonRenderer.skeleton; float flipRotation = (skeleton.flipX ^ skeleton.flipY) ? -1f : 1f; + Transform thisTransform = this.transform; - if (cachedTransform.parent == skeletonTransform) { - cachedTransform.localPosition = new Vector3(bone.worldX, bone.worldY, followZPosition ? 0f : cachedTransform.localPosition.z); + // Recommended setup: Use local transform properties if Spine GameObject is parent + if (thisTransform.parent == skeletonTransform) { + thisTransform.localPosition = new Vector3(bone.worldX, bone.worldY, followZPosition ? 0f : thisTransform.localPosition.z); if (followBoneRotation) { - Vector3 rotation = cachedTransform.localRotation.eulerAngles; - cachedTransform.localRotation = Quaternion.Euler(rotation.x, rotation.y, bone.WorldRotationX * flipRotation); + Vector3 rotation = thisTransform.localRotation.eulerAngles; + thisTransform.localRotation = Quaternion.Euler(rotation.x, rotation.y, bone.WorldRotationX * flipRotation); } + // For special cases: Use transform world properties if transform relationship is complicated } else { Vector3 targetWorldPosition = skeletonTransform.TransformPoint(new Vector3(bone.worldX, bone.worldY, 0f)); if (!followZPosition) - targetWorldPosition.z = cachedTransform.position.z; + targetWorldPosition.z = thisTransform.position.z; - cachedTransform.position = targetWorldPosition; + thisTransform.position = targetWorldPosition; if (followBoneRotation) { - Vector3 rotation = skeletonTransform.rotation.eulerAngles; - - cachedTransform.rotation = Quaternion.Euler(rotation.x, rotation.y, skeletonTransform.rotation.eulerAngles.z + (bone.WorldRotationX * flipRotation)); + Vector3 worldRotation = skeletonTransform.rotation.eulerAngles; + thisTransform.rotation = Quaternion.Euler(worldRotation.x, worldRotation.y, skeletonTransform.rotation.eulerAngles.z + (bone.WorldRotationX * flipRotation)); } } diff --git a/spine-unity/Assets/spine-unity/Editor/BoneFollowerInspector.cs b/spine-unity/Assets/spine-unity/Editor/BoneFollowerInspector.cs index 5305d2b35..6f7a01bc3 100644 --- a/spine-unity/Assets/spine-unity/Editor/BoneFollowerInspector.cs +++ b/spine-unity/Assets/spine-unity/Editor/BoneFollowerInspector.cs @@ -35,7 +35,7 @@ using UnityEngine; [CustomEditor(typeof(BoneFollower))] public class BoneFollowerInspector : Editor { - private SerializedProperty boneName, skeletonRenderer, followZPosition, followBoneRotation; + SerializedProperty boneName, skeletonRenderer, followZPosition, followBoneRotation; BoneFollower component; bool needsReset; @@ -47,18 +47,7 @@ public class BoneFollowerInspector : Editor { component = (BoneFollower)target; component.skeletonRenderer.Initialize(false); } - - void FindRenderer () { - if (skeletonRenderer.objectReferenceValue == null) { - SkeletonRenderer parentRenderer = SkeletonUtility.GetInParent(component.transform); - - if (parentRenderer != null) { - skeletonRenderer.objectReferenceValue = (UnityEngine.Object)parentRenderer; - } - - } - } - + override public void OnInspectorGUI () { if (needsReset) { component.Reset(); @@ -68,7 +57,14 @@ public class BoneFollowerInspector : Editor { } serializedObject.Update(); - FindRenderer(); + // FindRenderer() + if (skeletonRenderer.objectReferenceValue == null) { + SkeletonRenderer parentRenderer = SkeletonUtility.GetInParent(component.transform); + + if (parentRenderer != null) { + skeletonRenderer.objectReferenceValue = (UnityEngine.Object)parentRenderer; + } + } EditorGUILayout.PropertyField(skeletonRenderer); @@ -81,8 +77,6 @@ public class BoneFollowerInspector : Editor { serializedObject.Update(); } - - EditorGUILayout.PropertyField(followBoneRotation); EditorGUILayout.PropertyField(followZPosition); } else { From 6950832d1e8e2a3647b4c389bf8380d6da2c3678 Mon Sep 17 00:00:00 2001 From: John Date: Wed, 9 Mar 2016 05:14:45 +0800 Subject: [PATCH 2/9] Fix SkeletonUtility Bone SceneGUI --- .../SkeletonUtility/Editor/SkeletonUtilityInspector.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/spine-unity/Assets/spine-unity/SkeletonUtility/Editor/SkeletonUtilityInspector.cs b/spine-unity/Assets/spine-unity/SkeletonUtility/Editor/SkeletonUtilityInspector.cs index e6af51945..d1f559181 100644 --- a/spine-unity/Assets/spine-unity/SkeletonUtility/Editor/SkeletonUtilityInspector.cs +++ b/spine-unity/Assets/spine-unity/SkeletonUtility/Editor/SkeletonUtilityInspector.cs @@ -96,21 +96,20 @@ public class SkeletonUtilityInspector : Editor { } - void OnDestroy () { - - } - void OnSceneGUI () { if (skeleton == null) { OnEnable(); return; } - float flipRotation = skeleton.FlipX ? -1 : 1; + // MITCH + //float flipRotation = skeleton.FlipX ? -1 : 1; + const float flipRotation = 1; foreach (Bone b in skeleton.Bones) { Vector3 vec = transform.TransformPoint(new Vector3(b.WorldX, b.WorldY, 0)); + // MITCH Quaternion rot = Quaternion.Euler(0, 0, b.WorldRotationX * flipRotation); Vector3 forward = transform.TransformDirection(rot * Vector3.right); forward *= flipRotation; From 2a244bbbe0163d23562b0984b104a3b4031dbee0 Mon Sep 17 00:00:00 2001 From: John Date: Fri, 11 Mar 2016 06:54:15 +0800 Subject: [PATCH 3/9] Explicit AnimationStateData key in C#. From user issue: http://esotericsoftware.com/forum/Performance-issue-of-KeyValuePair-5966 --- spine-csharp/src/AnimationStateData.cs | 31 +++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/spine-csharp/src/AnimationStateData.cs b/spine-csharp/src/AnimationStateData.cs index eea87429e..bf36b2c55 100644 --- a/spine-csharp/src/AnimationStateData.cs +++ b/spine-csharp/src/AnimationStateData.cs @@ -35,7 +35,7 @@ using System.Collections.Generic; namespace Spine { public class AnimationStateData { internal SkeletonData skeletonData; - private Dictionary, float> animationToMixTime = new Dictionary, float>(); + private Dictionary animationToMixTime = new Dictionary(AnimationPairComparer.Instance); internal float defaultMix; public SkeletonData SkeletonData { get { return skeletonData; } } @@ -56,16 +56,41 @@ namespace Spine { public void SetMix (Animation from, Animation to, float duration) { if (from == null) throw new ArgumentNullException("from cannot be null."); if (to == null) throw new ArgumentNullException("to cannot be null."); - KeyValuePair key = new KeyValuePair(from, to); + AnimationPair key = new AnimationPair(from, to); animationToMixTime.Remove(key); animationToMixTime.Add(key, duration); } public float GetMix (Animation from, Animation to) { - KeyValuePair key = new KeyValuePair(from, to); + AnimationPair key = new AnimationPair(from, to); float duration; if (animationToMixTime.TryGetValue(key, out duration)) return duration; return defaultMix; } + + struct AnimationPair { + public readonly Animation a1; + public readonly Animation a2; + + public AnimationPair (Animation a1, Animation a2) { + this.a1 = a1; + this.a2 = a2; + } + } + + // Avoids boxing in the dictionary. + class AnimationPairComparer : IEqualityComparer { + internal static readonly AnimationPairComparer Instance = new AnimationPairComparer(); + + bool IEqualityComparer.Equals (AnimationPair x, AnimationPair y) { + return ReferenceEquals(x.a1, y.a1) && ReferenceEquals(x.a2, y.a2); + } + + int IEqualityComparer.GetHashCode (AnimationPair obj) { + // from Tuple.CombineHashCodes // return (((h1 << 5) + h1) ^ h2); + int h1 = obj.a1.GetHashCode(); + return (((h1 << 5) + h1) ^ obj.a2.GetHashCode()); + } + } } } From 4b23116dffb8d3cd125cb2730a02e273281f28cf Mon Sep 17 00:00:00 2001 From: John Date: Fri, 11 Mar 2016 06:59:25 +0800 Subject: [PATCH 4/9] Use struct for Skin.cs https://github.com/EsotericSoftware/spine-runtimes/issues/460 --- spine-csharp/src/Skin.cs | 42 ++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/spine-csharp/src/Skin.cs b/spine-csharp/src/Skin.cs index 4c1c1edaa..2f6b86019 100644 --- a/spine-csharp/src/Skin.cs +++ b/spine-csharp/src/Skin.cs @@ -61,13 +61,13 @@ namespace Spine { public void FindNamesForSlot (int slotIndex, List names) { if (names == null) throw new ArgumentNullException("names cannot be null."); foreach (AttachmentKeyTuple key in attachments.Keys) - if (key.SlotIndex == slotIndex) names.Add(key.Name); + if (key.slotIndex == slotIndex) names.Add(key.name); } public void FindAttachmentsForSlot (int slotIndex, List attachments) { if (attachments == null) throw new ArgumentNullException("attachments cannot be null."); foreach (KeyValuePair entry in this.attachments) - if (entry.Key.SlotIndex == slotIndex) attachments.Add(entry.Value); + if (entry.Key.slotIndex == slotIndex) attachments.Add(entry.Value); } override public String ToString () { @@ -77,37 +77,37 @@ namespace Spine { /// Attach all attachments from this skin if the corresponding attachment from the old skin is currently attached. internal void AttachAll (Skeleton skeleton, Skin oldSkin) { foreach (KeyValuePair entry in oldSkin.attachments) { - int slotIndex = entry.Key.SlotIndex; + int slotIndex = entry.Key.slotIndex; Slot slot = skeleton.slots.Items[slotIndex]; if (slot.attachment == entry.Value) { - Attachment attachment = GetAttachment(slotIndex, entry.Key.Name); + Attachment attachment = GetAttachment(slotIndex, entry.Key.name); if (attachment != null) slot.Attachment = attachment; } } } - // Avoids boxing in the dictionary. - private class AttachmentKeyTupleComparer : IEqualityComparer { - internal static readonly AttachmentKeyTupleComparer Instance = new AttachmentKeyTupleComparer(); + struct AttachmentKeyTuple { + public readonly int slotIndex; + public readonly string name; + internal readonly int nameHashCode; - bool IEqualityComparer.Equals (AttachmentKeyTuple o1, AttachmentKeyTuple o2) { - return o1.SlotIndex == o2.SlotIndex && o1.NameHashCode == o2.NameHashCode && o1.Name == o2.Name; - } - - int IEqualityComparer.GetHashCode (AttachmentKeyTuple o) { - return o.SlotIndex; + public AttachmentKeyTuple (int slotIndex, string name) { + this.slotIndex = slotIndex; + this.name = name; + nameHashCode = this.name.GetHashCode(); } } - private class AttachmentKeyTuple { - public readonly int SlotIndex; - public readonly string Name; - public readonly int NameHashCode; + // Avoids boxing in the dictionary. + class AttachmentKeyTupleComparer : IEqualityComparer { + internal static readonly AttachmentKeyTupleComparer Instance = new AttachmentKeyTupleComparer(); - public AttachmentKeyTuple (int slotIndex, string name) { - SlotIndex = slotIndex; - Name = name; - NameHashCode = Name.GetHashCode(); + bool IEqualityComparer.Equals (AttachmentKeyTuple o1, AttachmentKeyTuple o2) { + return o1.slotIndex == o2.slotIndex && o1.nameHashCode == o2.nameHashCode && o1.name == o2.name; + } + + int IEqualityComparer.GetHashCode (AttachmentKeyTuple o) { + return o.slotIndex; } } } From 2f3a572ff62f5e5b4e7287cba0dc3636ce97bdc3 Mon Sep 17 00:00:00 2001 From: John Date: Sat, 12 Mar 2016 09:49:41 +0800 Subject: [PATCH 5/9] Mecanim Dummy Clip Generation Warning There was a Unity bug causing an internal Dictionary add to fail, and thus prevent existing generated Mecanim controller from being updated. Posted on the Unity forums here: http://forum.unity3d.com/threads/bug-hidden-duplicate-animationclips.391202/ --- .../spine-unity/Editor/SkeletonBaker.cs | 270 ++++++++++-------- 1 file changed, 146 insertions(+), 124 deletions(-) diff --git a/spine-unity/Assets/spine-unity/Editor/SkeletonBaker.cs b/spine-unity/Assets/spine-unity/Editor/SkeletonBaker.cs index 44ae92a43..033235775 100644 --- a/spine-unity/Assets/spine-unity/Editor/SkeletonBaker.cs +++ b/spine-unity/Assets/spine-unity/Editor/SkeletonBaker.cs @@ -4,6 +4,8 @@ * SkeletonBaker added by Mitch Thompson * Full irrevocable rights and permissions granted to Esoteric Software *****************************************************************************/ +#define SPINE_SKELETON_ANIMATOR + using UnityEngine; using UnityEditor; using UnityEditorInternal; @@ -44,6 +46,133 @@ using Spine; /// public static class SkeletonBaker { + + #region SkeletonAnimator's Mecanim Clips +#if SPINE_SKELETON_ANIMATOR + public static void GenerateMecanimAnimationClips (SkeletonDataAsset skeletonDataAsset) { + //skeletonDataAsset.Clear(); + var data = skeletonDataAsset.GetSkeletonData(true); + if (data == null) { + Debug.LogError("SkeletonData failed!", skeletonDataAsset); + return; + } + + string dataPath = AssetDatabase.GetAssetPath(skeletonDataAsset); + string controllerPath = dataPath.Replace("_SkeletonData", "_Controller").Replace(".asset", ".controller"); + +#if UNITY_5 + UnityEditor.Animations.AnimatorController controller; + + if (skeletonDataAsset.controller != null) { + controller = (UnityEditor.Animations.AnimatorController)skeletonDataAsset.controller; + controllerPath = AssetDatabase.GetAssetPath(controller); + } else { + if (File.Exists(controllerPath)) { + if (EditorUtility.DisplayDialog("Controller Overwrite Warning", "Unknown Controller already exists at: " + controllerPath, "Update", "Overwrite")) { + controller = (UnityEditor.Animations.AnimatorController)AssetDatabase.LoadAssetAtPath(controllerPath, typeof(RuntimeAnimatorController)); + } else { + controller = (UnityEditor.Animations.AnimatorController)UnityEditor.Animations.AnimatorController.CreateAnimatorControllerAtPath(controllerPath); + } + } else { + controller = (UnityEditor.Animations.AnimatorController)UnityEditor.Animations.AnimatorController.CreateAnimatorControllerAtPath(controllerPath); + } + + } +#else + UnityEditorInternal.AnimatorController controller; + + if (skeletonDataAsset.controller != null) { + controller = (UnityEditorInternal.AnimatorController)skeletonDataAsset.controller; + controllerPath = AssetDatabase.GetAssetPath(controller); + } else { + if (File.Exists(controllerPath)) { + if (EditorUtility.DisplayDialog("Controller Overwrite Warning", "Unknown Controller already exists at: " + controllerPath, "Update", "Overwrite")) { + controller = (UnityEditorInternal.AnimatorController)AssetDatabase.LoadAssetAtPath(controllerPath, typeof(RuntimeAnimatorController)); + } else { + controller = (UnityEditorInternal.AnimatorController)UnityEditorInternal.AnimatorController.CreateAnimatorControllerAtPath(controllerPath); + } + } else { + controller = (UnityEditorInternal.AnimatorController)UnityEditorInternal.AnimatorController.CreateAnimatorControllerAtPath(controllerPath); + } + } +#endif + + skeletonDataAsset.controller = controller; + EditorUtility.SetDirty(skeletonDataAsset); + + UnityEngine.Object[] objs = AssetDatabase.LoadAllAssetsAtPath(controllerPath); + + var unityAnimationClipTable = new Dictionary(); + var spineAnimationTable = new Dictionary(); + + foreach (var o in objs) { + //Debug.LogFormat("({0}){1} : {3} + {2} + {4}", o.GetType(), o.name, o.hideFlags, o.GetInstanceID(), o.GetHashCode()); + // There is a bug in Unity 5.3.3 (and likely before) that creates + // a duplicate AnimationClip when you duplicate a Mecanim Animator State. + // These duplicates seem to be identifiable by their HideFlags, so we'll exclude them. + if (o is AnimationClip) { + var clip = o as AnimationClip; + if (!clip.HasFlag(HideFlags.HideInHierarchy)) { + if (unityAnimationClipTable.ContainsKey(clip.name)) { + Debug.LogWarningFormat("Duplicate AnimationClips were found named {0}", clip.name); + } + unityAnimationClipTable.Add(clip.name, clip); + } + } + } + + foreach (var anim in data.Animations) { + string name = anim.Name; + spineAnimationTable.Add(name, anim); + + if (unityAnimationClipTable.ContainsKey(name) == false) { + //generate new dummy clip + AnimationClip newClip = new AnimationClip(); + newClip.name = name; +#if !(UNITY_5) + AnimationUtility.SetAnimationType(newClip, ModelImporterAnimationType.Generic); +#endif + AssetDatabase.AddObjectToAsset(newClip, controller); + unityAnimationClipTable.Add(name, newClip); + } + + AnimationClip clip = unityAnimationClipTable[name]; + + clip.SetCurve("", typeof(GameObject), "dummy", AnimationCurve.Linear(0, 0, anim.Duration, 0)); + var settings = AnimationUtility.GetAnimationClipSettings(clip); + settings.stopTime = anim.Duration; + + SetAnimationSettings(clip, settings); + + AnimationUtility.SetAnimationEvents(clip, new AnimationEvent[0]); + + foreach (Timeline t in anim.Timelines) { + if (t is EventTimeline) { + ParseEventTimeline((EventTimeline)t, clip, SendMessageOptions.DontRequireReceiver); + } + } + + EditorUtility.SetDirty(clip); + + unityAnimationClipTable.Remove(name); + } + + //clear no longer used animations + foreach (var clip in unityAnimationClipTable.Values) { + AnimationClip.DestroyImmediate(clip, true); + } + + AssetDatabase.Refresh(); + AssetDatabase.SaveAssets(); + } + + static bool HasFlag (this UnityEngine.Object o, HideFlags flagToCheck) { + return (o.hideFlags & flagToCheck) == flagToCheck; + } +#endif + #endregion + + #region Baking /// /// Interval between key sampling for Bezier curves, IK controlled bones, and Inherit Rotation effected bones. /// @@ -89,8 +218,8 @@ public static class SkeletonBaker { } #endif - Dictionary existingClipTable = new Dictionary(); - List unusedClipNames = new List(); + var existingClipTable = new Dictionary(); + var unusedClipNames = new List(); Object[] animObjs = AssetDatabase.LoadAllAssetsAtPath(controllerPath); foreach (Object o in animObjs) { @@ -344,115 +473,6 @@ public static class SkeletonBaker { } - public static void GenerateMecanimAnimationClips (SkeletonDataAsset skeletonDataAsset) { - var data = skeletonDataAsset.GetSkeletonData(true); - if (data == null) { - Debug.LogError("SkeletonData failed!", skeletonDataAsset); - return; - } - - string dataPath = AssetDatabase.GetAssetPath(skeletonDataAsset); - string controllerPath = dataPath.Replace("_SkeletonData", "_Controller").Replace(".asset", ".controller"); - - -#if UNITY_5 - UnityEditor.Animations.AnimatorController controller; - - if (skeletonDataAsset.controller != null) { - controller = (UnityEditor.Animations.AnimatorController)skeletonDataAsset.controller; - controllerPath = AssetDatabase.GetAssetPath(controller); - } else { - if (File.Exists(controllerPath)) { - if (EditorUtility.DisplayDialog("Controller Overwrite Warning", "Unknown Controller already exists at: " + controllerPath, "Update", "Overwrite")) { - controller = (UnityEditor.Animations.AnimatorController)AssetDatabase.LoadAssetAtPath(controllerPath, typeof(RuntimeAnimatorController)); - } else { - controller = (UnityEditor.Animations.AnimatorController)UnityEditor.Animations.AnimatorController.CreateAnimatorControllerAtPath(controllerPath); - } - } else { - controller = (UnityEditor.Animations.AnimatorController)UnityEditor.Animations.AnimatorController.CreateAnimatorControllerAtPath(controllerPath); - } - - } -#else - UnityEditorInternal.AnimatorController controller; - - if (skeletonDataAsset.controller != null) { - controller = (UnityEditorInternal.AnimatorController)skeletonDataAsset.controller; - controllerPath = AssetDatabase.GetAssetPath(controller); - } else { - if (File.Exists(controllerPath)) { - if (EditorUtility.DisplayDialog("Controller Overwrite Warning", "Unknown Controller already exists at: " + controllerPath, "Update", "Overwrite")) { - controller = (UnityEditorInternal.AnimatorController)AssetDatabase.LoadAssetAtPath(controllerPath, typeof(RuntimeAnimatorController)); - } else { - controller = (UnityEditorInternal.AnimatorController)UnityEditorInternal.AnimatorController.CreateAnimatorControllerAtPath(controllerPath); - } - } else { - controller = (UnityEditorInternal.AnimatorController)UnityEditorInternal.AnimatorController.CreateAnimatorControllerAtPath(controllerPath); - } - } -#endif - - skeletonDataAsset.controller = controller; - EditorUtility.SetDirty(skeletonDataAsset); - - Object[] objs = AssetDatabase.LoadAllAssetsAtPath(controllerPath); - - Dictionary clipTable = new Dictionary(); - Dictionary animTable = new Dictionary(); - - foreach (var o in objs) { - if (o is AnimationClip) { - clipTable.Add(o.name, (AnimationClip)o); - } - } - - foreach (var anim in data.Animations) { - string name = anim.Name; - animTable.Add(name, anim); - - if (clipTable.ContainsKey(name) == false) { - //generate new dummy clip - AnimationClip newClip = new AnimationClip(); - newClip.name = name; -#if UNITY_5 -#else - AnimationUtility.SetAnimationType(newClip, ModelImporterAnimationType.Generic); -#endif - - AssetDatabase.AddObjectToAsset(newClip, controller); - clipTable.Add(name, newClip); - } - - AnimationClip clip = clipTable[name]; - - clip.SetCurve("", typeof(GameObject), "dummy", AnimationCurve.Linear(0, 0, anim.Duration, 0)); - var settings = AnimationUtility.GetAnimationClipSettings(clip); - settings.stopTime = anim.Duration; - - SetAnimationSettings(clip, settings); - - AnimationUtility.SetAnimationEvents(clip, new AnimationEvent[0]); - - foreach (Timeline t in anim.Timelines) { - if (t is EventTimeline) { - ParseEventTimeline((EventTimeline)t, clip, SendMessageOptions.DontRequireReceiver); - } - } - - EditorUtility.SetDirty(clip); - - clipTable.Remove(name); - } - - //clear no longer used animations - foreach (var clip in clipTable.Values) { - AnimationClip.DestroyImmediate(clip, true); - } - - AssetDatabase.Refresh(); - AssetDatabase.SaveAssets(); - } - static Bone extractionBone; static Slot extractionSlot; @@ -747,17 +767,6 @@ public static class SkeletonBaker { return arr; } - static void SetAnimationSettings (AnimationClip clip, AnimationClipSettings settings) { -#if UNITY_5 - AnimationUtility.SetAnimationClipSettings(clip, settings); -#else - MethodInfo methodInfo = typeof(AnimationUtility).GetMethod("SetAnimationClipSettings", BindingFlags.Static | BindingFlags.NonPublic); - methodInfo.Invoke(null, new object[] { clip, settings }); - - EditorUtility.SetDirty(clip); -#endif - } - static AnimationClip ExtractAnimation (string name, SkeletonData skeletonData, Dictionary> slotLookup, bool bakeIK, SendMessageOptions eventOptions, AnimationClip clip = null) { var animation = skeletonData.FindAnimation(name); @@ -864,7 +873,7 @@ public static class SkeletonBaker { ae.functionName = ev.Data.Name; ae.messageOptions = eventOptions; - if (ev.String != "" && ev.String != null) { + if (!string.IsNullOrEmpty(ev.String)) { ae.stringParameter = ev.String; } else { if (ev.Int == 0 && ev.Float == 0) { @@ -1447,7 +1456,6 @@ public static class SkeletonBaker { AnimationUtility.SetEditorCurve(clip, yBind, new AnimationCurve()); EditorCurveBinding zBind = EditorCurveBinding.FloatCurve(path, typeof(Transform), propertyName + ".z"); AnimationUtility.SetEditorCurve(clip, zBind, curve); - } static string GetPath (BoneData b) { @@ -1461,4 +1469,18 @@ public static class SkeletonBaker { return GetPathRecurse(b.Parent) + "/" + b.Name; } + #endregion + + static void SetAnimationSettings (AnimationClip clip, AnimationClipSettings settings) { +#if UNITY_5 + AnimationUtility.SetAnimationClipSettings(clip, settings); +#else + MethodInfo methodInfo = typeof(AnimationUtility).GetMethod("SetAnimationClipSettings", BindingFlags.Static | BindingFlags.NonPublic); + methodInfo.Invoke(null, new object[] { clip, settings }); + + EditorUtility.SetDirty(clip); +#endif + } + + } From 5570e2b5d0413a8509a1de046b3dff4754316ed9 Mon Sep 17 00:00:00 2001 From: John Date: Sat, 12 Mar 2016 14:50:39 +0800 Subject: [PATCH 6/9] Fixed backwards slider-validated values. --- .../Assets/spine-unity/Editor/SkeletonRendererInspector.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spine-unity/Assets/spine-unity/Editor/SkeletonRendererInspector.cs b/spine-unity/Assets/spine-unity/Editor/SkeletonRendererInspector.cs index f2e46c9bd..26776b9ba 100644 --- a/spine-unity/Assets/spine-unity/Editor/SkeletonRendererInspector.cs +++ b/spine-unity/Assets/spine-unity/Editor/SkeletonRendererInspector.cs @@ -139,8 +139,8 @@ public class SkeletonRendererInspector : Editor { new GUIContent("Immutable Triangles", "Enable to optimize rendering for skeletons that never change attachment visbility")); EditorGUILayout.Space(); - const float MinZSpacing = 0f; - const float MaxZSpacing = 0.1f; + const float MinZSpacing = -0.1f; + const float MaxZSpacing = 0f; EditorGUILayout.Slider(zSpacing, MinZSpacing, MaxZSpacing); EditorGUILayout.PropertyField(normals); From 476ce5165d6ed0ff98e6ad4453a4d8ce1b66e38f Mon Sep 17 00:00:00 2001 From: John Date: Tue, 15 Mar 2016 01:47:44 +0800 Subject: [PATCH 7/9] SkeletonDataAssetInspector null checks & helpbox. --- .../Editor/SkeletonDataAssetInspector.cs | 29 ++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/spine-unity/Assets/spine-unity/Asset Types/Editor/SkeletonDataAssetInspector.cs b/spine-unity/Assets/spine-unity/Asset Types/Editor/SkeletonDataAssetInspector.cs index 440f3d7f8..5784b6fc3 100644 --- a/spine-unity/Assets/spine-unity/Asset Types/Editor/SkeletonDataAssetInspector.cs +++ b/spine-unity/Assets/spine-unity/Asset Types/Editor/SkeletonDataAssetInspector.cs @@ -147,9 +147,14 @@ public class SkeletonDataAssetInspector : Editor { GUILayout.Space(32); if (GUILayout.Button(new GUIContent("Generate Mecanim Controller"), GUILayout.Width(195), GUILayout.Height(20))) SkeletonBaker.GenerateMecanimAnimationClips(m_skeletonDataAsset); - //GUILayout.Label(new GUIContent("Alternative to SkeletonAnimation, not a requirement.", SpineEditorUtilities.Icons.warning)); GUILayout.EndHorizontal(); EditorGUILayout.LabelField("SkeletonAnimator is the Mecanim alternative to SkeletonAnimation. It is not required.", EditorStyles.miniLabel); + } else { + GUILayout.BeginHorizontal(); + GUILayout.Space(32); + if (GUILayout.Button(new GUIContent("Update Controller Animations"), GUILayout.Width(195), GUILayout.Height(20))) + SkeletonBaker.GenerateMecanimAnimationClips(m_skeletonDataAsset); + GUILayout.EndHorizontal(); } EditorGUI.indentLevel--; } @@ -228,6 +233,7 @@ public class SkeletonDataAssetInspector : Editor { } + void DrawReimportButton () { EditorGUI.BeginDisabledGroup(skeletonJSON.objectReferenceValue == null); if (GUILayout.Button(new GUIContent("Attempt Reimport", SpineEditorUtilities.Icons.warning))) { @@ -302,10 +308,14 @@ public class SkeletonDataAssetInspector : Editor { if (!showAnimationList) return; - if (GUILayout.Button(new GUIContent("Setup Pose", SpineEditorUtilities.Icons.skeleton), GUILayout.Width(105), GUILayout.Height(18))) { - StopAnimation(); - m_skeletonAnimation.skeleton.SetToSetupPose(); - m_requireRefresh = true; + if (m_skeletonAnimation != null && m_skeletonAnimation.state != null) { + if (GUILayout.Button(new GUIContent("Setup Pose", SpineEditorUtilities.Icons.skeleton), GUILayout.Width(105), GUILayout.Height(18))) { + StopAnimation(); + m_skeletonAnimation.skeleton.SetToSetupPose(); + m_requireRefresh = true; + } + } else { + EditorGUILayout.HelpBox("Animations can be previewed if you expand the Preview window below.", MessageType.Info); } EditorGUILayout.LabelField("Name", "Duration"); @@ -498,6 +508,10 @@ public class SkeletonDataAssetInspector : Editor { private Color m_originColor = new Color(0.3f, 0.3f, 0.3f, 1); private void StopAnimation () { + if (m_skeletonAnimation == null) { + Debug.LogWarning("Animation was stopped but preview doesn't exist. It's possible that the Preview Panel is closed."); + } + m_skeletonAnimation.state.ClearTrack(0); m_playing = false; } @@ -562,7 +576,7 @@ public class SkeletonDataAssetInspector : Editor { m_initialized = true; AdjustCameraGoals(true); } catch { - + // WARNING: Suppresses errors. } } } @@ -861,6 +875,7 @@ public class SkeletonDataAssetInspector : Editor { if (position.Contains(current.mousePosition)) { m_orthoGoal += current.delta.y; + m_orthoGoal = Mathf.Max(0.01f, m_orthoGoal); GUIUtility.hotControl = controlID; current.Use(); } @@ -959,4 +974,4 @@ public class SkeletonDataAssetInspector : Editor { tex = this.m_previewUtility.EndStaticPreview(); return tex; } -} \ No newline at end of file +} From a73467109054956766afa7ccb9b8b5395ffff269 Mon Sep 17 00:00:00 2001 From: pharan Date: Tue, 15 Mar 2016 12:05:34 +0800 Subject: [PATCH 8/9] Removed old raptor sample binary. --- .../Examples/Spine/Raptor/raptor.skel.bytes | Bin 41027 -> 0 bytes .../Spine/Raptor/raptor.skel.bytes.meta | 8 -------- 2 files changed, 8 deletions(-) delete mode 100644 spine-unity/Assets/Examples/Spine/Raptor/raptor.skel.bytes delete mode 100644 spine-unity/Assets/Examples/Spine/Raptor/raptor.skel.bytes.meta diff --git a/spine-unity/Assets/Examples/Spine/Raptor/raptor.skel.bytes b/spine-unity/Assets/Examples/Spine/Raptor/raptor.skel.bytes deleted file mode 100644 index 507d86e2e9ae3c329c49f2bc913cf1666980cc98..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 41027 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 diff --git a/spine-unity/Assets/Examples/Spine/Raptor/raptor.skel.bytes.meta b/spine-unity/Assets/Examples/Spine/Raptor/raptor.skel.bytes.meta deleted file mode 100644 index 7dae281bc..000000000 --- a/spine-unity/Assets/Examples/Spine/Raptor/raptor.skel.bytes.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 5d6edb328bfcef44a9d1bf852e5724bc -timeCreated: 1427642224 -licenseType: Free -TextScriptImporter: - userData: - assetBundleName: - assetBundleVariant: From 143b750dc9dd4c485f7c50fcda704611556a8525 Mon Sep 17 00:00:00 2001 From: John Date: Tue, 15 Mar 2016 16:01:57 +0800 Subject: [PATCH 9/9] Exclude BuildTargetGroup.Unknown --- .../Assets/spine-unity/Editor/SpineEditorUtilities.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs b/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs index 11e9c737a..d99750ab3 100644 --- a/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs +++ b/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs @@ -1135,10 +1135,13 @@ public class SpineEditorUtilities : AssetPostprocessor { static void EnableTK2D () { bool added = false; foreach (BuildTargetGroup group in System.Enum.GetValues(typeof(BuildTargetGroup))) { + if (group == BuildTargetGroup.Unknown) + continue; + string defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(group); if (!defines.Contains(SPINE_TK2D_DEFINE)) { added = true; - if (defines.EndsWith(";")) + if (defines.EndsWith(";", System.StringComparison.Ordinal)) defines = defines + SPINE_TK2D_DEFINE; else defines = defines + ";" + SPINE_TK2D_DEFINE;