diff --git a/spine-unity/Assets/spine-unity/BoneFollower.cs b/spine-unity/Assets/spine-unity/BoneFollower.cs
index e900ba8ee..1a4071762 100644
--- a/spine-unity/Assets/spine-unity/BoneFollower.cs
+++ b/spine-unity/Assets/spine-unity/BoneFollower.cs
@@ -57,6 +57,8 @@ public class BoneFollower : MonoBehaviour {
/// If a bone isn't set, boneName is used to find the bone.
+
+ [SpineBone(dataField: "skeletonRenderer")]
public String boneName;
public bool resetOnAwake = true;
protected Transform cachedTransform;
diff --git a/spine-unity/Assets/spine-unity/BoundingBoxFollower.cs b/spine-unity/Assets/spine-unity/BoundingBoxFollower.cs
new file mode 100644
index 000000000..f1396c6d0
--- /dev/null
+++ b/spine-unity/Assets/spine-unity/BoundingBoxFollower.cs
@@ -0,0 +1,160 @@
+using UnityEngine;
+using System.Collections;
+using System.Collections.Generic;
+using Spine;
+
+[ExecuteInEditMode]
+public class BoundingBoxFollower : MonoBehaviour {
+
+ public SkeletonRenderer skeletonRenderer;
+
+ [SpineSlot(dataField: "skeletonRenderer", containsBoundingBoxes: true)]
+ public string slotName;
+
+ //TODO: not this
+ [Tooltip("LOL JK, Someone else do it!")]
+ public bool use3DMeshCollider;
+
+ private Slot slot;
+ private BoundingBoxAttachment currentAttachment;
+ private PolygonCollider2D currentCollider;
+ private string currentAttachmentName;
+ private bool valid = false;
+ private bool hasReset;
+
+ public Dictionary colliderTable = new Dictionary();
+ public 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;
+ }
+ }
+
+
+ void OnEnable () {
+ ClearColliders();
+
+ if (skeletonRenderer == null)
+ skeletonRenderer = GetComponentInParent();
+
+ if (skeletonRenderer != null) {
+ skeletonRenderer.OnReset -= HandleReset;
+ skeletonRenderer.OnReset += HandleReset;
+ }
+ }
+
+ void OnDisable () {
+ skeletonRenderer.OnReset -= HandleReset;
+ }
+
+ void Start () {
+ if (!hasReset && skeletonRenderer != null)
+ HandleReset(skeletonRenderer);
+ }
+
+ public void HandleReset (SkeletonRenderer renderer) {
+ if (slotName == null || slotName == "")
+ return;
+
+ hasReset = true;
+
+ ClearColliders();
+ colliderTable.Clear();
+
+ if (skeletonRenderer.skeleton == null) {
+ skeletonRenderer.OnReset -= HandleReset;
+ skeletonRenderer.Reset();
+ skeletonRenderer.OnReset += HandleReset;
+ }
+
+
+ var skeleton = skeletonRenderer.skeleton;
+ slot = skeleton.FindSlot(slotName);
+ int slotIndex = skeleton.FindSlotIndex(slotName);
+
+ foreach (var skin in skeleton.Data.Skins) {
+ List attachmentNames = new List();
+ skin.FindNamesForSlot(slotIndex, attachmentNames);
+
+ foreach (var name in attachmentNames) {
+ var attachment = skin.GetAttachment(slotIndex, name);
+ if (attachment is BoundingBoxAttachment) {
+ var collider = SkeletonUtility.AddBoundingBoxAsComponent((BoundingBoxAttachment)attachment, gameObject, true);
+ collider.enabled = false;
+ collider.hideFlags = HideFlags.HideInInspector;
+ colliderTable.Add((BoundingBoxAttachment)attachment, collider);
+ attachmentNameTable.Add((BoundingBoxAttachment)attachment, name);
+ }
+ }
+ }
+
+ if (colliderTable.Count == 0)
+ valid = false;
+ else
+ valid = true;
+
+ if (!valid)
+ Debug.LogWarning("Bounding Box Follower not valid! Slot [" + slotName + "] does not contain any Bounding Box Attachments!");
+ }
+
+ void ClearColliders () {
+ var colliders = GetComponents();
+ if (Application.isPlaying) {
+ foreach (var c in colliders) {
+ Destroy(c);
+ }
+ } else {
+ foreach (var c in colliders) {
+ DestroyImmediate(c);
+ }
+ }
+
+ colliderTable.Clear();
+ attachmentNameTable.Clear();
+ }
+
+ void LateUpdate () {
+ if (!skeletonRenderer.valid)
+ return;
+
+ if (slot != null) {
+ if (slot.Attachment != currentAttachment)
+ SetCurrent((BoundingBoxAttachment)slot.Attachment);
+ }
+ }
+
+ void SetCurrent (BoundingBoxAttachment attachment) {
+ if (currentCollider)
+ currentCollider.enabled = false;
+
+ if (attachment != null) {
+ currentCollider = colliderTable[attachment];
+ currentCollider.enabled = true;
+ } else {
+ currentCollider = null;
+ }
+
+ currentAttachment = attachment;
+
+ currentAttachmentName = currentAttachment == null ? null : attachmentNameTable[attachment];
+ }
+}
diff --git a/spine-unity/Assets/spine-unity/BoundingBoxFollower.cs.meta b/spine-unity/Assets/spine-unity/BoundingBoxFollower.cs.meta
new file mode 100644
index 000000000..d81fd14af
--- /dev/null
+++ b/spine-unity/Assets/spine-unity/BoundingBoxFollower.cs.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 0317ee9ba6e1b1e49a030268e026d372
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
diff --git a/spine-unity/Assets/spine-unity/Editor/BoneFollowerInspector.cs b/spine-unity/Assets/spine-unity/Editor/BoneFollowerInspector.cs
index 943a98715..224bc65ff 100644
--- a/spine-unity/Assets/spine-unity/Editor/BoneFollowerInspector.cs
+++ b/spine-unity/Assets/spine-unity/Editor/BoneFollowerInspector.cs
@@ -35,6 +35,7 @@ using UnityEngine;
public class BoneFollowerInspector : Editor {
private SerializedProperty boneName, skeletonRenderer, followZPosition, followBoneRotation;
BoneFollower component;
+ bool needsReset;
void OnEnable () {
skeletonRenderer = serializedObject.FindProperty("skeletonRenderer");
@@ -64,6 +65,12 @@ public class BoneFollowerInspector : Editor {
}
override public void OnInspectorGUI () {
+ if (needsReset) {
+ component.Reset();
+ component.DoUpdate();
+ needsReset = false;
+ SceneView.RepaintAll();
+ }
serializedObject.Update();
FindRenderer();
@@ -71,26 +78,16 @@ public class BoneFollowerInspector : Editor {
EditorGUILayout.PropertyField(skeletonRenderer);
if (component.valid) {
- String[] bones = new String[1];
- try {
- bones = new String[component.skeletonRenderer.skeleton.Data.Bones.Count + 1];
- } catch {
-
+ EditorGUI.BeginChangeCheck();
+ EditorGUILayout.PropertyField(boneName);
+ if (EditorGUI.EndChangeCheck()) {
+ serializedObject.ApplyModifiedProperties();
+ needsReset = true;
+ serializedObject.Update();
}
+
+
- bones[0] = "";
- for (int i = 0; i < bones.Length - 1; i++)
- bones[i + 1] = component.skeletonRenderer.skeleton.Data.Bones[i].Name;
- Array.Sort(bones);
- int boneIndex = Math.Max(0, Array.IndexOf(bones, boneName.stringValue));
-
- EditorGUILayout.BeginHorizontal();
- EditorGUILayout.LabelField("Bone");
- EditorGUIUtility.LookLikeControls();
- boneIndex = EditorGUILayout.Popup(boneIndex, bones);
- EditorGUILayout.EndHorizontal();
-
- boneName.stringValue = boneIndex == 0 ? null : bones[boneIndex];
EditorGUILayout.PropertyField(followBoneRotation);
EditorGUILayout.PropertyField(followZPosition);
} else {
diff --git a/spine-unity/Assets/spine-unity/Editor/BoundingBoxFollowerInspector.cs b/spine-unity/Assets/spine-unity/Editor/BoundingBoxFollowerInspector.cs
new file mode 100644
index 000000000..fddcd6e24
--- /dev/null
+++ b/spine-unity/Assets/spine-unity/Editor/BoundingBoxFollowerInspector.cs
@@ -0,0 +1,53 @@
+using UnityEngine;
+using UnityEditor;
+using System.Collections;
+
+[CustomEditor(typeof(BoundingBoxFollower))]
+public class BoundingBoxFollowerInspector : Editor {
+ SerializedProperty skeletonRenderer, slotName;
+ BoundingBoxFollower follower;
+ bool needToReset = false;
+
+ void OnEnable () {
+ skeletonRenderer = serializedObject.FindProperty("skeletonRenderer");
+ slotName = serializedObject.FindProperty("slotName");
+ follower = (BoundingBoxFollower)target;
+ }
+
+ public override void OnInspectorGUI () {
+ if (needToReset) {
+ follower.HandleReset(null);
+ needToReset = false;
+ }
+ EditorGUI.BeginChangeCheck();
+ EditorGUILayout.PropertyField(skeletonRenderer);
+ EditorGUILayout.PropertyField(slotName, new GUIContent("Slot"));
+
+ if (EditorGUI.EndChangeCheck()){
+ serializedObject.ApplyModifiedProperties();
+ needToReset = true;
+ }
+
+ bool hasBone = follower.GetComponent() != null;
+
+ EditorGUI.BeginDisabledGroup(hasBone || 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;
+ }
+ }
+ EditorGUI.EndDisabledGroup();
+
+
+
+ //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);
+ }
+ }
+}
diff --git a/spine-unity/Assets/spine-unity/Editor/BoundingBoxFollowerInspector.cs.meta b/spine-unity/Assets/spine-unity/Editor/BoundingBoxFollowerInspector.cs.meta
new file mode 100644
index 000000000..e42ba7739
--- /dev/null
+++ b/spine-unity/Assets/spine-unity/Editor/BoundingBoxFollowerInspector.cs.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 670a3cefa3853bd48b5da53a424fd542
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-boundingBox.png.meta b/spine-unity/Assets/spine-unity/Editor/GUI/icon-boundingBox.png.meta
index 49c9ab374..0e5d62848 100644
--- a/spine-unity/Assets/spine-unity/Editor/GUI/icon-boundingBox.png.meta
+++ b/spine-unity/Assets/spine-unity/Editor/GUI/icon-boundingBox.png.meta
@@ -20,11 +20,8 @@ TextureImporter:
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 0
- cubemapConvolution: 0
- cubemapConvolutionSteps: 8
- cubemapConvolutionExponent: 1.5
seamlessCubemap: 0
- textureFormat: -1
+ textureFormat: -3
maxTextureSize: 1024
textureSettings:
filterMode: -1
@@ -33,7 +30,6 @@ TextureImporter:
wrapMode: 1
nPOTScale: 0
lightmap: 0
- rGBM: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
@@ -49,5 +45,3 @@ TextureImporter:
sprites: []
spritePackingTag:
userData:
- assetBundleName:
- assetBundleVariant:
diff --git a/spine-unity/Assets/spine-unity/Editor/GUI/icon-hingeChain.png.meta b/spine-unity/Assets/spine-unity/Editor/GUI/icon-hingeChain.png.meta
index 83eb12195..e61da1e82 100644
--- a/spine-unity/Assets/spine-unity/Editor/GUI/icon-hingeChain.png.meta
+++ b/spine-unity/Assets/spine-unity/Editor/GUI/icon-hingeChain.png.meta
@@ -5,8 +5,8 @@ TextureImporter:
serializedVersion: 2
mipmaps:
mipMapMode: 0
- enableMipMap: 1
- linearTexture: 0
+ enableMipMap: 0
+ linearTexture: 1
correctGamma: 0
fadeOut: 0
borderMipMap: 0
@@ -20,20 +20,16 @@ TextureImporter:
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 0
- cubemapConvolution: 0
- cubemapConvolutionSteps: 8
- cubemapConvolutionExponent: 1.5
seamlessCubemap: 0
- textureFormat: -1
+ textureFormat: -3
maxTextureSize: 1024
textureSettings:
filterMode: -1
- aniso: -1
+ aniso: 1
mipBias: -1
- wrapMode: -1
- nPOTScale: 1
+ wrapMode: 1
+ nPOTScale: 0
lightmap: 0
- rGBM: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
@@ -42,12 +38,10 @@ TextureImporter:
spritePivot: {x: .5, y: .5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
- alphaIsTransparency: 0
- textureType: -1
+ alphaIsTransparency: 1
+ textureType: 2
buildTargetSettings: []
spriteSheet:
sprites: []
spritePackingTag:
userData:
- assetBundleName:
- assetBundleVariant:
diff --git a/spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs b/spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs
index 9d9e3b3d2..59364ac4c 100644
--- a/spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs
+++ b/spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs
@@ -114,8 +114,35 @@ public class SpineSlotDrawer : PropertyDrawer {
for (int i = 0; i < data.Slots.Count; i++) {
string name = data.Slots[i].Name;
- if (name.StartsWith(attrib.startsWith))
- menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property));
+ if (name.StartsWith(attrib.startsWith)) {
+ if (attrib.containsBoundingBoxes) {
+
+ int slotIndex = i;
+
+ List attachments = new List();
+ foreach (var skin in data.Skins) {
+ skin.FindAttachmentsForSlot(slotIndex, attachments);
+ }
+
+ bool hasBoundingBox = false;
+ foreach (var attachment in attachments) {
+ if (attachment is BoundingBoxAttachment) {
+ menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property));
+ hasBoundingBox = true;
+ break;
+ }
+ }
+
+ if (!hasBoundingBox)
+ menu.AddDisabledItem(new GUIContent(name));
+
+
+ } else {
+ menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property));
+ }
+
+ }
+
}
menu.ShowAsContext();
diff --git a/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs b/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs
index a697c8fc5..0ba0fd164 100644
--- a/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs
+++ b/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs
@@ -149,6 +149,7 @@ public class SpineEditorUtilities : AssetPostprocessor {
public static string editorGUIPath = "";
static Dictionary skeletonRendererTable;
static Dictionary skeletonUtilityBoneTable;
+ static Dictionary boundingBoxFollowerTable;
public static float defaultScale = 0.01f;
public static float defaultMix = 0.2f;
public static string defaultShader = "Spine/Skeleton";
@@ -172,6 +173,7 @@ public class SpineEditorUtilities : AssetPostprocessor {
skeletonRendererTable = new Dictionary();
skeletonUtilityBoneTable = new Dictionary();
+ boundingBoxFollowerTable = new Dictionary();
EditorApplication.hierarchyWindowChanged += HierarchyWindowChanged;
EditorApplication.hierarchyWindowItemOnGUI += HierarchyWindowItemOnGUI;
@@ -188,15 +190,19 @@ public class SpineEditorUtilities : AssetPostprocessor {
static void HierarchyWindowChanged () {
skeletonRendererTable.Clear();
skeletonUtilityBoneTable.Clear();
+ boundingBoxFollowerTable.Clear();
SkeletonRenderer[] arr = Object.FindObjectsOfType();
-
foreach (SkeletonRenderer r in arr)
skeletonRendererTable.Add(r.gameObject.GetInstanceID(), r.gameObject);
SkeletonUtilityBone[] boneArr = Object.FindObjectsOfType();
foreach (SkeletonUtilityBone b in boneArr)
skeletonUtilityBoneTable.Add(b.gameObject.GetInstanceID(), b);
+
+ BoundingBoxFollower[] bbfArr = Object.FindObjectsOfType();
+ foreach (BoundingBoxFollower bbf in bbfArr)
+ boundingBoxFollowerTable.Add(bbf.gameObject.GetInstanceID(), bbf);
}
static void HierarchyWindowItemOnGUI (int instanceId, Rect selectionRect) {
@@ -226,6 +232,21 @@ public class SpineEditorUtilities : AssetPostprocessor {
}
}
+ } else if (boundingBoxFollowerTable.ContainsKey(instanceId)) {
+ Rect r = new Rect(selectionRect);
+ r.x -= 26;
+
+ if (boundingBoxFollowerTable[instanceId] != null) {
+ if (boundingBoxFollowerTable[instanceId].transform.childCount == 0)
+ r.x += 13;
+
+ r.y += 2;
+
+ r.width = 13;
+ r.height = 13;
+
+ GUI.DrawTexture(r, Icons.boundingBox);
+ }
}
}
diff --git a/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtility.cs b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtility.cs
index 091c0139d..5eec07700 100644
--- a/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtility.cs
+++ b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtility.cs
@@ -101,6 +101,28 @@ public class SkeletonUtility : MonoBehaviour {
return null;
}
+ public static PolygonCollider2D AddBoundingBoxAsComponent (BoundingBoxAttachment boundingBox, GameObject gameObject, bool isTrigger = true) {
+ if (boundingBox == null)
+ return null;
+
+ var collider = gameObject.AddComponent();
+ collider.isTrigger = isTrigger;
+ float[] floats = boundingBox.Vertices;
+ int floatCount = floats.Length;
+ int vertCount = floatCount / 2;
+
+ Vector2[] verts = new Vector2[vertCount];
+ int v = 0;
+ for (int i = 0; i < floatCount; i += 2, v++) {
+ verts[v].x = floats[i];
+ verts[v].y = floats[i + 1];
+ }
+
+ collider.SetPath(0, verts);
+
+ return collider;
+ }
+
public delegate void SkeletonUtilityDelegate ();
diff --git a/spine-unity/Assets/spine-unity/SpineAttributes.cs b/spine-unity/Assets/spine-unity/SpineAttributes.cs
index 1bf15bca2..e7a2256d5 100644
--- a/spine-unity/Assets/spine-unity/SpineAttributes.cs
+++ b/spine-unity/Assets/spine-unity/SpineAttributes.cs
@@ -38,6 +38,7 @@ using System.Collections;
public class SpineSlot : PropertyAttribute {
public string startsWith = "";
public string dataField = "";
+ public bool containsBoundingBoxes = false;
///
/// Smart popup menu for Spine Slots
@@ -47,9 +48,11 @@ public class SpineSlot : PropertyAttribute {
/// 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 SpineSlot(string startsWith = "", string dataField = "") {
+ /// Disables popup results that don't contain bounding box attachments when true.
+ public SpineSlot(string startsWith = "", string dataField = "", bool containsBoundingBoxes = false) {
this.startsWith = startsWith;
this.dataField = dataField;
+ this.containsBoundingBoxes = containsBoundingBoxes;
}
}