From bb73f7d6e48803f5a58fff6d065c6a3c76d6b80e Mon Sep 17 00:00:00 2001 From: pharan Date: Sat, 6 Oct 2018 02:37:09 +0800 Subject: [PATCH 1/9] [unity] Some code and editor cleanup. --- .../AssetDatabaseAvailabilityDetector.cs | 12 +-- .../spine-unity/Editor/SkeletonDebugWindow.cs | 10 +-- .../Editor/SpineAtlasAssetInspector.cs | 12 ++- .../Editor/SpineEditorUtilities.cs | 82 ++++++++++--------- .../Asset Types/SkeletonDataAsset.cs | 38 ++++----- .../Asset Types/SpineAtlasAsset.cs | 2 - 6 files changed, 83 insertions(+), 73 deletions(-) diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/AssetDatabaseAvailabilityDetector.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/AssetDatabaseAvailabilityDetector.cs index ec76a4a78..398f0c176 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/AssetDatabaseAvailabilityDetector.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/AssetDatabaseAvailabilityDetector.cs @@ -32,20 +32,20 @@ using UnityEngine; namespace Spine.Unity.Editor { public static class AssetDatabaseAvailabilityDetector { - const string MARKER_RESOURCE_NAME = "SpineAssetDatabaseMarker"; - private static bool _isMarkerLoaded; + const string MarkerResourceName = "SpineAssetDatabaseMarker"; + private static bool isMarkerLoaded; public static bool IsAssetDatabaseAvailable (bool forceCheck = false) { - if (!forceCheck && _isMarkerLoaded) + if (!forceCheck && isMarkerLoaded) return true; - TextAsset markerTextAsset = Resources.Load(MARKER_RESOURCE_NAME); - _isMarkerLoaded = markerTextAsset != null; + TextAsset markerTextAsset = Resources.Load(AssetDatabaseAvailabilityDetector.MarkerResourceName); + isMarkerLoaded = markerTextAsset != null; if (markerTextAsset != null) { Resources.UnloadAsset(markerTextAsset); } - return _isMarkerLoaded; + return isMarkerLoaded; } } } diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SkeletonDebugWindow.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SkeletonDebugWindow.cs index abab90f5e..604619bdc 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SkeletonDebugWindow.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SkeletonDebugWindow.cs @@ -228,11 +228,11 @@ namespace Spine.Unity.Editor { EditorGUI.EndDisabledGroup(); // Flip - EditorGUILayout.BeginHorizontal(GUILayout.MaxWidth(160f)); - EditorGUILayout.LabelField("Scale", GUILayout.MaxWidth(EditorGUIUtility.labelWidth - 20f)); - skeleton.ScaleX = EditorGUILayout.DelayedFloatField(".ScaleX", skeleton.ScaleX, GUILayout.MaxWidth(70f)); - skeleton.ScaleY = EditorGUILayout.DelayedFloatField(".ScaleY", skeleton.ScaleY, GUILayout.MaxWidth(70f)); - GUILayout.EndHorizontal(); + skeleton.ScaleX = EditorGUILayout.DelayedFloatField(".ScaleX", skeleton.ScaleX); + skeleton.ScaleY = EditorGUILayout.DelayedFloatField(".ScaleY", skeleton.ScaleY); + //EditorGUILayout.BeginHorizontal(GUILayout.MaxWidth(160f)); + ////EditorGUILayout.LabelField("Scale", GUILayout.Width(EditorGUIUtility.labelWidth - 20f)); + //GUILayout.EndHorizontal(); // Color skeleton.SetColor(EditorGUILayout.ColorField(".R .G .B .A", skeleton.GetColor())); diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineAtlasAssetInspector.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineAtlasAssetInspector.cs index 758bfe748..f068cb2a3 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineAtlasAssetInspector.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineAtlasAssetInspector.cs @@ -134,7 +134,7 @@ namespace Spine.Unity.Editor { } EditorGUILayout.Space(); - if (SpineInspectorUtility.LargeCenteredButton(SpineInspectorUtility.TempContent("Set Mipmap Bias to " + SpineEditorUtilities.Preferences.DEFAULT_MIPMAPBIAS))) { + if (SpineInspectorUtility.LargeCenteredButton(SpineInspectorUtility.TempContent("Set Mipmap Bias to " + SpineEditorUtilities.Preferences.DEFAULT_MIPMAPBIAS, tooltip: "This may help textures with mipmaps be less blurry when used for 2D sprites."))) { foreach (var m in atlasAsset.materials) { var texture = m.mainTexture; texture.mipMapBias = SpineEditorUtilities.Preferences.DEFAULT_MIPMAPBIAS; @@ -261,12 +261,18 @@ namespace Spine.Unity.Editor { } #else if (atlasFile.objectReferenceValue != null) { - EditorGUILayout.LabelField("Atlas Regions", EditorStyles.boldLabel); + + int baseIndent = EditorGUI.indentLevel; var regions = SpineAtlasAssetInspector.GetRegions(atlasAsset.GetAtlas()); + int regionsCount = regions.Count; + using (new EditorGUILayout.HorizontalScope()) { + EditorGUILayout.LabelField("Atlas Regions", EditorStyles.boldLabel); + EditorGUILayout.LabelField(string.Format("{0} regions total", regionsCount)); + } AtlasPage lastPage = null; - for (int i = 0; i < regions.Count; i++) { + for (int i = 0; i < regionsCount; i++) { if (lastPage != regions[i].page) { if (lastPage != null) { EditorGUILayout.Separator(); diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineEditorUtilities.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineEditorUtilities.cs index 1b4e5d701..5043aa1fd 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineEditorUtilities.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineEditorUtilities.cs @@ -1165,15 +1165,13 @@ namespace Spine.Unity.Editor { internal static readonly List additionalSpawnTypes = new List(); - public static void IngestAdvancedRenderSettings (SkeletonRenderer skeletonRenderer) { + public static void TryInitializeSkeletonRendererSettings (SkeletonRenderer skeletonRenderer, Skin skin = null) { const string PMAShaderQuery = "Spine/Skeleton"; const string TintBlackShaderQuery = "Tint Black"; - if (skeletonRenderer == null) - return; + if (skeletonRenderer == null) return; var skeletonDataAsset = skeletonRenderer.skeletonDataAsset; - if (skeletonDataAsset == null) - return; + if (skeletonDataAsset == null) return; bool pmaVertexColors = false; bool tintBlack = false; @@ -1199,6 +1197,14 @@ namespace Spine.Unity.Editor { skeletonRenderer.pmaVertexColors = pmaVertexColors; skeletonRenderer.tintBlack = tintBlack; + skeletonRenderer.zSpacing = SpineEditorUtilities.Preferences.defaultZSpacing; + + var data = skeletonDataAsset.GetSkeletonData(false); + bool noSkins = data.DefaultSkin == null && (data.Skins == null || data.Skins.Count == 0); // Support attachmentless/skinless SkeletonData. + skin = skin ?? data.DefaultSkin ?? (noSkins ? null : data.Skins.Items[0]); + if (skin != null) { + skeletonRenderer.initialSkinName = skin.Name; + } } public static SkeletonAnimation InstantiateSkeletonAnimation (SkeletonDataAsset skeletonDataAsset, string skinName, bool destroyInvalid = true) { @@ -1227,8 +1233,9 @@ namespace Spine.Unity.Editor { GameObject go = new GameObject(spineGameObjectName, typeof(MeshFilter), typeof(MeshRenderer), typeof(SkeletonAnimation)); SkeletonAnimation newSkeletonAnimation = go.GetComponent(); newSkeletonAnimation.skeletonDataAsset = skeletonDataAsset; - IngestAdvancedRenderSettings(newSkeletonAnimation); + TryInitializeSkeletonRendererSettings(newSkeletonAnimation, skin); + // Initialize try { newSkeletonAnimation.Initialize(false); } catch (System.Exception e) { @@ -1239,16 +1246,6 @@ namespace Spine.Unity.Editor { throw e; } - // Set Defaults - bool noSkins = data.DefaultSkin == null && (data.Skins == null || data.Skins.Count == 0); // Support attachmentless/skinless SkeletonData. - skin = skin ?? data.DefaultSkin ?? (noSkins ? null : data.Skins.Items[0]); - if (skin != null) { - newSkeletonAnimation.initialSkinName = skin.Name; - newSkeletonAnimation.skeleton.SetSkin(skin); - } - - newSkeletonAnimation.zSpacing = SpineEditorUtilities.Preferences.defaultZSpacing; - newSkeletonAnimation.skeleton.Update(0); newSkeletonAnimation.state.Update(0); newSkeletonAnimation.state.Apply(newSkeletonAnimation.skeleton); @@ -1274,7 +1271,22 @@ namespace Spine.Unity.Editor { return InstantiateSkeletonMecanim(skeletonDataAsset, skeletonDataAsset.GetSkeletonData(true).FindSkin(skinName)); } - public static SkeletonMecanim InstantiateSkeletonMecanim (SkeletonDataAsset skeletonDataAsset, Skin skin = null) { + public static SkeletonMecanim InstantiateSkeletonMecanim (SkeletonDataAsset skeletonDataAsset, Skin skin = null, bool destroyInvalid = true) { + SkeletonData data = skeletonDataAsset.GetSkeletonData(true); + + if (data == null) { + for (int i = 0; i < skeletonDataAsset.atlasAssets.Length; i++) { + string reloadAtlasPath = AssetDatabase.GetAssetPath(skeletonDataAsset.atlasAssets[i]); + skeletonDataAsset.atlasAssets[i] = (AtlasAssetBase)AssetDatabase.LoadAssetAtPath(reloadAtlasPath, typeof(AtlasAssetBase)); + } + data = skeletonDataAsset.GetSkeletonData(false); + } + + if (data == null) { + Debug.LogWarning("InstantiateSkeletonMecanim tried to instantiate a skeleton from an invalid SkeletonDataAsset."); + return null; + } + string spineGameObjectName = string.Format("Spine Mecanim GameObject ({0})", skeletonDataAsset.name.Replace("_SkeletonData", "")); GameObject go = new GameObject(spineGameObjectName, typeof(MeshFilter), typeof(MeshRenderer), typeof(Animator), typeof(SkeletonMecanim)); @@ -1285,32 +1297,26 @@ namespace Spine.Unity.Editor { go.GetComponent().runtimeAnimatorController = skeletonDataAsset.controller; - SkeletonMecanim anim = go.GetComponent(); - anim.skeletonDataAsset = skeletonDataAsset; - IngestAdvancedRenderSettings(anim); + SkeletonMecanim newSkeletonMecanim = go.GetComponent(); + newSkeletonMecanim.skeletonDataAsset = skeletonDataAsset; + TryInitializeSkeletonRendererSettings(newSkeletonMecanim, skin); - SkeletonData data = skeletonDataAsset.GetSkeletonData(true); - if (data == null) { - for (int i = 0; i < skeletonDataAsset.atlasAssets.Length; i++) { - string reloadAtlasPath = AssetDatabase.GetAssetPath(skeletonDataAsset.atlasAssets[i]); - skeletonDataAsset.atlasAssets[i] = (AtlasAssetBase)AssetDatabase.LoadAssetAtPath(reloadAtlasPath, typeof(AtlasAssetBase)); + // Initialize + try { + newSkeletonMecanim.Initialize(false); + } catch (System.Exception e) { + if (destroyInvalid) { + Debug.LogWarning("Editor-instantiated SkeletonAnimation threw an Exception. Destroying GameObject to prevent orphaned GameObject."); + GameObject.DestroyImmediate(go); } - data = skeletonDataAsset.GetSkeletonData(true); + throw e; } - // Set defaults - skin = skin ?? data.DefaultSkin ?? data.Skins.Items[0]; - anim.zSpacing = SpineEditorUtilities.Preferences.defaultZSpacing; + newSkeletonMecanim.skeleton.Update(0); + newSkeletonMecanim.skeleton.UpdateWorldTransform(); + newSkeletonMecanim.LateUpdate(); - anim.Initialize(false); - anim.skeleton.SetSkin(skin); - anim.initialSkinName = skin.Name; - - anim.skeleton.Update(0); - anim.skeleton.UpdateWorldTransform(); - anim.LateUpdate(); - - return anim; + return newSkeletonMecanim; } #endif #endregion diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/SkeletonDataAsset.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/SkeletonDataAsset.cs index 544a7a782..fe2f90b12 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/SkeletonDataAsset.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/SkeletonDataAsset.cs @@ -100,6 +100,13 @@ namespace Spine.Unity { stateData = null; } + public AnimationStateData GetAnimationStateData () { + if (stateData != null) + return stateData; + GetSkeletonData(false); + return stateData; + } + /// Loads, caches and returns the SkeletonData from the skeleton data file. Returns the cached SkeletonData after the first time it is called. Pass false to prevent direct errors from being logged. public SkeletonData GetSkeletonData (bool quiet) { if (skeletonJSON == null) { @@ -187,6 +194,18 @@ namespace Spine.Unity { FillStateData(); } + public void FillStateData () { + if (stateData != null) { + stateData.defaultMix = defaultMix; + + for (int i = 0, n = fromAnimation.Length; i < n; i++) { + if (fromAnimation[i].Length == 0 || toAnimation[i].Length == 0) + continue; + stateData.SetMix(fromAnimation[i], toAnimation[i], duration[i]); + } + } + } + internal Atlas[] GetAtlasArray () { var returnList = new System.Collections.Generic.List(atlasAssets.Length); for (int i = 0; i < atlasAssets.Length; i++) { @@ -215,25 +234,6 @@ namespace Spine.Unity { return json.ReadSkeletonData(input); } - public void FillStateData () { - if (stateData != null) { - stateData.defaultMix = defaultMix; - - for (int i = 0, n = fromAnimation.Length; i < n; i++) { - if (fromAnimation[i].Length == 0 || toAnimation[i].Length == 0) - continue; - stateData.SetMix(fromAnimation[i], toAnimation[i], duration[i]); - } - } - } - - public AnimationStateData GetAnimationStateData () { - if (stateData != null) - return stateData; - GetSkeletonData(false); - return stateData; - } - } } diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/SpineAtlasAsset.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/SpineAtlasAsset.cs index a7d88979a..fd3ff9e64 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/SpineAtlasAsset.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/SpineAtlasAsset.cs @@ -115,8 +115,6 @@ namespace Spine.Unity { } #endregion - - void Reset () { Clear(); } From 6e7370f603c87a97a0ba05c43e77d51316ff386a Mon Sep 17 00:00:00 2001 From: pharan Date: Sat, 6 Oct 2018 02:37:38 +0800 Subject: [PATCH 2/9] [unity] Use scale instead of flip for SkeletonFlip timeline mixer. --- .../SpineSkeletonFlipMixerBehaviour.cs | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Timeline/SpineSkeletonFlip/SpineSkeletonFlipMixerBehaviour.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Timeline/SpineSkeletonFlip/SpineSkeletonFlipMixerBehaviour.cs index 1ce745d12..ffc29ae29 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Timeline/SpineSkeletonFlip/SpineSkeletonFlipMixerBehaviour.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Timeline/SpineSkeletonFlip/SpineSkeletonFlipMixerBehaviour.cs @@ -38,7 +38,8 @@ using Spine.Unity; namespace Spine.Unity.Playables { public class SpineSkeletonFlipMixerBehaviour : PlayableBehaviour { - bool defaultFlipX, defaultFlipY; + float originalScaleX, originalScaleY; + float baseScaleX, baseScaleY; SpinePlayableHandleBase playableHandle; bool m_FirstFrameHappened; @@ -52,8 +53,10 @@ namespace Spine.Unity.Playables { var skeleton = playableHandle.Skeleton; if (!m_FirstFrameHappened) { - defaultFlipX = skeleton.FlipX; - defaultFlipY = skeleton.FlipY; + originalScaleX = skeleton.ScaleX; + originalScaleY = skeleton.ScaleY; + baseScaleX = Mathf.Abs(originalScaleX); + baseScaleY = Mathf.Abs(originalScaleY); m_FirstFrameHappened = true; } @@ -71,8 +74,7 @@ namespace Spine.Unity.Playables { totalWeight += inputWeight; if (inputWeight > greatestWeight) { - skeleton.FlipX = input.flipX; - skeleton.FlipY = input.flipY; + SetSkeletonScaleFromFlip(skeleton, input.flipX, input.flipY); greatestWeight = inputWeight; } @@ -81,11 +83,16 @@ namespace Spine.Unity.Playables { } if (currentInputs != 1 && 1f - totalWeight > greatestWeight) { - skeleton.FlipX = defaultFlipX; - skeleton.FlipY = defaultFlipY; + skeleton.scaleX = originalScaleX; + skeleton.scaleY = originalScaleY; } } + public void SetSkeletonScaleFromFlip (Skeleton skeleton, bool flipX, bool flipY) { + skeleton.scaleX = flipX ? -baseScaleX : baseScaleX; + skeleton.scaleY = flipY ? -baseScaleY : baseScaleY; + } + public override void OnGraphStop (Playable playable) { m_FirstFrameHappened = false; @@ -93,8 +100,8 @@ namespace Spine.Unity.Playables { return; var skeleton = playableHandle.Skeleton; - skeleton.FlipX = defaultFlipX; - skeleton.FlipY = defaultFlipY; + skeleton.scaleX = originalScaleX; + skeleton.scaleY = originalScaleY; } } From 2dcff2e50f6f957962c934fdb96534a9546f6c33 Mon Sep 17 00:00:00 2001 From: pharan Date: Sat, 6 Oct 2018 02:38:14 +0800 Subject: [PATCH 3/9] [unity] Timeline count tooltip for animation list. --- .../Editor/spine-unity/Editor/SkeletonDataAssetInspector.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SkeletonDataAssetInspector.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SkeletonDataAssetInspector.cs index c2e09f31e..96570c75a 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SkeletonDataAssetInspector.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SkeletonDataAssetInspector.cs @@ -451,7 +451,8 @@ namespace Spine.Unity.Editor { } //string frameCountString = (fps > 0) ? ("(" + (Mathf.RoundToInt(animation.Duration * fps)) + ")").PadLeft(12, ' ') : string.Empty; //EditorGUILayout.LabelField(new GUIContent(animation.Name, Icons.animation), SpineInspectorUtility.TempContent(animation.Duration.ToString("f3") + "s" + frameCountString)); - EditorGUILayout.LabelField(new GUIContent(animation.Name, Icons.animation), SpineInspectorUtility.TempContent(animation.Duration.ToString("f3") + "s")); + string durationString = animation.Duration.ToString("f3"); + EditorGUILayout.LabelField(new GUIContent(animation.Name, Icons.animation), SpineInspectorUtility.TempContent(durationString + "s", tooltip: string.Format("{0} seconds\n{1} timelines", durationString, animation.Timelines.Count))); } } } From 6fee0e3622738c2781c3a4b3debfbf2ab4f9e9d3 Mon Sep 17 00:00:00 2001 From: pharan Date: Sat, 6 Oct 2018 02:39:29 +0800 Subject: [PATCH 4/9] [unity] Use dummy AnimationState for AnimationState timeline mixer preview. --- .../SpineAnimationStateMixerBehaviour.cs | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Timeline/SpineAnimationState/SpineAnimationStateMixerBehaviour.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Timeline/SpineAnimationState/SpineAnimationStateMixerBehaviour.cs index a4994157c..6c94d2eb8 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Timeline/SpineAnimationState/SpineAnimationStateMixerBehaviour.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Timeline/SpineAnimationState/SpineAnimationStateMixerBehaviour.cs @@ -105,6 +105,9 @@ namespace Spine.Unity.Playables { } #if SPINE_EDITMODEPOSE + + AnimationState dummyAnimationState; + public void PreviewEditModePose (Playable playable, SkeletonAnimation spineComponent) { if (Application.isPlaying) return; if (spineComponent == null) return; @@ -150,11 +153,28 @@ namespace Spine.Unity.Playables { // Approximate what AnimationState might do at runtime. if (fromAnimation != null && mixDuration > 0 && toClipTime < mixDuration) { + dummyAnimationState = dummyAnimationState ?? new AnimationState(spineComponent.skeletonDataAsset.GetAnimationStateData()); + + var toTrack = dummyAnimationState.GetCurrent(0); + var fromTrack = toTrack != null ? toTrack.mixingFrom : null; + bool isAnimationTransitionMatch = (toTrack != null && toTrack.animation == toAnimation && fromTrack != null && fromTrack.animation == fromAnimation); + + if (!isAnimationTransitionMatch) { + dummyAnimationState.ClearTracks(); + fromTrack = dummyAnimationState.SetAnimation(0, fromAnimation, fromClipLoop); + fromTrack.AllowImmediateQueue(); + toTrack = dummyAnimationState.SetAnimation(0, toAnimation, clipData.loop); + } + + // Update track times. + fromTrack.trackTime = fromClipTime; + toTrack.trackTime = toClipTime; + toTrack.mixTime = toClipTime; + + // Apply Pose skeleton.SetToSetupPose(); - float fauxFromAlpha = (1f - toClipTime/mixDuration); - fauxFromAlpha = fauxFromAlpha > 0.5f ? 1f : fauxFromAlpha * 2f; // fake value, but reduce dip. - fromAnimation.Apply(skeleton, 0, fromClipTime, fromClipLoop, null, fauxFromAlpha, MixBlend.Setup, MixDirection.Out); //fromAnimation.PoseSkeleton(skeleton, fromClipTime, fromClipLoop); - toAnimation.Apply(skeleton, 0, toClipTime, clipData.loop, null, toClipTime/mixDuration, MixBlend.Replace, MixDirection.In); + dummyAnimationState.Update(0); + dummyAnimationState.Apply(skeleton); } else { skeleton.SetToSetupPose(); toAnimation.PoseSkeleton(skeleton, toClipTime, clipData.loop); From 8112f9c55d61b0bd5d476934ecbb4ee2ae2f8ba3 Mon Sep 17 00:00:00 2001 From: pharan Date: Mon, 8 Oct 2018 04:50:53 +0800 Subject: [PATCH 5/9] [unity] Material cache for BlendModeMaterials --- .../Asset Types/BlendModeMaterialsAsset.cs | 108 ++++++++++-------- 1 file changed, 59 insertions(+), 49 deletions(-) diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/BlendModeMaterialsAsset.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/BlendModeMaterialsAsset.cs index 10a09a8e6..4d93d17cb 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/BlendModeMaterialsAsset.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/BlendModeMaterialsAsset.cs @@ -52,67 +52,77 @@ namespace Spine.Unity { public static void ApplyMaterials (SkeletonData skeletonData, Material multiplyTemplate, Material screenTemplate, Material additiveTemplate, bool includeAdditiveSlots) { if (skeletonData == null) throw new ArgumentNullException("skeletonData"); - var atlasPageMaterialCache = new Dictionary, AtlasPage>(); - var attachmentBuffer = new List(); - var slotsItems = skeletonData.Slots.Items; - for (int i = 0, slotCount = skeletonData.Slots.Count; i < slotCount; i++) { - var slot = slotsItems[i]; - if (slot.blendMode == BlendMode.Normal) continue; - if (!includeAdditiveSlots && slot.blendMode == BlendMode.Additive) continue; + using (var materialCache = new AtlasMaterialCache()) { + var attachmentBuffer = new List(); + var slotsItems = skeletonData.Slots.Items; + for (int i = 0, slotCount = skeletonData.Slots.Count; i < slotCount; i++) { + var slot = slotsItems[i]; + if (slot.blendMode == BlendMode.Normal) continue; + if (!includeAdditiveSlots && slot.blendMode == BlendMode.Additive) continue; - attachmentBuffer.Clear(); - foreach (var skin in skeletonData.Skins) - skin.FindAttachmentsForSlot(i, attachmentBuffer); + attachmentBuffer.Clear(); + foreach (var skin in skeletonData.Skins) + skin.FindAttachmentsForSlot(i, attachmentBuffer); - Material templateMaterial = null; - switch (slot.blendMode) { - case BlendMode.Multiply: - templateMaterial = multiplyTemplate; - break; - case BlendMode.Screen: - templateMaterial = screenTemplate; - break; - case BlendMode.Additive: - templateMaterial = additiveTemplate; - break; - } - if (templateMaterial == null) continue; + Material templateMaterial = null; + switch (slot.blendMode) { + case BlendMode.Multiply: + templateMaterial = multiplyTemplate; + break; + case BlendMode.Screen: + templateMaterial = screenTemplate; + break; + case BlendMode.Additive: + templateMaterial = additiveTemplate; + break; + } + if (templateMaterial == null) continue; - foreach (var attachment in attachmentBuffer) { - var renderableAttachment = attachment as IHasRendererObject; - if (renderableAttachment != null) { - renderableAttachment.RendererObject = AtlasRegionCloneWithMaterial((AtlasRegion)renderableAttachment.RendererObject, templateMaterial, atlasPageMaterialCache); + foreach (var attachment in attachmentBuffer) { + var renderableAttachment = attachment as IHasRendererObject; + if (renderableAttachment != null) { + renderableAttachment.RendererObject = materialCache.CloneAtlasRegionWithMaterial((AtlasRegion)renderableAttachment.RendererObject, templateMaterial); + } } } + } - //atlasPageMaterialCache.Clear(); //attachmentBuffer.Clear(); } - static AtlasRegion AtlasRegionCloneWithMaterial (AtlasRegion originalRegion, Material materialTemplate, Dictionary, AtlasPage> cache) { - var newRegion = originalRegion.Clone(); - newRegion.page = GetAtlasPageWithMaterial(originalRegion.page, materialTemplate, cache); - return newRegion; - } + class AtlasMaterialCache : IDisposable { + readonly Dictionary, AtlasPage> cache = new Dictionary, AtlasPage>(); - static AtlasPage GetAtlasPageWithMaterial (AtlasPage originalPage, Material materialTemplate, Dictionary, AtlasPage> cache) { - if (originalPage == null) throw new ArgumentNullException("originalPage"); - - AtlasPage newPage = null; - var key = new KeyValuePair(originalPage, materialTemplate); - cache.TryGetValue(key, out newPage); - - if (newPage == null) { - newPage = originalPage.Clone(); - var originalMaterial = originalPage.rendererObject as Material; - newPage.rendererObject = new Material(materialTemplate) { - name = originalMaterial.name + " " + materialTemplate.name, - mainTexture = originalMaterial.mainTexture - }; - cache.Add(key, newPage); + /// Creates a clone of an AtlasRegion that uses different Material settings, while retaining the original texture. + public AtlasRegion CloneAtlasRegionWithMaterial (AtlasRegion originalRegion, Material materialTemplate) { + var newRegion = originalRegion.Clone(); + newRegion.page = GetAtlasPageWithMaterial(originalRegion.page, materialTemplate); + return newRegion; } - return newPage; + AtlasPage GetAtlasPageWithMaterial (AtlasPage originalPage, Material materialTemplate) { + if (originalPage == null) throw new ArgumentNullException("originalPage"); + + AtlasPage newPage = null; + var key = new KeyValuePair(originalPage, materialTemplate); + cache.TryGetValue(key, out newPage); + + if (newPage == null) { + newPage = originalPage.Clone(); + var originalMaterial = originalPage.rendererObject as Material; + newPage.rendererObject = new Material(materialTemplate) { + name = originalMaterial.name + " " + materialTemplate.name, + mainTexture = originalMaterial.mainTexture + }; + cache.Add(key, newPage); + } + + return newPage; + } + + public void Dispose () { + cache.Clear(); + } } } From 230ae89d6643245f888bde2cfaf665e1b64ef3cc Mon Sep 17 00:00:00 2001 From: pharan Date: Mon, 8 Oct 2018 04:54:37 +0800 Subject: [PATCH 6/9] [unity] Improved multiedit for attributes. Updated inspectors. --- .../Editor/BoneFollowerInspector.cs | 16 +- .../Editor/SkeletonAnimationInspector.cs | 32 +-- .../Editor/SkeletonRendererInspector.cs | 260 ++++++++++-------- .../Editor/SpineAttributeDrawers.cs | 122 ++++---- .../Editor/SpineEditorUtilities.cs | 2 +- .../Editor/SpineInspectorUtility.cs | 5 +- .../Components/SkeletonRenderer.cs | 1 + .../Runtime/spine-unity/SpineAttributes.cs | 8 +- 8 files changed, 260 insertions(+), 186 deletions(-) diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/BoneFollowerInspector.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/BoneFollowerInspector.cs index f1cb32fd0..dd44a34c5 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/BoneFollowerInspector.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/BoneFollowerInspector.cs @@ -46,7 +46,7 @@ namespace Spine.Unity.Editor { [MenuItem ("CONTEXT/SkeletonRenderer/Add BoneFollower GameObject")] static void AddBoneFollowerGameObject (MenuCommand cmd) { var skeletonRenderer = cmd.context as SkeletonRenderer; - var go = new GameObject("BoneFollower"); + var go = new GameObject("New BoneFollower"); var t = go.transform; t.SetParent(skeletonRenderer.transform); t.localPosition = Vector3.zero; @@ -65,8 +65,20 @@ namespace Spine.Unity.Editor { var skeletonRenderer = cmd.context as SkeletonRenderer; return skeletonRenderer.valid; } + + [MenuItem("CONTEXT/BoneFollower/Rename BoneFollower GameObject")] + static void RenameGameObject (MenuCommand cmd) { + AutonameGameObject(cmd.context as BoneFollower); + } #endregion + static void AutonameGameObject (BoneFollower boneFollower) { + if (boneFollower == null) return; + + string boneName = boneFollower.boneName; + boneFollower.gameObject.name = string.IsNullOrEmpty(boneName) ? "BoneFollower" : string.Format("{0} (BoneFollower)", boneName); + } + void OnEnable () { skeletonRenderer = serializedObject.FindProperty("skeletonRenderer"); boneName = serializedObject.FindProperty("boneName"); @@ -195,7 +207,7 @@ namespace Spine.Unity.Editor { bool missingRigidBody = (hasCollider2D && component.GetComponent() == null) || (hasCollider3D && component.GetComponent() == null); if (missingRigidBody) { using (new SpineInspectorUtility.BoxScope()) { - EditorGUILayout.HelpBox("Collider detected. Unity recommends adding a Rigidbody to the parent Transforms of any colliders that are intended to be dynamically repositioned and rotated.", MessageType.Warning); + EditorGUILayout.HelpBox("Collider detected. Unity recommends adding a Rigidbody to the Transforms of any colliders that are intended to be dynamically repositioned and rotated.", MessageType.Warning); var rbType = hasCollider2D ? typeof(Rigidbody2D) : typeof(Rigidbody); string rbLabel = string.Format("Add {0}", rbType.Name); var rbContent = SpineInspectorUtility.TempContent(rbLabel, SpineInspectorUtility.UnityIcon(rbType), "Add a rigidbody to this GameObject to be the Physics body parent of the attached collider."); diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SkeletonAnimationInspector.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SkeletonAnimationInspector.cs index b5755dcda..4f9d5d189 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SkeletonAnimationInspector.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SkeletonAnimationInspector.cs @@ -56,16 +56,12 @@ namespace Spine.Unity.Editor { bool sameData = SpineInspectorUtility.TargetsUseSameData(serializedObject); if (multi) { - foreach (var o in targets) - TrySetAnimation(o, multi); + foreach (var o in targets) + TrySetAnimation(o as SkeletonAnimation, multi); EditorGUILayout.Space(); if (!sameData) { - #if UNITY_5_3_OR_NEWER EditorGUILayout.DelayedTextField(animationName); - #else - animationName.stringValue = EditorGUILayout.TextField(animationName.displayName, animationName.stringValue); - #endif } else { EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(animationName); @@ -78,7 +74,7 @@ namespace Spine.Unity.Editor { component.timeScale = Mathf.Max(component.timeScale, 0); } } else { - TrySetAnimation(target, multi); + TrySetAnimation(target as SkeletonAnimation, multi); EditorGUILayout.Space(); EditorGUI.BeginChangeCheck(); @@ -99,31 +95,33 @@ namespace Spine.Unity.Editor { } } - protected void TrySetAnimation (Object o, bool multi) { - var skeletonAnimation = o as SkeletonAnimation; + protected void TrySetAnimation (SkeletonAnimation skeletonAnimation, bool multi) { if (skeletonAnimation == null) return; if (!skeletonAnimation.valid) return; if (!isInspectingPrefab) { if (wasAnimationNameChanged) { + var skeleton = skeletonAnimation.Skeleton; + var state = skeletonAnimation.AnimationState; + if (!Application.isPlaying) { - if (skeletonAnimation.state != null) skeletonAnimation.state.ClearTrack(0); - skeletonAnimation.skeleton.SetToSetupPose(); + if (state != null) state.ClearTrack(0); + skeleton.SetToSetupPose(); } - Spine.Animation animationToUse = skeletonAnimation.skeleton.Data.FindAnimation(animationName.stringValue); + Spine.Animation animationToUse = skeleton.Data.FindAnimation(animationName.stringValue); if (!Application.isPlaying) { - if (animationToUse != null) animationToUse.PoseSkeleton(skeletonAnimation.Skeleton, 0f); - skeletonAnimation.Update(0); + if (animationToUse != null) animationToUse.PoseSkeleton(skeleton, 0f); + skeleton.UpdateWorldTransform(); skeletonAnimation.LateUpdate(); requireRepaint = true; } else { if (animationToUse != null) - skeletonAnimation.state.SetAnimation(0, animationToUse, loop.boolValue); + state.SetAnimation(0, animationToUse, loop.boolValue); else - skeletonAnimation.state.ClearTrack(0); + state.ClearTrack(0); } wasAnimationNameChanged = false; @@ -131,7 +129,7 @@ namespace Spine.Unity.Editor { // Reflect animationName serialized property in the inspector even if SetAnimation API was used. if (!multi && Application.isPlaying) { - TrackEntry current = skeletonAnimation.state.GetCurrent(0); + TrackEntry current = skeletonAnimation.AnimationState.GetCurrent(0); if (current != null) { if (skeletonAnimation.AnimationName != animationName.stringValue) animationName.stringValue = current.Animation.Name; diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SkeletonRendererInspector.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SkeletonRendererInspector.cs index 79858f680..1750fa54d 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SkeletonRendererInspector.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SkeletonRendererInspector.cs @@ -49,14 +49,20 @@ namespace Spine.Unity.Editor { protected SerializedProperty skeletonDataAsset, initialSkinName; protected SerializedProperty initialFlipX, initialFlipY; protected SerializedProperty singleSubmesh, separatorSlotNames, clearStateOnDisable, immutableTriangles; - protected SerializedProperty normals, tangents, meshes, zSpacing, pmaVertexColors, tintBlack; // MeshGenerator settings + protected SerializedProperty normals, tangents, zSpacing, pmaVertexColors, tintBlack; // MeshGenerator settings protected SpineInspectorUtility.SerializedSortingProperties sortingProperties; + protected bool isInspectingPrefab; + protected bool forceReloadQueued = false; protected GUIContent SkeletonDataAssetLabel, SkeletonUtilityButtonContent; - protected GUIContent PMAVertexColorsLabel, ClearStateOnDisableLabel, ZSpacingLabel, MeshesLabel, ImmubleTrianglesLabel, TintBlackLabel, SingleSubmeshLabel; + protected GUIContent PMAVertexColorsLabel, ClearStateOnDisableLabel, ZSpacingLabel, ImmubleTrianglesLabel, TintBlackLabel, SingleSubmeshLabel; protected GUIContent NormalsLabel, TangentsLabel; - const string ReloadButtonLabel = "Reload"; + + const string ReloadButtonString = "Reload"; + static GUILayoutOption reloadButtonWidth; + static GUILayoutOption ReloadButtonWidth { get { return reloadButtonWidth = reloadButtonWidth ?? GUILayout.Width(GUI.skin.label.CalcSize(new GUIContent(ReloadButtonString)).x + 20); } } + static GUIStyle ReloadButtonStyle { get { return EditorStyles.miniButtonRight; } } protected bool TargetIsValid { get { @@ -76,13 +82,12 @@ namespace Spine.Unity.Editor { protected virtual void OnEnable () { isInspectingPrefab = (PrefabUtility.GetPrefabType(target) == PrefabType.Prefab); - + SpineEditorUtilities.ConfirmInitialization(); // Labels SkeletonDataAssetLabel = new GUIContent("SkeletonData Asset", Icons.spine); SkeletonUtilityButtonContent = new GUIContent("Add Skeleton Utility", Icons.skeletonUtility); - MeshesLabel = new GUIContent("Render MeshAttachments", "Disable to optimize rendering for skeletons that don't use Mesh Attachments"); ImmubleTrianglesLabel = new GUIContent("Immutable Triangles", "Enable to optimize rendering for skeletons that never change attachment visbility"); PMAVertexColorsLabel = new GUIContent("PMA Vertex Colors", "Use this if you are using the default Spine/Skeleton shader or any premultiply-alpha shader."); ClearStateOnDisableLabel = new GUIContent("Clear State On Disable", "Use this if you are pooling or enabling/disabling your Spine GameObject."); @@ -90,7 +95,7 @@ namespace Spine.Unity.Editor { NormalsLabel = new GUIContent("Add Normals", "Use this if your shader requires vertex normals. A more efficient solution for 2D setups is to modify the shader to assume a single normal value for the whole mesh."); TangentsLabel = new GUIContent("Solve Tangents", "Calculates the tangents per frame. Use this if you are using lit shaders (usually with normal maps) that require vertex tangents."); TintBlackLabel = new GUIContent("Tint Black (!)", "Adds black tint vertex data to the mesh as UV2 and UV3. Black tinting requires that the shader interpret UV2 and UV3 as black tint colors for this effect to work. You may also use the default [Spine/Skeleton Tint Black] shader.\n\nIf you only need to tint the whole skeleton and not individual parts, the [Spine/Skeleton Tint] shader is recommended for better efficiency and changing/animating the _Black material property via MaterialPropertyBlock."); - SingleSubmeshLabel = new GUIContent("Use Single Submesh", "Simplifies submesh determination by assuming you are only using one Material and need only one submesh. This is will disable render separation and custom slot materials."); + SingleSubmeshLabel = new GUIContent("Use Single Submesh", "Simplifies submesh generation by assuming you are only using one Material and need only one submesh. This is will disable multiple materials, render separation, and custom slot materials."); var so = this.serializedObject; skeletonDataAsset = so.FindProperty("skeletonDataAsset"); @@ -99,7 +104,6 @@ namespace Spine.Unity.Editor { initialFlipY = so.FindProperty("initialFlipY"); normals = so.FindProperty("addNormals"); tangents = so.FindProperty("calculateTangents"); - meshes = so.FindProperty("renderMeshes"); immutableTriangles = so.FindProperty("immutableTriangles"); pmaVertexColors = so.FindProperty("pmaVertexColors"); clearStateOnDisable = so.FindProperty("clearStateOnDisable"); @@ -111,80 +115,115 @@ namespace Spine.Unity.Editor { zSpacing = so.FindProperty("zSpacing"); - SerializedObject rso = SpineInspectorUtility.GetRenderersSerializedObject(serializedObject); - sortingProperties = new SpineInspectorUtility.SerializedSortingProperties(rso); + SerializedObject renderersSerializedObject = SpineInspectorUtility.GetRenderersSerializedObject(serializedObject); // Allows proper multi-edit behavior. + sortingProperties = new SpineInspectorUtility.SerializedSortingProperties(renderersSerializedObject); } - GUIContent[] skins; - ExposedList loadedSkinList; + public void OnSceneGUI () { + var skeletonRenderer = (SkeletonRenderer)target; + var skeleton = skeletonRenderer.Skeleton; + var transform = skeletonRenderer.transform; + if (skeleton == null) return; + + SpineHandles.DrawBones(transform, skeleton); + } + + override public void OnInspectorGUI () { + bool multi = serializedObject.isEditingMultipleObjects; + DrawInspectorGUI(multi); + if (serializedObject.ApplyModifiedProperties() || SpineInspectorUtility.UndoRedoPerformed(Event.current)) { + if (!Application.isPlaying) { + if (multi) { + foreach (var o in targets) EditorForceInitializeComponent((SkeletonRenderer)o); + } else { + EditorForceInitializeComponent((SkeletonRenderer)target); + } + SceneView.RepaintAll(); + } + } + + if (!Application.isPlaying && Event.current.type == EventType.Layout) { + bool mismatchDetected = false; + if (multi) { + foreach (var o in targets) + mismatchDetected |= UpdateIfSkinMismatch((SkeletonRenderer)o); + } else { + mismatchDetected |= UpdateIfSkinMismatch(target as SkeletonRenderer); + } + + if (mismatchDetected) { + mismatchDetected = false; + SceneView.RepaintAll(); + } + } + } protected virtual void DrawInspectorGUI (bool multi) { - bool valid = TargetIsValid; - var reloadWidth = GUILayout.Width(GUI.skin.label.CalcSize(new GUIContent(ReloadButtonLabel)).x + 20); - var reloadButtonStyle = EditorStyles.miniButtonRight; - - if (multi) { - using (new EditorGUILayout.HorizontalScope(EditorStyles.helpBox)) { - SpineInspectorUtility.PropertyFieldFitLabel(skeletonDataAsset, SkeletonDataAssetLabel); - if (GUILayout.Button(ReloadButtonLabel, reloadButtonStyle, reloadWidth)) { + // Initialize. + if (Event.current.type == EventType.Layout) { + if (forceReloadQueued) { + forceReloadQueued = false; + if (multi) { + foreach (var c in targets) + EditorForceReloadSkeletonDataAssetAndComponent(c as SkeletonRenderer); + } else { + EditorForceReloadSkeletonDataAssetAndComponent(target as SkeletonRenderer); + } + } else { + if (multi) { foreach (var c in targets) { var component = c as SkeletonRenderer; - if (component.skeletonDataAsset != null) { - foreach (AtlasAssetBase aa in component.skeletonDataAsset.atlasAssets) { - if (aa != null) - aa.Clear(); - } - component.skeletonDataAsset.Clear(); + if (!component.valid) { + EditorForceInitializeComponent(component); + if (!component.valid) continue; } - component.Initialize(true); } + } else { + var component = (SkeletonRenderer)target; + if (!component.valid) + EditorForceInitializeComponent(component); } } - foreach (var c in targets) { - var component = c as SkeletonRenderer; - if (!component.valid) { - if (Event.current.type == EventType.Layout) { - component.Initialize(true); - component.LateUpdate(); + #if NO_PREFAB_MESH + if (isInspectingPrefab) { + if (multi) { + foreach (var c in targets) { + var component = (SkeletonRenderer)c; + MeshFilter meshFilter = component.GetComponent(); + if (meshFilter != null && meshFilter.sharedMesh != null) + meshFilter.sharedMesh = null; } - if (!component.valid) - continue; - } - - #if NO_PREFAB_MESH - if (isInspectingPrefab) { + } else { + var component = (SkeletonRenderer)target; MeshFilter meshFilter = component.GetComponent(); if (meshFilter != null && meshFilter.sharedMesh != null) meshFilter.sharedMesh = null; } - #endif } - - if (valid) - EditorGUILayout.PropertyField(initialSkinName); + #endif + } + + bool valid = TargetIsValid; + + // Fields. + if (multi) { + using (new EditorGUILayout.HorizontalScope(EditorStyles.helpBox)) { + SpineInspectorUtility.PropertyFieldFitLabel(skeletonDataAsset, SkeletonDataAssetLabel); + if (GUILayout.Button(ReloadButtonString, ReloadButtonStyle, ReloadButtonWidth)) + forceReloadQueued = true; + } + + if (valid) EditorGUILayout.PropertyField(initialSkinName, SpineInspectorUtility.TempContent("Initial Skin")); } else { var component = (SkeletonRenderer)target; - if (!component.valid && Event.current.type == EventType.Layout) { - component.Initialize(true); - component.LateUpdate(); - } - using (new EditorGUILayout.HorizontalScope(EditorStyles.helpBox)) { SpineInspectorUtility.PropertyFieldFitLabel(skeletonDataAsset, SkeletonDataAssetLabel); if (component.valid) { - if (GUILayout.Button(ReloadButtonLabel, reloadButtonStyle, reloadWidth)) { - if (component.skeletonDataAsset != null) { - foreach (AtlasAssetBase aa in component.skeletonDataAsset.atlasAssets) { - if (aa != null) - aa.Clear(); - } - component.skeletonDataAsset.Clear(); - } - component.Initialize(true); - } + if (GUILayout.Button(ReloadButtonString, ReloadButtonStyle, ReloadButtonWidth)) + forceReloadQueued = true; } } @@ -193,38 +232,14 @@ namespace Spine.Unity.Editor { return; } - #if NO_PREFAB_MESH - if (isInspectingPrefab) { - MeshFilter meshFilter = component.GetComponent(); - if (meshFilter != null && meshFilter.sharedMesh != null) - meshFilter.sharedMesh = null; + if (!SkeletonDataAssetIsValid(component.skeletonDataAsset)) { + EditorGUILayout.HelpBox("Skeleton Data Asset error. Please check Skeleton Data Asset.", MessageType.Error); + return; } - #endif - // Initial skin name. - if (component.valid) { - var skeletonDataSkins = component.skeleton.Data.Skins; - int skinCount = skeletonDataSkins.Count; - if (loadedSkinList != skeletonDataSkins) { - skins = new GUIContent[skinCount]; - loadedSkinList = skeletonDataSkins; - for (int i = 0; i < skins.Length; i++) { - string skinNameString = skeletonDataSkins.Items[i].Name; - skins[i] = new GUIContent(skinNameString, Icons.skin); - } - } - - int skinIndex = 0; - for (int i = 0; i < skins.Length; i++) { - string skinNameString = skeletonDataSkins.Items[i].Name; - if (skinNameString == initialSkinName.stringValue) - skinIndex = i; - } - - skinIndex = EditorGUILayout.Popup(SpineInspectorUtility.TempContent("Initial Skin"), skinIndex, skins); - if (skins.Length > 0) // Support attachmentless/skinless SkeletonData. - initialSkinName.stringValue = skins[skinIndex].text; - } + if (valid) + EditorGUILayout.PropertyField(initialSkinName, SpineInspectorUtility.TempContent("Initial Skin")); + } EditorGUILayout.Space(); @@ -232,8 +247,9 @@ namespace Spine.Unity.Editor { // Sorting Layers SpineInspectorUtility.SortingPropertyFields(sortingProperties, applyModifiedProperties: true); - if (!TargetIsValid) return; - + if (!valid) + return; + // More Render Options... using (new SpineInspectorUtility.BoxScope()) { EditorGUI.BeginChangeCheck(); @@ -250,11 +266,11 @@ namespace Spine.Unity.Editor { EditorGUILayout.EndHorizontal(); if (advancedFoldout) { - + using (new SpineInspectorUtility.IndentScope()) { using (new EditorGUILayout.HorizontalScope()) { SpineInspectorUtility.ToggleLeftLayout(initialFlipX); - SpineInspectorUtility.ToggleLeftLayout(initialFlipY); + SpineInspectorUtility.ToggleLeftLayout(initialFlipY); EditorGUILayout.Space(); } @@ -263,7 +279,6 @@ namespace Spine.Unity.Editor { using (new SpineInspectorUtility.LabelWidthScope()) { // Optimization options if (singleSubmesh != null) EditorGUILayout.PropertyField(singleSubmesh, SingleSubmeshLabel); - //if (meshes != null) EditorGUILayout.PropertyField(meshes, MeshesLabel); if (immutableTriangles != null) EditorGUILayout.PropertyField(immutableTriangles, ImmubleTrianglesLabel); EditorGUILayout.PropertyField(clearStateOnDisable, ClearStateOnDisableLabel); EditorGUILayout.Space(); @@ -290,7 +305,7 @@ namespace Spine.Unity.Editor { EditorGUILayout.Space(); - if (TargetIsValid && !isInspectingPrefab) { + if (valid && !isInspectingPrefab) { if (multi) { // Support multi-edit SkeletonUtility button. // EditorGUILayout.Space(); @@ -302,7 +317,7 @@ namespace Spine.Unity.Editor { // } } else { var component = (Component)target; - if (component.GetComponent() == null) { + if (component.GetComponent() == null) { if (SpineInspectorUtility.CenteredButton(SkeletonUtilityButtonContent, 21, true, 200f)) component.gameObject.AddComponent(); } @@ -330,7 +345,7 @@ namespace Spine.Unity.Editor { var sr = separatorSlotNames.serializedObject.targetObject as ISkeletonComponent; var skeleton = sr.Skeleton; int lastSlot = skeleton.Slots.Count - 1; - if (skeleton != null) { + if (skeleton != null) { for (int i = 0, n = separatorSlotNames.arraySize; i < n; i++) { int index = skeleton.FindSlotIndex(separatorSlotNames.GetArrayElementAtIndex(i).stringValue); if (index == 0 || index == lastSlot) { @@ -360,27 +375,50 @@ namespace Spine.Unity.Editor { } } - public void OnSceneGUI () { - var skeletonRenderer = (SkeletonRenderer)target; - var skeleton = skeletonRenderer.skeleton; - var transform = skeletonRenderer.transform; - if (skeleton == null) return; + static bool UpdateIfSkinMismatch (SkeletonRenderer skeletonRenderer) { + if (!skeletonRenderer.valid) return false; - SpineHandles.DrawBones(transform, skeleton); + var skin = skeletonRenderer.Skeleton.Skin; + string skeletonSkinName = skin != null ? skin.Name : null; + string componentSkinName = skeletonRenderer.initialSkinName; + bool defaultCase = skin == null && string.IsNullOrEmpty(componentSkinName); + bool fieldMatchesSkin = defaultCase || string.Equals(componentSkinName, skeletonSkinName, System.StringComparison.Ordinal); + + if (!fieldMatchesSkin) { + Skin skinToSet = string.IsNullOrEmpty(componentSkinName) ? null : skeletonRenderer.Skeleton.Data.FindSkin(componentSkinName); + skeletonRenderer.Skeleton.Skin = skinToSet; + skeletonRenderer.Skeleton.SetSlotsToSetupPose(); + skeletonRenderer.LateUpdate(); + return true; + } + return false; } - override public void OnInspectorGUI () { - bool multi = serializedObject.isEditingMultipleObjects; - DrawInspectorGUI(multi); - if (serializedObject.ApplyModifiedProperties() || SpineInspectorUtility.UndoRedoPerformed(Event.current)) { - if (!Application.isPlaying) { - if (multi) - foreach (var o in targets) - ((SkeletonRenderer)o).Initialize(true); - else - ((SkeletonRenderer)target).Initialize(true); + static void EditorForceReloadSkeletonDataAssetAndComponent (SkeletonRenderer component) { + if (component == null) return; + + // Clear all and reload. + if (component.skeletonDataAsset != null) { + foreach (AtlasAssetBase aa in component.skeletonDataAsset.atlasAssets) { + if (aa != null) aa.Clear(); } + component.skeletonDataAsset.Clear(); } + component.skeletonDataAsset.GetSkeletonData(true); + + // Reinitialize. + EditorForceInitializeComponent(component); + } + + static void EditorForceInitializeComponent (SkeletonRenderer component) { + if (component == null) return; + if (!SkeletonDataAssetIsValid(component.SkeletonDataAsset)) return; + component.Initialize(true); + component.LateUpdate(); + } + + static bool SkeletonDataAssetIsValid (SkeletonDataAsset asset) { + return asset != null && asset.GetSkeletonData(quiet: true) != null; } } diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineAttributeDrawers.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineAttributeDrawers.cs index f66134ec7..4e71bf522 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineAttributeDrawers.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineAttributeDrawers.cs @@ -39,24 +39,24 @@ using Spine; namespace Spine.Unity.Editor { public struct SpineDrawerValuePair { - public string str; + public string stringValue; public SerializedProperty property; public SpineDrawerValuePair (string val, SerializedProperty property) { - this.str = val; + this.stringValue = val; this.property = property; } } public abstract class SpineTreeItemDrawerBase : PropertyDrawer where T:SpineAttributeBase { protected SkeletonDataAsset skeletonDataAsset; - internal const string NoneString = ""; + internal const string NoneStringConstant = ""; - // Analysis disable once StaticFieldInGenericType - static GUIContent noneLabel; - static GUIContent NoneLabel (Texture2D image = null) { - if (noneLabel == null) - noneLabel = new GUIContent(NoneString); + internal virtual string NoneString { get { return NoneStringConstant; } } + + GUIContent noneLabel; + GUIContent NoneLabel (Texture2D image = null) { + if (noneLabel == null) noneLabel = new GUIContent(NoneString); noneLabel.image = image; return noneLabel; } @@ -74,6 +74,12 @@ namespace Spine.Unity.Editor { return; } + // Handle multi-editing when instances don't use the same SkeletonDataAsset. + if (!SpineInspectorUtility.TargetsUseSameData(property.serializedObject)) { + EditorGUI.DelayedTextField(position, property, label); + return; + } + SerializedProperty dataField = property.FindBaseOrSiblingProperty(TargetAttribute.dataField); if (dataField != null) { @@ -116,8 +122,8 @@ namespace Spine.Unity.Editor { position = EditorGUI.PrefixLabel(position, label); - var image = Icon; - var propertyStringValue = (property.hasMultipleDifferentValues) ? SpineInspectorUtility.EmDash : property.stringValue; + Texture2D image = Icon; + string propertyStringValue = (property.hasMultipleDifferentValues) ? SpineInspectorUtility.EmDash : property.stringValue; if (GUI.Button(position, string.IsNullOrEmpty(propertyStringValue) ? NoneLabel(image) : SpineInspectorUtility.TempContent(propertyStringValue, image), EditorStyles.popup)) Selector(property); } @@ -151,8 +157,10 @@ namespace Spine.Unity.Editor { protected virtual void HandleSelect (object menuItemObject) { var clickedItem = (SpineDrawerValuePair)menuItemObject; - clickedItem.property.stringValue = clickedItem.str; - clickedItem.property.serializedObject.ApplyModifiedProperties(); + var serializedProperty = clickedItem.property; + if (serializedProperty.serializedObject.isEditingMultipleObjects) serializedProperty.stringValue = "oaifnoiasf°ñ123526"; // HACK: to trigger change on multi-editing. + serializedProperty.stringValue = clickedItem.stringValue; + serializedProperty.serializedObject.ApplyModifiedProperties(); } public override float GetPropertyHeight (SerializedProperty property, GUIContent label) { @@ -167,9 +175,8 @@ namespace Spine.Unity.Editor { protected override Texture2D Icon { get { return SpineEditorUtilities.Icons.slot; } } protected override void PopulateMenu (GenericMenu menu, SerializedProperty property, SpineSlot targetAttribute, SkeletonData data) { - if (TargetAttribute.includeNone) - menu.AddItem(new GUIContent(NoneString), string.IsNullOrEmpty(property.stringValue), HandleSelect, new SpineDrawerValuePair(string.Empty, property)); + menu.AddItem(new GUIContent(NoneString), !property.hasMultipleDifferentValues && string.IsNullOrEmpty(property.stringValue), HandleSelect, new SpineDrawerValuePair(string.Empty, property)); for (int i = 0; i < data.Slots.Count; i++) { string name = data.Slots.Items[i].Name; @@ -186,7 +193,7 @@ namespace Spine.Unity.Editor { var bbAttachment = attachment as BoundingBoxAttachment; if (bbAttachment != null) { string menuLabel = bbAttachment.IsWeighted() ? name + " (!)" : name; - menu.AddItem(new GUIContent(menuLabel), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); + menu.AddItem(new GUIContent(menuLabel), !property.hasMultipleDifferentValues && name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); hasBoundingBox = true; break; } @@ -196,7 +203,7 @@ namespace Spine.Unity.Editor { menu.AddDisabledItem(new GUIContent(name)); } else { - menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); + menu.AddItem(new GUIContent(name), !property.hasMultipleDifferentValues && name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); } } @@ -208,28 +215,33 @@ namespace Spine.Unity.Editor { [CustomPropertyDrawer(typeof(SpineSkin))] public class SpineSkinDrawer : SpineTreeItemDrawerBase { + const string DefaultSkinName = "default"; protected override Texture2D Icon { get { return SpineEditorUtilities.Icons.skin; } } - public static void GetSkinMenuItems (SkeletonData data, List animationNames, List menuItems, bool includeNone = true) { + internal override string NoneString { get { return TargetAttribute.defaultAsEmptyString ? DefaultSkinName : NoneStringConstant; } } + + public static void GetSkinMenuItems (SkeletonData data, List outputNames, List outputMenuItems, bool includeNone = true) { if (data == null) return; + if (outputNames == null) return; + if (outputMenuItems == null) return; var skins = data.Skins; - animationNames.Clear(); - menuItems.Clear(); + outputNames.Clear(); + outputMenuItems.Clear(); var icon = SpineEditorUtilities.Icons.skin; if (includeNone) { - animationNames.Add(""); - menuItems.Add(new GUIContent(NoneString, icon)); + outputNames.Add(""); + outputMenuItems.Add(new GUIContent(NoneStringConstant, icon)); } foreach (var s in skins) { - var skinName = s.Name; - animationNames.Add(skinName); - menuItems.Add(new GUIContent(skinName, icon)); + string skinName = s.Name; + outputNames.Add(skinName); + outputMenuItems.Add(new GUIContent(skinName, icon)); } } @@ -239,9 +251,13 @@ namespace Spine.Unity.Editor { for (int i = 0; i < data.Skins.Count; i++) { string name = data.Skins.Items[i].Name; - if (name.StartsWith(targetAttribute.startsWith, StringComparison.Ordinal)) - menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); - } + if (name.StartsWith(targetAttribute.startsWith, StringComparison.Ordinal)) { + bool isDefault = string.Equals(name, DefaultSkinName, StringComparison.Ordinal); + string choiceValue = TargetAttribute.defaultAsEmptyString && isDefault ? string.Empty : name; + menu.AddItem(new GUIContent(name), !property.hasMultipleDifferentValues && choiceValue == property.stringValue, HandleSelect, new SpineDrawerValuePair(choiceValue, property)); + } + + } } } @@ -251,23 +267,25 @@ namespace Spine.Unity.Editor { protected override Texture2D Icon { get { return SpineEditorUtilities.Icons.animation; } } - public static void GetAnimationMenuItems (SkeletonData data, List animationNames, List menuItems, bool includeNone = true) { + public static void GetAnimationMenuItems (SkeletonData data, List outputNames, List outputMenuItems, bool includeNone = true) { if (data == null) return; + if (outputNames == null) return; + if (outputMenuItems == null) return; var animations = data.Animations; - animationNames.Clear(); - menuItems.Clear(); + outputNames.Clear(); + outputMenuItems.Clear(); if (includeNone) { - animationNames.Add(""); - menuItems.Add(new GUIContent(NoneString, SpineEditorUtilities.Icons.animation)); + outputNames.Add(""); + outputMenuItems.Add(new GUIContent(NoneStringConstant, SpineEditorUtilities.Icons.animation)); } foreach (var a in animations) { - var animationName = a.Name; - animationNames.Add(animationName); - menuItems.Add(new GUIContent(animationName, SpineEditorUtilities.Icons.animation)); + string animationName = a.Name; + outputNames.Add(animationName); + outputMenuItems.Add(new GUIContent(animationName, SpineEditorUtilities.Icons.animation)); } } @@ -275,12 +293,12 @@ namespace Spine.Unity.Editor { var animations = skeletonDataAsset.GetAnimationStateData().SkeletonData.Animations; if (TargetAttribute.includeNone) - menu.AddItem(new GUIContent(NoneString), string.IsNullOrEmpty(property.stringValue), HandleSelect, new SpineDrawerValuePair(string.Empty, property)); + menu.AddItem(new GUIContent(NoneString), !property.hasMultipleDifferentValues && string.IsNullOrEmpty(property.stringValue), HandleSelect, new SpineDrawerValuePair(string.Empty, property)); for (int i = 0; i < animations.Count; i++) { string name = animations.Items[i].Name; if (name.StartsWith(targetAttribute.startsWith, StringComparison.Ordinal)) - menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); + menu.AddItem(new GUIContent(name), !property.hasMultipleDifferentValues && name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); } } @@ -301,7 +319,7 @@ namespace Spine.Unity.Editor { if (includeNone) { eventNames.Add(""); - menuItems.Add(new GUIContent(NoneString, SpineEditorUtilities.Icons.userEvent)); + menuItems.Add(new GUIContent(NoneStringConstant, SpineEditorUtilities.Icons.userEvent)); } foreach (var a in animations) { @@ -315,12 +333,12 @@ namespace Spine.Unity.Editor { var events = skeletonDataAsset.GetSkeletonData(false).Events; if (TargetAttribute.includeNone) - menu.AddItem(new GUIContent(NoneString), string.IsNullOrEmpty(property.stringValue), HandleSelect, new SpineDrawerValuePair(string.Empty, property)); + menu.AddItem(new GUIContent(NoneString), !property.hasMultipleDifferentValues && string.IsNullOrEmpty(property.stringValue), HandleSelect, new SpineDrawerValuePair(string.Empty, property)); for (int i = 0; i < events.Count; i++) { string name = events.Items[i].Name; if (name.StartsWith(targetAttribute.startsWith, StringComparison.Ordinal)) - menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); + menu.AddItem(new GUIContent(name), !property.hasMultipleDifferentValues && name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); } } @@ -335,12 +353,12 @@ namespace Spine.Unity.Editor { var constraints = skeletonDataAsset.GetSkeletonData(false).IkConstraints; if (TargetAttribute.includeNone) - menu.AddItem(new GUIContent(NoneString), string.IsNullOrEmpty(property.stringValue), HandleSelect, new SpineDrawerValuePair(string.Empty, property)); + menu.AddItem(new GUIContent(NoneString), !property.hasMultipleDifferentValues && string.IsNullOrEmpty(property.stringValue), HandleSelect, new SpineDrawerValuePair(string.Empty, property)); for (int i = 0; i < constraints.Count; i++) { string name = constraints.Items[i].Name; if (name.StartsWith(targetAttribute.startsWith, StringComparison.Ordinal)) - menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); + menu.AddItem(new GUIContent(name), !property.hasMultipleDifferentValues && name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); } } @@ -355,12 +373,12 @@ namespace Spine.Unity.Editor { var constraints = skeletonDataAsset.GetSkeletonData(false).TransformConstraints; if (TargetAttribute.includeNone) - menu.AddItem(new GUIContent(NoneString), string.IsNullOrEmpty(property.stringValue), HandleSelect, new SpineDrawerValuePair(string.Empty, property)); + menu.AddItem(new GUIContent(NoneString), !property.hasMultipleDifferentValues && string.IsNullOrEmpty(property.stringValue), HandleSelect, new SpineDrawerValuePair(string.Empty, property)); for (int i = 0; i < constraints.Count; i++) { string name = constraints.Items[i].Name; if (name.StartsWith(targetAttribute.startsWith, StringComparison.Ordinal)) - menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); + menu.AddItem(new GUIContent(name), !property.hasMultipleDifferentValues && name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); } } } @@ -374,12 +392,12 @@ namespace Spine.Unity.Editor { var constraints = skeletonDataAsset.GetSkeletonData(false).PathConstraints; if (TargetAttribute.includeNone) - menu.AddItem(new GUIContent(NoneString), string.IsNullOrEmpty(property.stringValue), HandleSelect, new SpineDrawerValuePair(string.Empty, property)); + menu.AddItem(new GUIContent(NoneString), !property.hasMultipleDifferentValues && string.IsNullOrEmpty(property.stringValue), HandleSelect, new SpineDrawerValuePair(string.Empty, property)); for (int i = 0; i < constraints.Count; i++) { string name = constraints.Items[i].Name; if (name.StartsWith(targetAttribute.startsWith, StringComparison.Ordinal)) - menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); + menu.AddItem(new GUIContent(name), !property.hasMultipleDifferentValues && name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); } } } @@ -422,7 +440,7 @@ namespace Spine.Unity.Editor { menu.AddSeparator(""); if (TargetAttribute.includeNone) { const string NullAttachmentName = ""; - menu.AddItem(new GUIContent("Null"), property.stringValue == NullAttachmentName, HandleSelect, new SpineDrawerValuePair(NullAttachmentName, property)); + menu.AddItem(new GUIContent("Null"), !property.hasMultipleDifferentValues && property.stringValue == NullAttachmentName, HandleSelect, new SpineDrawerValuePair(NullAttachmentName, property)); menu.AddSeparator(""); } @@ -465,7 +483,7 @@ namespace Spine.Unity.Editor { if (targetAttribute.placeholdersOnly && !placeholderNames.Contains(attachmentPath)) { menu.AddDisabledItem(new GUIContent(menuPath)); } else { - menu.AddItem(new GUIContent(menuPath), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); + menu.AddItem(new GUIContent(menuPath), !property.hasMultipleDifferentValues && name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); } } @@ -485,12 +503,12 @@ namespace Spine.Unity.Editor { menu.AddSeparator(""); if (TargetAttribute.includeNone) - menu.AddItem(new GUIContent(NoneString), string.IsNullOrEmpty(property.stringValue), HandleSelect, new SpineDrawerValuePair(string.Empty, property)); + menu.AddItem(new GUIContent(NoneString), !property.hasMultipleDifferentValues && string.IsNullOrEmpty(property.stringValue), HandleSelect, new SpineDrawerValuePair(string.Empty, property)); for (int i = 0; i < data.Bones.Count; i++) { string name = data.Bones.Items[i].Name; if (name.StartsWith(targetAttribute.startsWith, StringComparison.Ordinal)) - menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); + menu.AddItem(new GUIContent(name), !property.hasMultipleDifferentValues && name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); } } @@ -540,7 +558,7 @@ namespace Spine.Unity.Editor { for (int i = 0; i < regions.Count; i++) { string name = regions[i].name; - menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); + menu.AddItem(new GUIContent(name), !property.hasMultipleDifferentValues && name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); } menu.ShowAsContext(); @@ -548,7 +566,7 @@ namespace Spine.Unity.Editor { static void HandleSelect (object val) { var pair = (SpineDrawerValuePair)val; - pair.property.stringValue = pair.str; + pair.property.stringValue = pair.stringValue; pair.property.serializedObject.ApplyModifiedProperties(); } diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineEditorUtilities.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineEditorUtilities.cs index 5043aa1fd..282ffdfdd 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineEditorUtilities.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineEditorUtilities.cs @@ -1202,7 +1202,7 @@ namespace Spine.Unity.Editor { var data = skeletonDataAsset.GetSkeletonData(false); bool noSkins = data.DefaultSkin == null && (data.Skins == null || data.Skins.Count == 0); // Support attachmentless/skinless SkeletonData. skin = skin ?? data.DefaultSkin ?? (noSkins ? null : data.Skins.Items[0]); - if (skin != null) { + if (skin != null && skin != data.DefaultSkin) { skeletonRenderer.initialSkinName = skin.Name; } } diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineInspectorUtility.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineInspectorUtility.cs index cf395daec..d1cdcc0cd 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineInspectorUtility.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineInspectorUtility.cs @@ -165,8 +165,9 @@ namespace Spine.Unity.Editor { public static GUIStyle GrayMiniLabel { get { if (grayMiniLabel == null) { - grayMiniLabel = new GUIStyle(EditorStyles.centeredGreyMiniLabel); - grayMiniLabel.alignment = TextAnchor.UpperLeft; + grayMiniLabel = new GUIStyle(EditorStyles.centeredGreyMiniLabel) { + alignment = TextAnchor.UpperLeft + }; } return grayMiniLabel; } diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs index 9b1f3f52c..17eacbfc8 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs @@ -48,6 +48,7 @@ namespace Spine.Unity { public SkeletonDataAsset skeletonDataAsset; public SkeletonDataAsset SkeletonDataAsset { get { return skeletonDataAsset; } } // ISkeletonComponent + [SpineSkin(defaultAsEmptyString:true)] public string initialSkinName; public bool initialFlipX, initialFlipY; diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/SpineAttributes.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/SpineAttributes.cs index 5f3d7ed91..acb5b5ec0 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/SpineAttributes.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/SpineAttributes.cs @@ -149,17 +149,23 @@ namespace Spine.Unity { /// Filters popup results to elements that begin with supplied string. /// If true, the dropdown list will include a "none" option which stored as an empty string. /// If true, and an animation list source can't be found, the field will fall back to a normal text field. If false, it will show an error. + /// If true, the default choice will be serialized as an empty string. /// If specified, a locally scoped field with the name supplied by in dataField will be used to fill the popup results. /// Valid types are SkeletonDataAsset and SkeletonRenderer (and derivatives) /// If left empty and the script the attribute is applied to is derived from Component, GetComponent() will be called as a fallback. /// - public SpineSkin (string startsWith = "", string dataField = "", bool includeNone = true, bool fallbackToTextField = false) { + + public bool defaultAsEmptyString = false; + + public SpineSkin (string startsWith = "", string dataField = "", bool includeNone = true, bool fallbackToTextField = false, bool defaultAsEmptyString = false) { this.startsWith = startsWith; this.dataField = dataField; this.includeNone = includeNone; this.fallbackToTextField = fallbackToTextField; + this.defaultAsEmptyString = defaultAsEmptyString; } } + public class SpineAnimation : SpineAttributeBase { /// /// Smart popup menu for Spine Animations From 910e88bbb3c92f9055234a6fd1c161137d8de2f3 Mon Sep 17 00:00:00 2001 From: pharan Date: Mon, 8 Oct 2018 04:55:47 +0800 Subject: [PATCH 7/9] [unity] Assorted cleanup. --- .../Editor/SpineInspectorUtility.cs | 6 -- .../Editor/SkeletonUtilityBoneInspector.cs | 14 ++- .../Editor/SkeletonUtilityInspector.cs | 57 +++++------ .../Asset Types/SkeletonDataAsset.cs.meta | 12 ++- .../spine-unity/Components/BoneFollower.cs | 4 +- .../Components/SkeletonRenderer.cs | 3 +- .../Runtime/spine-unity/ISkeletonAnimation.cs | 2 - .../AttachmentTools/AttachmentTools.cs | 7 ++ .../SkeletonUtilityEyeConstraint.cs | 13 +-- .../SkeletonUtilityGroundConstraint.cs | 4 +- .../SkeletonUtility/SkeletonUtility.cs | 97 +++++++++---------- .../SkeletonUtility/SkeletonUtilityBone.cs | 32 +++--- .../SkeletonUtilityConstraint.cs | 14 ++- 13 files changed, 126 insertions(+), 139 deletions(-) diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineInspectorUtility.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineInspectorUtility.cs index d1cdcc0cd..933bd0852 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineInspectorUtility.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineInspectorUtility.cs @@ -341,12 +341,6 @@ namespace Spine.Unity.Editor { public SerializedSortingProperties (Renderer r) : this(new SerializedObject(r)) {} public SerializedSortingProperties (Object[] renderers) : this(new SerializedObject(renderers)) {} - /// - /// Initializes a new instance of the - /// struct. - /// - /// SerializedObject of the renderer. Use - /// to easily generate this. public SerializedSortingProperties (SerializedObject rendererSerializedObject) { renderer = rendererSerializedObject; sortingLayerID = renderer.FindProperty("m_SortingLayerID"); diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/SkeletonUtility/Editor/SkeletonUtilityBoneInspector.cs b/spine-unity/Assets/Spine/Editor/spine-unity/SkeletonUtility/Editor/SkeletonUtilityBoneInspector.cs index de58f122b..e1b798f52 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/SkeletonUtility/Editor/SkeletonUtilityBoneInspector.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/SkeletonUtility/Editor/SkeletonUtilityBoneInspector.cs @@ -53,7 +53,6 @@ namespace Spine.Unity.Editor { bool canCreateHingeChain = false; Dictionary> boundingBoxTable = new Dictionary>(); - //string currentSkinName = ""; void OnEnable () { mode = this.serializedObject.FindProperty("mode"); @@ -81,7 +80,6 @@ namespace Spine.Unity.Editor { if (skeleton.Skin == null) skin = skeleton.Data.DefaultSkin; - //currentSkinName = skin.Name; for(int i = 0; i < slotCount; i++){ Slot slot = skeletonUtility.skeletonRenderer.skeleton.Slots.Items[i]; if (slot.Bone == utilityBone.bone) { @@ -103,7 +101,7 @@ namespace Spine.Unity.Editor { void EvaluateFlags () { utilityBone = (SkeletonUtilityBone)target; - skeletonUtility = utilityBone.skeletonUtility; + skeletonUtility = utilityBone.hierarchy; if (Selection.objects.Length == 1) { containsFollows = utilityBone.mode == SkeletonUtilityBone.Mode.Follow; @@ -146,7 +144,7 @@ namespace Spine.Unity.Editor { using (new GUILayout.HorizontalScope()) { EditorGUILayout.PrefixLabel("Bone"); if (GUILayout.Button(str, EditorStyles.popup)) { - BoneSelectorContextMenu(str, ((SkeletonUtilityBone)target).skeletonUtility.skeletonRenderer.skeleton.Bones, "", TargetBoneSelected); + BoneSelectorContextMenu(str, ((SkeletonUtilityBone)target).hierarchy.skeletonRenderer.skeleton.Bones, "", TargetBoneSelected); } } } @@ -166,7 +164,7 @@ namespace Spine.Unity.Editor { using (new GUILayout.HorizontalScope()) { EditorGUILayout.Space(); using (new EditorGUI.DisabledGroupScope(multiObject || !utilityBone.valid || utilityBone.bone == null || utilityBone.bone.Children.Count == 0)) { - if (GUILayout.Button(SpineInspectorUtility.TempContent("Add Child", Icons.bone), GUILayout.MinWidth(120), GUILayout.Height(24))) + if (GUILayout.Button(SpineInspectorUtility.TempContent("Add Child Bone", Icons.bone), GUILayout.MinWidth(120), GUILayout.Height(24))) BoneSelectorContextMenu("", utilityBone.bone.Children, "", SpawnChildBoneSelected); } using (new EditorGUI.DisabledGroupScope(multiObject || !utilityBone.valid || utilityBone.bone == null || containsOverrides)) { @@ -260,12 +258,12 @@ namespace Spine.Unity.Editor { GameObject go = skeletonUtility.SpawnBoneRecursively(bone, utilityBone.transform, utilityBone.mode, utilityBone.position, utilityBone.rotation, utilityBone.scale); SkeletonUtilityBone[] newUtilityBones = go.GetComponentsInChildren(); foreach (SkeletonUtilityBone utilBone in newUtilityBones) - SkeletonUtilityInspector.AttachIcon(utilBone); + SkeletonGameObjectsInspector.AttachIcon(utilBone); } } else { var bone = (Bone)obj; GameObject go = skeletonUtility.SpawnBone(bone, utilityBone.transform, utilityBone.mode, utilityBone.position, utilityBone.rotation, utilityBone.scale); - SkeletonUtilityInspector.AttachIcon(go.GetComponent()); + SkeletonGameObjectsInspector.AttachIcon(go.GetComponent()); Selection.activeGameObject = go; EditorGUIUtility.PingObject(go); } @@ -274,7 +272,7 @@ namespace Spine.Unity.Editor { void SpawnOverride () { GameObject go = skeletonUtility.SpawnBone(utilityBone.bone, utilityBone.transform.parent, SkeletonUtilityBone.Mode.Override, utilityBone.position, utilityBone.rotation, utilityBone.scale); go.name = go.name + " [Override]"; - SkeletonUtilityInspector.AttachIcon(go.GetComponent()); + SkeletonGameObjectsInspector.AttachIcon(go.GetComponent()); Selection.activeGameObject = go; EditorGUIUtility.PingObject(go); } diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/SkeletonUtility/Editor/SkeletonUtilityInspector.cs b/spine-unity/Assets/Spine/Editor/spine-unity/SkeletonUtility/Editor/SkeletonUtilityInspector.cs index 218c75303..4ccc85a6e 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/SkeletonUtility/Editor/SkeletonUtilityInspector.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/SkeletonUtility/Editor/SkeletonUtilityInspector.cs @@ -41,18 +41,17 @@ namespace Spine.Unity.Editor { using Icons = SpineEditorUtilities.Icons; [CustomEditor(typeof(SkeletonUtility))] - public class SkeletonUtilityInspector : UnityEditor.Editor { + public class SkeletonGameObjectsInspector : UnityEditor.Editor { - SkeletonUtility skeletonUtility; + SkeletonUtility skeletonGameObjects; Skeleton skeleton; SkeletonRenderer skeletonRenderer; bool isPrefab; - - GUIContent SpawnHierarchyButtonLabel = new GUIContent("Spawn Hierarchy", Icons.skeleton); + readonly GUIContent SpawnHierarchyButtonLabel = new GUIContent("Spawn Hierarchy", Icons.skeleton); void OnEnable () { - skeletonUtility = (SkeletonUtility)target; - skeletonRenderer = skeletonUtility.GetComponent(); + skeletonGameObjects = (SkeletonUtility)target; + skeletonRenderer = skeletonGameObjects.GetComponent(); skeleton = skeletonRenderer.Skeleton; if (skeleton == null) { @@ -77,9 +76,13 @@ namespace Spine.Unity.Editor { return; } - skeletonUtility.boneRoot = (Transform)EditorGUILayout.ObjectField("Bone Root", skeletonUtility.boneRoot, typeof(Transform), true); + EditorGUILayout.PropertyField(serializedObject.FindProperty("boneRoot"), SpineInspectorUtility.TempContent("Skeleton Root")); + + bool hasRootBone = skeletonGameObjects.boneRoot != null; + + if (!hasRootBone) + EditorGUILayout.HelpBox("No hierarchy found. Use Spawn Hierarchy to generate GameObjects for bones.", MessageType.Info); - bool hasRootBone = skeletonUtility.boneRoot != null; using (new EditorGUI.DisabledGroupScope(hasRootBone)) { if (SpineInspectorUtility.LargeCenteredButton(SpawnHierarchyButtonLabel)) SpawnHierarchyContextMenu(); @@ -87,37 +90,37 @@ namespace Spine.Unity.Editor { if (hasRootBone) { if (SpineInspectorUtility.CenteredButton(new GUIContent("Remove Hierarchy"))) { - Undo.RegisterCompleteObjectUndo(skeletonUtility, "Remove Hierarchy"); - Undo.DestroyObjectImmediate(skeletonUtility.boneRoot.gameObject); - skeletonUtility.boneRoot = null; + Undo.RegisterCompleteObjectUndo(skeletonGameObjects, "Remove Hierarchy"); + Undo.DestroyObjectImmediate(skeletonGameObjects.boneRoot.gameObject); + skeletonGameObjects.boneRoot = null; } } } void SpawnHierarchyContextMenu () { - GenericMenu menu = new GenericMenu(); + var menu = new GenericMenu(); - menu.AddItem(new GUIContent("Follow"), false, SpawnFollowHierarchy); + menu.AddItem(new GUIContent("Follow all bones"), false, SpawnFollowHierarchy); menu.AddItem(new GUIContent("Follow (Root Only)"), false, SpawnFollowHierarchyRootOnly); menu.AddSeparator(""); - menu.AddItem(new GUIContent("Override"), false, SpawnOverrideHierarchy); + menu.AddItem(new GUIContent("Override all bones"), false, SpawnOverrideHierarchy); menu.AddItem(new GUIContent("Override (Root Only)"), false, SpawnOverrideHierarchyRootOnly); menu.ShowAsContext(); } - public static void AttachIcon (SkeletonUtilityBone utilityBone) { - Skeleton skeleton = utilityBone.skeletonUtility.skeletonRenderer.skeleton; - Texture2D icon = utilityBone.bone.Data.Length == 0 ? Icons.nullBone : Icons.boneNib; + public static void AttachIcon (SkeletonUtilityBone boneComponent) { + Skeleton skeleton = boneComponent.hierarchy.skeletonRenderer.skeleton; + Texture2D icon = boneComponent.bone.Data.Length == 0 ? Icons.nullBone : Icons.boneNib; foreach (IkConstraint c in skeleton.IkConstraints) - if (c.Target == utilityBone.bone) { + if (c.Target == boneComponent.bone) { icon = Icons.constraintNib; break; } typeof(EditorGUIUtility).InvokeMember("SetIconForObject", BindingFlags.InvokeMethod | BindingFlags.Static | BindingFlags.NonPublic, null, null, new object[2] { - utilityBone.gameObject, + boneComponent.gameObject, icon }); } @@ -131,23 +134,23 @@ namespace Spine.Unity.Editor { } void SpawnFollowHierarchy () { - Selection.activeGameObject = skeletonUtility.SpawnHierarchy(SkeletonUtilityBone.Mode.Follow, true, true, true); - AttachIconsToChildren(skeletonUtility.boneRoot); + Selection.activeGameObject = skeletonGameObjects.SpawnHierarchy(SkeletonUtilityBone.Mode.Follow, true, true, true); + AttachIconsToChildren(skeletonGameObjects.boneRoot); } void SpawnFollowHierarchyRootOnly () { - Selection.activeGameObject = skeletonUtility.SpawnRoot(SkeletonUtilityBone.Mode.Follow, true, true, true); - AttachIconsToChildren(skeletonUtility.boneRoot); + Selection.activeGameObject = skeletonGameObjects.SpawnRoot(SkeletonUtilityBone.Mode.Follow, true, true, true); + AttachIconsToChildren(skeletonGameObjects.boneRoot); } void SpawnOverrideHierarchy () { - Selection.activeGameObject = skeletonUtility.SpawnHierarchy(SkeletonUtilityBone.Mode.Override, true, true, true); - AttachIconsToChildren(skeletonUtility.boneRoot); + Selection.activeGameObject = skeletonGameObjects.SpawnHierarchy(SkeletonUtilityBone.Mode.Override, true, true, true); + AttachIconsToChildren(skeletonGameObjects.boneRoot); } void SpawnOverrideHierarchyRootOnly () { - Selection.activeGameObject = skeletonUtility.SpawnRoot(SkeletonUtilityBone.Mode.Override, true, true, true); - AttachIconsToChildren(skeletonUtility.boneRoot); + Selection.activeGameObject = skeletonGameObjects.SpawnRoot(SkeletonUtilityBone.Mode.Override, true, true, true); + AttachIconsToChildren(skeletonGameObjects.boneRoot); } } diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/SkeletonDataAsset.cs.meta b/spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/SkeletonDataAsset.cs.meta index b5162ad53..941ef0f6f 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/SkeletonDataAsset.cs.meta +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/SkeletonDataAsset.cs.meta @@ -1,8 +1,18 @@ fileFormatVersion: 2 guid: f1b3b4b945939a54ea0b23d3396115fb +timeCreated: 1536403985 +licenseType: Pro MonoImporter: serializedVersion: 2 - defaultReferences: [] + defaultReferences: + - multiplyMaterialTemplate: {fileID: 2100000, guid: 53bf0ab317d032d418cf1252d68f51df, + type: 2} + - screenMaterialTemplate: {fileID: 2100000, guid: 73f0f46d3177c614baf0fa48d646a9be, + type: 2} + - additiveMaterialTemplate: {fileID: 2100000, guid: 4deba332d47209e4780b3c5fcf0e3745, + type: 2} + - skeletonJSON: {instanceID: 0} + - controller: {instanceID: 0} executionOrder: 0 icon: {fileID: 2800000, guid: 68defdbc95b30a74a9ad396bfc9a2277, type: 3} userData: diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/BoneFollower.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/BoneFollower.cs index c462b262c..aa33634c8 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/BoneFollower.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/BoneFollower.cs @@ -65,10 +65,8 @@ namespace Spine.Unity { #endregion [NonSerialized] public bool valid; - /// - /// The bone. - /// [NonSerialized] public Bone bone; + Transform skeletonTransform; bool skeletonTransformIsParent; diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs index 17eacbfc8..6e70f270c 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs @@ -58,7 +58,6 @@ namespace Spine.Unity { [System.NonSerialized] public readonly List separatorSlots = new List(); [Range(-0.1f, 0f)] public float zSpacing; - //public bool renderMeshes = true; public bool useClipping = true; public bool immutableTriangles = false; public bool pmaVertexColors = true; @@ -311,7 +310,9 @@ namespace Spine.Unity { // STEP 3. Move the mesh data into a UnityEngine.Mesh =========================================================================== var currentMesh = currentSmartMesh.mesh; meshGenerator.FillVertexData(currentMesh); + rendererBuffers.UpdateSharedMaterials(workingSubmeshInstructions); + if (updateTriangles) { // Check if the triangles should also be updated. meshGenerator.FillTriangles(currentMesh); meshRenderer.sharedMaterials = rendererBuffers.GetUpdatedSharedMaterialsArray(); diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/ISkeletonAnimation.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/ISkeletonAnimation.cs index d1ab2ffcb..acd085d7a 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/ISkeletonAnimation.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/ISkeletonAnimation.cs @@ -36,8 +36,6 @@ namespace Spine.Unity { event UpdateBonesDelegate UpdateLocal; event UpdateBonesDelegate UpdateWorld; event UpdateBonesDelegate UpdateComplete; - - //void LateUpdate (); Skeleton Skeleton { get; } } diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/AttachmentTools/AttachmentTools.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/AttachmentTools/AttachmentTools.cs index 926efbe32..a6d4a3932 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/AttachmentTools/AttachmentTools.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/AttachmentTools/AttachmentTools.cs @@ -805,6 +805,12 @@ namespace Spine.Unity.Modules.AttachmentTools { skin.AddAttachment(slotIndex, keyName, attachment); } + /// Adds skin items from another skin. For items that already exist, the previous values are replaced. + public static void AddAttachments (this Skin skin, Skin otherSkin) { + if (otherSkin == null) return; + otherSkin.CopyTo(skin, true, false); + } + /// Gets an attachment from the skin for the specified slot index and name. public static Attachment GetAttachment (this Skin skin, string slotName, string keyName, Skeleton skeleton) { int slotIndex = skeleton.FindSlotIndex(slotName); @@ -835,6 +841,7 @@ namespace Spine.Unity.Modules.AttachmentTools { skin.Attachments.Clear(); } + //[System.Obsolete] public static void Append (this Skin destination, Skin source) { source.CopyTo(destination, true, false); } diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/SkeletonUtility Modules/SkeletonUtilityEyeConstraint.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/SkeletonUtility Modules/SkeletonUtilityEyeConstraint.cs index 9b2effb1a..52fb39193 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/SkeletonUtility Modules/SkeletonUtilityEyeConstraint.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/SkeletonUtility Modules/SkeletonUtilityEyeConstraint.cs @@ -42,9 +42,7 @@ namespace Spine.Unity.Modules { Vector3 centerPoint; protected override void OnEnable () { - if (!Application.isPlaying) - return; - + if (!Application.isPlaying) return; base.OnEnable(); Bounds centerBounds = new Bounds(eyes[0].localPosition, Vector3.zero); @@ -58,19 +56,14 @@ namespace Spine.Unity.Modules { } protected override void OnDisable () { - if (!Application.isPlaying) - return; - + if (!Application.isPlaying) return; base.OnDisable(); } public override void DoUpdate () { - - if (target != null) - targetPosition = target.position; + if (target != null) targetPosition = target.position; Vector3 goal = targetPosition; - Vector3 center = transform.TransformPoint(centerPoint); Vector3 dir = goal - center; diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/SkeletonUtility Modules/SkeletonUtilityGroundConstraint.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/SkeletonUtility Modules/SkeletonUtilityGroundConstraint.cs index d8ab190bf..d88c9af78 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/SkeletonUtility Modules/SkeletonUtilityGroundConstraint.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/SkeletonUtility Modules/SkeletonUtilityGroundConstraint.cs @@ -105,8 +105,8 @@ namespace Spine.Unity.Modules { v.y = Mathf.Clamp(v.y, Mathf.Min(lastHitY, hitY), float.MaxValue); transform.position = v; - utilBone.bone.X = transform.localPosition.x; - utilBone.bone.Y = transform.localPosition.y; + bone.bone.X = transform.localPosition.x; + bone.bone.Y = transform.localPosition.y; lastHitY = hitY; } diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/SkeletonUtility/SkeletonUtility.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/SkeletonUtility/SkeletonUtility.cs index bcbf4cff3..0fab0f8be 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/SkeletonUtility/SkeletonUtility.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/SkeletonUtility/SkeletonUtility.cs @@ -37,7 +37,7 @@ using Spine; namespace Spine.Unity { [RequireComponent(typeof(ISkeletonAnimation))] [ExecuteInEditMode] - public class SkeletonUtility : MonoBehaviour { + public sealed class SkeletonUtility : MonoBehaviour { #region BoundingBoxAttachment public static PolygonCollider2D AddBoundingBoxGameObject (Skeleton skeleton, string skinName, string slotName, string attachmentName, Transform parent, bool isTrigger = true) { @@ -122,23 +122,19 @@ namespace Spine.Unity { void Update () { var skeleton = skeletonRenderer.skeleton; - if (boneRoot != null && skeleton != null) { + if (skeleton != null && boneRoot != null) { boneRoot.localScale = new Vector3(skeleton.scaleX, skeleton.scaleY, 1f); } } - [HideInInspector] - public SkeletonRenderer skeletonRenderer; - [HideInInspector] - public ISkeletonAnimation skeletonAnimation; - [System.NonSerialized] - public List utilityBones = new List(); - [System.NonSerialized] - public List utilityConstraints = new List(); + [HideInInspector] public SkeletonRenderer skeletonRenderer; + [HideInInspector] public ISkeletonAnimation skeletonAnimation; + [System.NonSerialized] public List boneComponents = new List(); + [System.NonSerialized] public List constraintComponents = new List(); - protected bool hasTransformBones; - protected bool hasUtilityConstraints; - protected bool needToReprocessBones; + bool hasOverrideBones; + bool hasConstraints; + bool needToReprocessBones; void OnEnable () { if (skeletonRenderer == null) { @@ -176,36 +172,34 @@ namespace Spine.Unity { } void HandleRendererReset (SkeletonRenderer r) { - if (OnReset != null) - OnReset(); - + if (OnReset != null) OnReset(); CollectBones(); } public void RegisterBone (SkeletonUtilityBone bone) { - if (utilityBones.Contains(bone)) + if (boneComponents.Contains(bone)) { return; - else { - utilityBones.Add(bone); + } else { + boneComponents.Add(bone); needToReprocessBones = true; } } public void UnregisterBone (SkeletonUtilityBone bone) { - utilityBones.Remove(bone); + boneComponents.Remove(bone); } public void RegisterConstraint (SkeletonUtilityConstraint constraint) { - if (utilityConstraints.Contains(constraint)) + if (constraintComponents.Contains(constraint)) return; else { - utilityConstraints.Add(constraint); + constraintComponents.Add(constraint); needToReprocessBones = true; } } public void UnregisterConstraint (SkeletonUtilityConstraint constraint) { - utilityConstraints.Remove(constraint); + constraintComponents.Remove(constraint); } public void CollectBones () { @@ -222,31 +216,31 @@ namespace Spine.Unity { for (int i = 0, n = transformConstraints.Count; i < n; i++) constraintTargets.Add(transformConstraints.Items[i].target); - var utilityBones = this.utilityBones; - for (int i = 0, n = utilityBones.Count; i < n; i++) { - var b = utilityBones[i]; + var boneComponents = this.boneComponents; + for (int i = 0, n = boneComponents.Count; i < n; i++) { + var b = boneComponents[i]; if (b.bone == null) continue; - hasTransformBones |= (b.mode == SkeletonUtilityBone.Mode.Override); - hasUtilityConstraints |= constraintTargets.Contains(b.bone); + hasOverrideBones |= (b.mode == SkeletonUtilityBone.Mode.Override); + hasConstraints |= constraintTargets.Contains(b.bone); } - hasUtilityConstraints |= utilityConstraints.Count > 0; + hasConstraints |= constraintComponents.Count > 0; if (skeletonAnimation != null) { skeletonAnimation.UpdateWorld -= UpdateWorld; skeletonAnimation.UpdateComplete -= UpdateComplete; - if (hasTransformBones || hasUtilityConstraints) + if (hasOverrideBones || hasConstraints) skeletonAnimation.UpdateWorld += UpdateWorld; - if (hasUtilityConstraints) + if (hasConstraints) skeletonAnimation.UpdateComplete += UpdateComplete; } needToReprocessBones = false; } else { - utilityBones.Clear(); - utilityConstraints.Clear(); + boneComponents.Clear(); + constraintComponents.Clear(); } } @@ -254,18 +248,18 @@ namespace Spine.Unity { if (needToReprocessBones) CollectBones(); - var utilityBones = this.utilityBones; - if (utilityBones == null) return; - for (int i = 0, n = utilityBones.Count; i < n; i++) - utilityBones[i].transformLerpComplete = false; + var boneComponents = this.boneComponents; + if (boneComponents == null) return; + for (int i = 0, n = boneComponents.Count; i < n; i++) + boneComponents[i].transformLerpComplete = false; UpdateAllBones(SkeletonUtilityBone.UpdatePhase.Local); } void UpdateWorld (ISkeletonAnimation anim) { UpdateAllBones(SkeletonUtilityBone.UpdatePhase.World); - for (int i = 0, n = utilityConstraints.Count; i < n; i++) - utilityConstraints[i].DoUpdate(); + for (int i = 0, n = constraintComponents.Count; i < n; i++) + constraintComponents[i].DoUpdate(); } void UpdateComplete (ISkeletonAnimation anim) { @@ -276,17 +270,17 @@ namespace Spine.Unity { if (boneRoot == null) CollectBones(); - var utilityBones = this.utilityBones; - if (utilityBones == null) return; - for (int i = 0, n = utilityBones.Count; i < n; i++) - utilityBones[i].DoUpdate(phase); + var boneComponents = this.boneComponents; + if (boneComponents == null) return; + for (int i = 0, n = boneComponents.Count; i < n; i++) + boneComponents[i].DoUpdate(phase); } public Transform GetBoneRoot () { if (boneRoot != null) return boneRoot; - boneRoot = new GameObject("SkeletonUtility-Root").transform; + boneRoot = new GameObject("SkeletonUtility-SkeletonRoot").transform; boneRoot.parent = transform; boneRoot.localPosition = Vector3.zero; boneRoot.localRotation = Quaternion.identity; @@ -326,10 +320,11 @@ namespace Spine.Unity { public GameObject SpawnBone (Bone bone, Transform parent, SkeletonUtilityBone.Mode mode, bool pos, bool rot, bool sca) { GameObject go = new GameObject(bone.Data.Name); - go.transform.parent = parent; + var goTransform = go.transform; + goTransform.parent = parent; SkeletonUtilityBone b = go.AddComponent(); - b.skeletonUtility = this; + b.hierarchy = this; b.position = pos; b.rotation = rot; b.scale = sca; @@ -341,13 +336,9 @@ namespace Spine.Unity { b.valid = true; if (mode == SkeletonUtilityBone.Mode.Override) { - if (rot) - go.transform.localRotation = Quaternion.Euler(0, 0, b.bone.AppliedRotation); - - if (pos) - go.transform.localPosition = new Vector3(b.bone.X, b.bone.Y, 0); - - go.transform.localScale = new Vector3(b.bone.scaleX, b.bone.scaleY, 0); + if (rot) goTransform.localRotation = Quaternion.Euler(0, 0, b.bone.AppliedRotation); + if (pos) goTransform.localPosition = new Vector3(b.bone.X, b.bone.Y, 0); + goTransform.localScale = new Vector3(b.bone.scaleX, b.bone.scaleY, 0); } return go; diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/SkeletonUtility/SkeletonUtilityBone.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/SkeletonUtility/SkeletonUtilityBone.cs index b80c59672..172ef16e2 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/SkeletonUtility/SkeletonUtilityBone.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/SkeletonUtility/SkeletonUtilityBone.cs @@ -28,15 +28,13 @@ * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -// Contributed by: Mitch Thompson - using UnityEngine; using Spine; namespace Spine.Unity { /// Sets a GameObject's transform to match a bone on a Spine skeleton. [ExecuteInEditMode] - [AddComponentMenu("Spine/SkeletonUtilityBone")] + [AddComponentMenu("Spine/SkeletonGameObjectsBone")] public class SkeletonUtilityBone : MonoBehaviour { public enum Mode { Follow, @@ -59,7 +57,7 @@ namespace Spine.Unity { public float overrideAlpha = 1; #endregion - [System.NonSerialized] public SkeletonUtility skeletonUtility; + [System.NonSerialized] public SkeletonUtility hierarchy; [System.NonSerialized] public Bone bone; [System.NonSerialized] public bool transformLerpComplete; [System.NonSerialized] public bool valid; @@ -71,23 +69,21 @@ namespace Spine.Unity { public void Reset () { bone = null; cachedTransform = transform; - valid = skeletonUtility != null && skeletonUtility.skeletonRenderer != null && skeletonUtility.skeletonRenderer.valid; + valid = hierarchy != null && hierarchy.skeletonRenderer != null && hierarchy.skeletonRenderer.valid; if (!valid) return; - skeletonTransform = skeletonUtility.transform; - skeletonUtility.OnReset -= HandleOnReset; - skeletonUtility.OnReset += HandleOnReset; + skeletonTransform = hierarchy.transform; + hierarchy.OnReset -= HandleOnReset; + hierarchy.OnReset += HandleOnReset; DoUpdate(UpdatePhase.Local); } void OnEnable () { - skeletonUtility = transform.GetComponentInParent(); + hierarchy = transform.GetComponentInParent(); + if (hierarchy == null) return; - if (skeletonUtility == null) - return; - - skeletonUtility.RegisterBone(this); - skeletonUtility.OnReset += HandleOnReset; + hierarchy.RegisterBone(this); + hierarchy.OnReset += HandleOnReset; } void HandleOnReset () { @@ -95,9 +91,9 @@ namespace Spine.Unity { } void OnDisable () { - if (skeletonUtility != null) { - skeletonUtility.OnReset -= HandleOnReset; - skeletonUtility.UnregisterBone(this); + if (hierarchy != null) { + hierarchy.OnReset -= HandleOnReset; + hierarchy.UnregisterBone(this); } } @@ -107,7 +103,7 @@ namespace Spine.Unity { return; } - var skeleton = skeletonUtility.skeletonRenderer.skeleton; + var skeleton = hierarchy.skeletonRenderer.skeleton; if (bone == null) { if (string.IsNullOrEmpty(boneName)) return; diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/SkeletonUtility/SkeletonUtilityConstraint.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/SkeletonUtility/SkeletonUtilityConstraint.cs index 0caefadf3..49fcfc265 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/SkeletonUtility/SkeletonUtilityConstraint.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/SkeletonUtility/SkeletonUtilityConstraint.cs @@ -28,25 +28,23 @@ * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -// Contributed by: Mitch Thompson - using UnityEngine; namespace Spine.Unity { [RequireComponent(typeof(SkeletonUtilityBone)), ExecuteInEditMode] public abstract class SkeletonUtilityConstraint : MonoBehaviour { - protected SkeletonUtilityBone utilBone; - protected SkeletonUtility skeletonUtility; + protected SkeletonUtilityBone bone; + protected SkeletonUtility hierarchy; protected virtual void OnEnable () { - utilBone = GetComponent(); - skeletonUtility = transform.GetComponentInParent(); - skeletonUtility.RegisterConstraint(this); + bone = GetComponent(); + hierarchy = transform.GetComponentInParent(); + hierarchy.RegisterConstraint(this); } protected virtual void OnDisable () { - skeletonUtility.UnregisterConstraint(this); + hierarchy.UnregisterConstraint(this); } public abstract void DoUpdate (); From 88c6c0e4059f39c1fa1b8b4c42cb422d01a0a254 Mon Sep 17 00:00:00 2001 From: pharan Date: Tue, 9 Oct 2018 07:07:27 +0800 Subject: [PATCH 8/9] [monogame] Fix example code. --- spine-monogame/example/ExampleGame.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spine-monogame/example/ExampleGame.cs b/spine-monogame/example/ExampleGame.cs index 25e55de76..ced2ede1e 100644 --- a/spine-monogame/example/ExampleGame.cs +++ b/spine-monogame/example/ExampleGame.cs @@ -98,6 +98,8 @@ namespace Spine { state = new AnimationState(stateData); if (name == "spineboy-ess") { + skeleton.SetAttachment("head-bb", "head"); // Activate the head BoundingBoxAttachment. + stateData.SetMix("run", "jump", 0.2f); stateData.SetMix("jump", "run", 0.4f); From cdc37a5554c0ba0ad8d186d88d19727e7c70b630 Mon Sep 17 00:00:00 2001 From: pharan Date: Tue, 9 Oct 2018 07:09:40 +0800 Subject: [PATCH 9/9] [xna] Fix example code. --- spine-xna/example/src/ExampleGame.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spine-xna/example/src/ExampleGame.cs b/spine-xna/example/src/ExampleGame.cs index a7b251457..f5d0db7c9 100644 --- a/spine-xna/example/src/ExampleGame.cs +++ b/spine-xna/example/src/ExampleGame.cs @@ -119,6 +119,8 @@ namespace Spine { state = new AnimationState(stateData); if (name == "spineboy-ess") { + skeleton.SetAttachment("head-bb", "head"); + stateData.SetMix("run", "jump", 0.2f); stateData.SetMix("jump", "run", 0.4f);