Selaa lähdekoodia

Merge pull request #409 from Fenrisul/master

[Unity] Added BoundingBoxFollower
Fenrisul 10 vuotta sitten
vanhempi
commit
9fae45306e

+ 2 - 0
spine-unity/Assets/spine-unity/BoneFollower.cs

@@ -57,6 +57,8 @@ public class BoneFollower : MonoBehaviour {
 
 
 	/// <summary>If a bone isn't set, boneName is used to find the bone.</summary>
+	
+	[SpineBone(dataField: "skeletonRenderer")]
 	public String boneName;
 	public bool resetOnAwake = true;
 	protected Transform cachedTransform;

+ 160 - 0
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<BoundingBoxAttachment, PolygonCollider2D> colliderTable = new Dictionary<BoundingBoxAttachment, PolygonCollider2D>();
+	public 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;
+		}
+	}
+
+	
+	void OnEnable () {
+		ClearColliders();
+
+		if (skeletonRenderer == null)
+			skeletonRenderer = GetComponentInParent<SkeletonRenderer>();
+
+		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<string> attachmentNames = new List<string>();
+			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<PolygonCollider2D>();
+		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];
+	}
+}

+ 8 - 0
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: 

+ 15 - 18
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] = "<None>";
-			for (int i = 0; i < bones.Length - 1; i++)
-				bones[i + 1] = component.skeletonRenderer.skeleton.Data.Bones[i].Name;
-			Array.Sort<String>(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 {

+ 53 - 0
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<BoneFollower>() != null;
+
+		EditorGUI.BeginDisabledGroup(hasBone || follower.Slot == null);
+		{
+			if (GUILayout.Button(new GUIContent("Add Bone Follower", SpineEditorUtilities.Icons.bone))) {
+				var boneFollower = follower.gameObject.AddComponent<BoneFollower>();
+				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);
+		}
+	}
+}

+ 8 - 0
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: 

+ 1 - 7
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: 

+ 8 - 14
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: 

+ 29 - 2
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<Attachment> attachments = new List<Attachment>();
+					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();

+ 22 - 1
spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs

@@ -149,6 +149,7 @@ public class SpineEditorUtilities : AssetPostprocessor {
 	public static string editorGUIPath = "";
 	static Dictionary<int, GameObject> skeletonRendererTable;
 	static Dictionary<int, SkeletonUtilityBone> skeletonUtilityBoneTable;
+	static Dictionary<int, BoundingBoxFollower> 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<int, GameObject>();
 		skeletonUtilityBoneTable = new Dictionary<int, SkeletonUtilityBone>();
+		boundingBoxFollowerTable = new Dictionary<int, BoundingBoxFollower>();
 
 		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<SkeletonRenderer>();
-
 		foreach (SkeletonRenderer r in arr)
 			skeletonRendererTable.Add(r.gameObject.GetInstanceID(), r.gameObject);
 
 		SkeletonUtilityBone[] boneArr = Object.FindObjectsOfType<SkeletonUtilityBone>();
 		foreach (SkeletonUtilityBone b in boneArr)
 			skeletonUtilityBoneTable.Add(b.gameObject.GetInstanceID(), b);
+
+		BoundingBoxFollower[] bbfArr = Object.FindObjectsOfType<BoundingBoxFollower>();
+		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);
+			}
 		}
 
 	}

+ 22 - 0
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<PolygonCollider2D>();
+		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 ();
 

+ 4 - 1
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;
 
 	/// <summary>
 	/// 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<SkeletonRenderer>() will be called as a fallback.
 	/// </param>
-	public SpineSlot(string startsWith = "", string dataField = "") {
+	/// <param name="containsBoundingBoxes">Disables popup results that don't contain bounding box attachments when true.</param>
+	public SpineSlot(string startsWith = "", string dataField = "", bool containsBoundingBoxes = false) {
 		this.startsWith = startsWith;
 		this.dataField = dataField;
+		this.containsBoundingBoxes = containsBoundingBoxes;
 	}
 }