diff --git a/spine-unity/Assets/spine-unity/Modules/BoundingBoxFollower/BoundingBoxFollower.cs b/spine-unity/Assets/spine-unity/Modules/BoundingBoxFollower/BoundingBoxFollower.cs index 0573b5ace..e089470b2 100644 --- a/spine-unity/Assets/spine-unity/Modules/BoundingBoxFollower/BoundingBoxFollower.cs +++ b/spine-unity/Assets/spine-unity/Modules/BoundingBoxFollower/BoundingBoxFollower.cs @@ -32,28 +32,30 @@ using UnityEngine; using System.Collections.Generic; namespace Spine.Unity { + [ExecuteInEditMode] public class BoundingBoxFollower : MonoBehaviour { - + #region Inspector public SkeletonRenderer skeletonRenderer; - [SpineSlot(dataField: "skeletonRenderer", containsBoundingBoxes: true)] public string slotName; + #endregion Slot slot; BoundingBoxAttachment currentAttachment; - PolygonCollider2D currentCollider; string currentAttachmentName; + PolygonCollider2D currentCollider; + bool valid = false; bool hasReset; - public Dictionary colliderTable = new Dictionary(); - public Dictionary attachmentNameTable = new Dictionary(); + public readonly Dictionary colliderTable = new Dictionary(); + public readonly Dictionary attachmentNameTable = new Dictionary(); - public string CurrentAttachmentName { get { return currentAttachmentName; } } - public BoundingBoxAttachment CurrentAttachment { get { return currentAttachment; } } - public PolygonCollider2D CurrentCollider { get { return currentCollider; } } public Slot Slot { get { return slot; } } + public BoundingBoxAttachment CurrentAttachment { get { return currentAttachment; } } + public string CurrentAttachmentName { get { return currentAttachmentName; } } + public PolygonCollider2D CurrentCollider { get { return currentCollider; } } void OnEnable () { ClearColliders(); @@ -62,74 +64,91 @@ namespace Spine.Unity { skeletonRenderer = GetComponentInParent(); if (skeletonRenderer != null) { - skeletonRenderer.OnRebuild -= HandleReset; - skeletonRenderer.OnRebuild += HandleReset; + skeletonRenderer.OnRebuild -= HandleRebuild; + skeletonRenderer.OnRebuild += HandleRebuild; if (hasReset) - HandleReset(skeletonRenderer); + HandleRebuild(skeletonRenderer); } } void OnDisable () { - skeletonRenderer.OnRebuild -= HandleReset; + skeletonRenderer.OnRebuild -= HandleRebuild; } void Start () { if (!hasReset && skeletonRenderer != null) - HandleReset(skeletonRenderer); + HandleRebuild(skeletonRenderer); } - public void HandleReset (SkeletonRenderer renderer) { + public void HandleRebuild (SkeletonRenderer renderer) { if (string.IsNullOrEmpty(slotName)) return; hasReset = true; - ClearColliders(); colliderTable.Clear(); if (skeletonRenderer.skeleton == null) { - skeletonRenderer.OnRebuild -= HandleReset; + skeletonRenderer.OnRebuild -= HandleRebuild; skeletonRenderer.Initialize(false); - skeletonRenderer.OnRebuild += HandleReset; + skeletonRenderer.OnRebuild += HandleRebuild; } var skeleton = skeletonRenderer.skeleton; slot = skeleton.FindSlot(slotName); int slotIndex = skeleton.FindSlotIndex(slotName); - foreach (var skin in skeleton.Data.Skins) { - var attachmentNames = new List(); - skin.FindNamesForSlot(slotIndex, attachmentNames); + if (this.gameObject.activeInHierarchy) { + foreach (var skin in skeleton.Data.Skins) { + var attachmentNames = new List(); + skin.FindNamesForSlot(slotIndex, attachmentNames); - foreach (var attachmentName in attachmentNames) { - var attachment = skin.GetAttachment(slotIndex, attachmentName); - var boundingBoxAttachment = attachment as BoundingBoxAttachment; - if (boundingBoxAttachment != null) { - var bbCollider = SkeletonUtility.AddBoundingBoxAsComponent(boundingBoxAttachment, gameObject, true); - bbCollider.enabled = false; - bbCollider.hideFlags = HideFlags.HideInInspector; - colliderTable.Add(boundingBoxAttachment, bbCollider); - attachmentNameTable.Add(boundingBoxAttachment, attachmentName); + foreach (var attachmentName in attachmentNames) { + var attachment = skin.GetAttachment(slotIndex, attachmentName); + var boundingBoxAttachment = attachment as BoundingBoxAttachment; + if (boundingBoxAttachment != null) { + var bbCollider = SkeletonUtility.AddBoundingBoxAsComponent(boundingBoxAttachment, gameObject, true); + bbCollider.enabled = false; + bbCollider.hideFlags = HideFlags.NotEditable; + colliderTable.Add(boundingBoxAttachment, bbCollider); + attachmentNameTable.Add(boundingBoxAttachment, attachmentName); + } } } } +#if UNITY_EDITOR valid = colliderTable.Count != 0; - - if (!valid) - Debug.LogWarning("Bounding Box Follower not valid! Slot [" + slotName + "] does not contain any Bounding Box Attachments!"); + if (!valid) { + if (this.gameObject.activeInHierarchy) + Debug.LogWarning("Bounding Box Follower not valid! Slot [" + slotName + "] does not contain any Bounding Box Attachments!"); + else + Debug.LogWarning("Bounding Box Follower tried to rebuild as a prefab."); + } +#endif + } void ClearColliders () { var colliders = GetComponents(); + if (colliders.Length == 0) return; + +#if UNITY_EDITOR if (Application.isPlaying) { - foreach (var c in colliders) - Destroy(c); + foreach (var c in colliders) { + if (c != null) + Destroy(c); + } } else { foreach (var c in colliders) DestroyImmediate(c); } +#else + foreach (var c in colliders) + if (c != null) + Destroy(c); +#endif colliderTable.Clear(); attachmentNameTable.Clear(); @@ -139,21 +158,19 @@ namespace Spine.Unity { if (!skeletonRenderer.valid) return; - if (slot != null) { - if (slot.Attachment != currentAttachment) - SetCurrent((BoundingBoxAttachment)slot.Attachment); - } + if (slot != null && slot.Attachment != currentAttachment) + SetCurrent((BoundingBoxAttachment)slot.Attachment); } void SetCurrent (BoundingBoxAttachment attachment) { - if (currentCollider) + if (currentCollider != null) currentCollider.enabled = false; - if (attachment != null) { + if (attachment == null) { + currentCollider = null; + } else { currentCollider = colliderTable[attachment]; currentCollider.enabled = true; - } else { - currentCollider = null; } currentAttachment = attachment; diff --git a/spine-unity/Assets/spine-unity/Modules/BoundingBoxFollower/Editor/BoundingBoxFollowerInspector.cs b/spine-unity/Assets/spine-unity/Modules/BoundingBoxFollower/Editor/BoundingBoxFollowerInspector.cs index 216fc2f81..f4f758802 100644 --- a/spine-unity/Assets/spine-unity/Modules/BoundingBoxFollower/Editor/BoundingBoxFollowerInspector.cs +++ b/spine-unity/Assets/spine-unity/Modules/BoundingBoxFollower/Editor/BoundingBoxFollowerInspector.cs @@ -31,7 +31,6 @@ using UnityEngine; using UnityEditor; -using System.Collections; namespace Spine.Unity.Editor { @@ -39,7 +38,8 @@ namespace Spine.Unity.Editor { public class BoundingBoxFollowerInspector : UnityEditor.Editor { SerializedProperty skeletonRenderer, slotName; BoundingBoxFollower follower; - bool needToReset = false; + bool rebuildRequired = false; + bool addBoneFollower = false; void OnEnable () { skeletonRenderer = serializedObject.FindProperty("skeletonRenderer"); @@ -48,41 +48,63 @@ namespace Spine.Unity.Editor { } public override void OnInspectorGUI () { - if (needToReset) { - follower.HandleReset(null); - needToReset = false; + bool isInspectingPrefab = (PrefabUtility.GetPrefabType(target) == PrefabType.Prefab); + bool repaintEvent = UnityEngine.Event.current.type == EventType.Repaint; + + if (rebuildRequired) { + follower.HandleRebuild(null); + rebuildRequired = false; } + EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(skeletonRenderer); EditorGUILayout.PropertyField(slotName, new GUIContent("Slot")); - - if (EditorGUI.EndChangeCheck()){ + if (EditorGUI.EndChangeCheck()) { serializedObject.ApplyModifiedProperties(); - needToReset = true; + if (!isInspectingPrefab) + rebuildRequired = true; } - bool hasBone = follower.GetComponent() != null; - - EditorGUI.BeginDisabledGroup(hasBone || follower.Slot == null); - { + bool hasBoneFollower = follower.GetComponent() != null; + using (new EditorGUI.DisabledGroupScope(hasBoneFollower || follower.Slot == null)) { if (GUILayout.Button(new GUIContent("Add Bone Follower", SpineEditorUtilities.Icons.bone))) { - var boneFollower = follower.gameObject.AddComponent(); - boneFollower.boneName = follower.Slot.Data.BoneData.Name; + addBoneFollower = true; } } - EditorGUI.EndDisabledGroup(); + if (isInspectingPrefab) { + follower.colliderTable.Clear(); + follower.attachmentNameTable.Clear(); + EditorGUILayout.HelpBox("BoundingBoxAttachments cannot be previewed in prefabs.", MessageType.Info); + // How do you prevent components from being saved into the prefab? No such HideFlag. DontSaveInEditor | DontSaveInBuild does not work. DestroyImmediate does not work. + var collider = follower.GetComponent(); + if (collider != null) Debug.LogWarning("Found BoundingBoxFollower collider components in prefab. These are disposed and regenerated at runtime."); - //GUILayout.Space(20); - GUILayout.Label("Attachment Names", EditorStyles.boldLabel); - foreach (var kp in follower.attachmentNameTable) { - string name = kp.Value; - var collider = follower.colliderTable[kp.Key]; - bool isPlaceholder = name != kp.Key.Name; - collider.enabled = EditorGUILayout.ToggleLeft(new GUIContent(!isPlaceholder ? name : name + " [" + kp.Key.Name + "]", isPlaceholder ? SpineEditorUtilities.Icons.skinPlaceholder : SpineEditorUtilities.Icons.boundingBox), collider.enabled); + } else { + EditorGUILayout.LabelField(string.Format("Attachment Names ({0} PolygonCollider2D)", follower.colliderTable.Count), EditorStyles.boldLabel); + EditorGUI.BeginChangeCheck(); + foreach (var kp in follower.attachmentNameTable) { + string attachmentName = kp.Value; + var collider = follower.colliderTable[kp.Key]; + bool isPlaceholder = attachmentName != kp.Key.Name; + collider.enabled = EditorGUILayout.ToggleLeft(new GUIContent(!isPlaceholder ? attachmentName : attachmentName + " [" + kp.Key.Name + "]", isPlaceholder ? SpineEditorUtilities.Icons.skinPlaceholder : SpineEditorUtilities.Icons.boundingBox), collider.enabled); + } + if (EditorGUI.EndChangeCheck()) { + SceneView.RepaintAll(); + } + + if (!Application.isPlaying) + EditorGUILayout.HelpBox("\nAt runtime, BoundingBoxFollower enables and disables PolygonCollider2Ds based on the currently active attachment in the slot.\n\nCheckboxes in Edit Mode are only for preview. Checkbox states are not saved.\n", MessageType.Info); + } + + if (addBoneFollower && repaintEvent) { + var boneFollower = follower.gameObject.AddComponent(); + boneFollower.boneName = follower.Slot.Data.BoneData.Name; + addBoneFollower = false; } } + } }