mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-03-26 22:49:01 +08:00
[spine-unity] Clarify BoundingBoxFollower behavior in editor. (#630)
This commit is contained in:
parent
e0c2db276f
commit
d6dc425817
@ -32,28 +32,30 @@ using UnityEngine;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Spine.Unity {
|
namespace Spine.Unity {
|
||||||
|
|
||||||
[ExecuteInEditMode]
|
[ExecuteInEditMode]
|
||||||
public class BoundingBoxFollower : MonoBehaviour {
|
public class BoundingBoxFollower : MonoBehaviour {
|
||||||
|
#region Inspector
|
||||||
public SkeletonRenderer skeletonRenderer;
|
public SkeletonRenderer skeletonRenderer;
|
||||||
|
|
||||||
[SpineSlot(dataField: "skeletonRenderer", containsBoundingBoxes: true)]
|
[SpineSlot(dataField: "skeletonRenderer", containsBoundingBoxes: true)]
|
||||||
public string slotName;
|
public string slotName;
|
||||||
|
#endregion
|
||||||
|
|
||||||
Slot slot;
|
Slot slot;
|
||||||
BoundingBoxAttachment currentAttachment;
|
BoundingBoxAttachment currentAttachment;
|
||||||
PolygonCollider2D currentCollider;
|
|
||||||
string currentAttachmentName;
|
string currentAttachmentName;
|
||||||
|
PolygonCollider2D currentCollider;
|
||||||
|
|
||||||
bool valid = false;
|
bool valid = false;
|
||||||
bool hasReset;
|
bool hasReset;
|
||||||
|
|
||||||
public Dictionary<BoundingBoxAttachment, PolygonCollider2D> colliderTable = new Dictionary<BoundingBoxAttachment, PolygonCollider2D>();
|
public readonly Dictionary<BoundingBoxAttachment, PolygonCollider2D> colliderTable = new Dictionary<BoundingBoxAttachment, PolygonCollider2D>();
|
||||||
public Dictionary<BoundingBoxAttachment, string> attachmentNameTable = new Dictionary<BoundingBoxAttachment, string>();
|
public readonly Dictionary<BoundingBoxAttachment, string> attachmentNameTable = new Dictionary<BoundingBoxAttachment, string>();
|
||||||
|
|
||||||
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 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 () {
|
void OnEnable () {
|
||||||
ClearColliders();
|
ClearColliders();
|
||||||
@ -62,74 +64,91 @@ namespace Spine.Unity {
|
|||||||
skeletonRenderer = GetComponentInParent<SkeletonRenderer>();
|
skeletonRenderer = GetComponentInParent<SkeletonRenderer>();
|
||||||
|
|
||||||
if (skeletonRenderer != null) {
|
if (skeletonRenderer != null) {
|
||||||
skeletonRenderer.OnRebuild -= HandleReset;
|
skeletonRenderer.OnRebuild -= HandleRebuild;
|
||||||
skeletonRenderer.OnRebuild += HandleReset;
|
skeletonRenderer.OnRebuild += HandleRebuild;
|
||||||
|
|
||||||
if (hasReset)
|
if (hasReset)
|
||||||
HandleReset(skeletonRenderer);
|
HandleRebuild(skeletonRenderer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnDisable () {
|
void OnDisable () {
|
||||||
skeletonRenderer.OnRebuild -= HandleReset;
|
skeletonRenderer.OnRebuild -= HandleRebuild;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Start () {
|
void Start () {
|
||||||
if (!hasReset && skeletonRenderer != null)
|
if (!hasReset && skeletonRenderer != null)
|
||||||
HandleReset(skeletonRenderer);
|
HandleRebuild(skeletonRenderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void HandleReset (SkeletonRenderer renderer) {
|
public void HandleRebuild (SkeletonRenderer renderer) {
|
||||||
if (string.IsNullOrEmpty(slotName))
|
if (string.IsNullOrEmpty(slotName))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
hasReset = true;
|
hasReset = true;
|
||||||
|
|
||||||
ClearColliders();
|
ClearColliders();
|
||||||
colliderTable.Clear();
|
colliderTable.Clear();
|
||||||
|
|
||||||
if (skeletonRenderer.skeleton == null) {
|
if (skeletonRenderer.skeleton == null) {
|
||||||
skeletonRenderer.OnRebuild -= HandleReset;
|
skeletonRenderer.OnRebuild -= HandleRebuild;
|
||||||
skeletonRenderer.Initialize(false);
|
skeletonRenderer.Initialize(false);
|
||||||
skeletonRenderer.OnRebuild += HandleReset;
|
skeletonRenderer.OnRebuild += HandleRebuild;
|
||||||
}
|
}
|
||||||
|
|
||||||
var skeleton = skeletonRenderer.skeleton;
|
var skeleton = skeletonRenderer.skeleton;
|
||||||
slot = skeleton.FindSlot(slotName);
|
slot = skeleton.FindSlot(slotName);
|
||||||
int slotIndex = skeleton.FindSlotIndex(slotName);
|
int slotIndex = skeleton.FindSlotIndex(slotName);
|
||||||
|
|
||||||
foreach (var skin in skeleton.Data.Skins) {
|
if (this.gameObject.activeInHierarchy) {
|
||||||
var attachmentNames = new List<string>();
|
foreach (var skin in skeleton.Data.Skins) {
|
||||||
skin.FindNamesForSlot(slotIndex, attachmentNames);
|
var attachmentNames = new List<string>();
|
||||||
|
skin.FindNamesForSlot(slotIndex, attachmentNames);
|
||||||
|
|
||||||
foreach (var attachmentName in attachmentNames) {
|
foreach (var attachmentName in attachmentNames) {
|
||||||
var attachment = skin.GetAttachment(slotIndex, attachmentName);
|
var attachment = skin.GetAttachment(slotIndex, attachmentName);
|
||||||
var boundingBoxAttachment = attachment as BoundingBoxAttachment;
|
var boundingBoxAttachment = attachment as BoundingBoxAttachment;
|
||||||
if (boundingBoxAttachment != null) {
|
if (boundingBoxAttachment != null) {
|
||||||
var bbCollider = SkeletonUtility.AddBoundingBoxAsComponent(boundingBoxAttachment, gameObject, true);
|
var bbCollider = SkeletonUtility.AddBoundingBoxAsComponent(boundingBoxAttachment, gameObject, true);
|
||||||
bbCollider.enabled = false;
|
bbCollider.enabled = false;
|
||||||
bbCollider.hideFlags = HideFlags.HideInInspector;
|
bbCollider.hideFlags = HideFlags.NotEditable;
|
||||||
colliderTable.Add(boundingBoxAttachment, bbCollider);
|
colliderTable.Add(boundingBoxAttachment, bbCollider);
|
||||||
attachmentNameTable.Add(boundingBoxAttachment, attachmentName);
|
attachmentNameTable.Add(boundingBoxAttachment, attachmentName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
valid = colliderTable.Count != 0;
|
valid = colliderTable.Count != 0;
|
||||||
|
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
|
||||||
|
|
||||||
if (!valid)
|
|
||||||
Debug.LogWarning("Bounding Box Follower not valid! Slot [" + slotName + "] does not contain any Bounding Box Attachments!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearColliders () {
|
void ClearColliders () {
|
||||||
var colliders = GetComponents<PolygonCollider2D>();
|
var colliders = GetComponents<PolygonCollider2D>();
|
||||||
|
if (colliders.Length == 0) return;
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
if (Application.isPlaying) {
|
if (Application.isPlaying) {
|
||||||
foreach (var c in colliders)
|
foreach (var c in colliders) {
|
||||||
Destroy(c);
|
if (c != null)
|
||||||
|
Destroy(c);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
foreach (var c in colliders)
|
foreach (var c in colliders)
|
||||||
DestroyImmediate(c);
|
DestroyImmediate(c);
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
foreach (var c in colliders)
|
||||||
|
if (c != null)
|
||||||
|
Destroy(c);
|
||||||
|
#endif
|
||||||
|
|
||||||
colliderTable.Clear();
|
colliderTable.Clear();
|
||||||
attachmentNameTable.Clear();
|
attachmentNameTable.Clear();
|
||||||
@ -139,21 +158,19 @@ namespace Spine.Unity {
|
|||||||
if (!skeletonRenderer.valid)
|
if (!skeletonRenderer.valid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (slot != null) {
|
if (slot != null && slot.Attachment != currentAttachment)
|
||||||
if (slot.Attachment != currentAttachment)
|
SetCurrent((BoundingBoxAttachment)slot.Attachment);
|
||||||
SetCurrent((BoundingBoxAttachment)slot.Attachment);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetCurrent (BoundingBoxAttachment attachment) {
|
void SetCurrent (BoundingBoxAttachment attachment) {
|
||||||
if (currentCollider)
|
if (currentCollider != null)
|
||||||
currentCollider.enabled = false;
|
currentCollider.enabled = false;
|
||||||
|
|
||||||
if (attachment != null) {
|
if (attachment == null) {
|
||||||
|
currentCollider = null;
|
||||||
|
} else {
|
||||||
currentCollider = colliderTable[attachment];
|
currentCollider = colliderTable[attachment];
|
||||||
currentCollider.enabled = true;
|
currentCollider.enabled = true;
|
||||||
} else {
|
|
||||||
currentCollider = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
currentAttachment = attachment;
|
currentAttachment = attachment;
|
||||||
|
|||||||
@ -31,7 +31,6 @@
|
|||||||
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using System.Collections;
|
|
||||||
|
|
||||||
namespace Spine.Unity.Editor {
|
namespace Spine.Unity.Editor {
|
||||||
|
|
||||||
@ -39,7 +38,8 @@ namespace Spine.Unity.Editor {
|
|||||||
public class BoundingBoxFollowerInspector : UnityEditor.Editor {
|
public class BoundingBoxFollowerInspector : UnityEditor.Editor {
|
||||||
SerializedProperty skeletonRenderer, slotName;
|
SerializedProperty skeletonRenderer, slotName;
|
||||||
BoundingBoxFollower follower;
|
BoundingBoxFollower follower;
|
||||||
bool needToReset = false;
|
bool rebuildRequired = false;
|
||||||
|
bool addBoneFollower = false;
|
||||||
|
|
||||||
void OnEnable () {
|
void OnEnable () {
|
||||||
skeletonRenderer = serializedObject.FindProperty("skeletonRenderer");
|
skeletonRenderer = serializedObject.FindProperty("skeletonRenderer");
|
||||||
@ -48,41 +48,63 @@ namespace Spine.Unity.Editor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override void OnInspectorGUI () {
|
public override void OnInspectorGUI () {
|
||||||
if (needToReset) {
|
bool isInspectingPrefab = (PrefabUtility.GetPrefabType(target) == PrefabType.Prefab);
|
||||||
follower.HandleReset(null);
|
bool repaintEvent = UnityEngine.Event.current.type == EventType.Repaint;
|
||||||
needToReset = false;
|
|
||||||
|
if (rebuildRequired) {
|
||||||
|
follower.HandleRebuild(null);
|
||||||
|
rebuildRequired = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorGUI.BeginChangeCheck();
|
EditorGUI.BeginChangeCheck();
|
||||||
EditorGUILayout.PropertyField(skeletonRenderer);
|
EditorGUILayout.PropertyField(skeletonRenderer);
|
||||||
EditorGUILayout.PropertyField(slotName, new GUIContent("Slot"));
|
EditorGUILayout.PropertyField(slotName, new GUIContent("Slot"));
|
||||||
|
if (EditorGUI.EndChangeCheck()) {
|
||||||
if (EditorGUI.EndChangeCheck()){
|
|
||||||
serializedObject.ApplyModifiedProperties();
|
serializedObject.ApplyModifiedProperties();
|
||||||
needToReset = true;
|
if (!isInspectingPrefab)
|
||||||
|
rebuildRequired = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasBone = follower.GetComponent<BoneFollower>() != null;
|
bool hasBoneFollower = follower.GetComponent<BoneFollower>() != null;
|
||||||
|
using (new EditorGUI.DisabledGroupScope(hasBoneFollower || follower.Slot == null)) {
|
||||||
EditorGUI.BeginDisabledGroup(hasBone || follower.Slot == null);
|
|
||||||
{
|
|
||||||
if (GUILayout.Button(new GUIContent("Add Bone Follower", SpineEditorUtilities.Icons.bone))) {
|
if (GUILayout.Button(new GUIContent("Add Bone Follower", SpineEditorUtilities.Icons.bone))) {
|
||||||
var boneFollower = follower.gameObject.AddComponent<BoneFollower>();
|
addBoneFollower = true;
|
||||||
boneFollower.boneName = follower.Slot.Data.BoneData.Name;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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<PolygonCollider2D>();
|
||||||
|
if (collider != null) Debug.LogWarning("Found BoundingBoxFollower collider components in prefab. These are disposed and regenerated at runtime.");
|
||||||
|
|
||||||
//GUILayout.Space(20);
|
} else {
|
||||||
GUILayout.Label("Attachment Names", EditorStyles.boldLabel);
|
EditorGUILayout.LabelField(string.Format("Attachment Names ({0} PolygonCollider2D)", follower.colliderTable.Count), EditorStyles.boldLabel);
|
||||||
foreach (var kp in follower.attachmentNameTable) {
|
EditorGUI.BeginChangeCheck();
|
||||||
string name = kp.Value;
|
foreach (var kp in follower.attachmentNameTable) {
|
||||||
var collider = follower.colliderTable[kp.Key];
|
string attachmentName = kp.Value;
|
||||||
bool isPlaceholder = name != kp.Key.Name;
|
var collider = follower.colliderTable[kp.Key];
|
||||||
collider.enabled = EditorGUILayout.ToggleLeft(new GUIContent(!isPlaceholder ? name : name + " [" + kp.Key.Name + "]", isPlaceholder ? SpineEditorUtilities.Icons.skinPlaceholder : SpineEditorUtilities.Icons.boundingBox), collider.enabled);
|
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>();
|
||||||
|
boneFollower.boneName = follower.Slot.Data.BoneData.Name;
|
||||||
|
addBoneFollower = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user