Browse Source

[unity] Updates to examples and editor fixes + new SpineAttributes

pharan 8 years ago
parent
commit
f18a3cadb2

+ 3 - 2
CHANGELOG.md

@@ -75,13 +75,14 @@
    * **Two color tinting** is currently supported via extra UV2 and UV3 mesh vertex streams. To use Two color tinting, you need to:
      * switch on "Tint Black" under "Advanced...",
      * use the new `Spine/Skeleton Tint Black` shader, or your own shader that treats the UV2 and UV3 streams similarly.
-   * **Clipping** is now supported. The SkeletonRenderers switches to slightly slower mesh generation code when clipping so limit your use of `ClippingAttachment`s when using on large numbers of skeletons.
+   * **Clipping** is now supported. The SkeletonAnimation switches to slightly slower mesh generation code when clipping so limit your use of `ClippingAttachment`s when using on large numbers of skeletons.
  * **[SpineAttribute] Improvements** 
    * **Icons have been added to SpineAttributeDrawers**. This should make your default inspectors easier to understand at a glance.
+   * **Added Constraint Attributes** You can now use `[SpineIkConstraint]` `[SpineTransformConstraint]` `[SpinePathConstraint]`
    * **SpineAttribute dataField** parameter can also now detect sibling fields within arrays and serializable structs/classes.
    * **[SpineAttribute(includeNone:false)]** SpineAttributes now have an `includeNone` optional parameter to specify if you want to include or exclude a none ("") value option in the dropdown menu. Default is `includeNone:true`.
    * **[SpineAttachment(skinField:"mySkin")]** The SpineAttachment attribute now has a skinField optional parameter to limit the dropdown items to attachments in a specific skin instead of the just default skin or all the skins in SkeletonData.
- * **SkeletonDebugWindow**. Debugging tools have been moved from the SkeletonRenderer and SkeletonUtility component inspectors into its own utility window. You can access "Skeleton Debug" under the `Advanced...` foldout in the SkeletonRenderer inspector, or in SkeletonRenderer's right-click/context menu.
+ * **SkeletonDebugWindow**. Debugging tools have been moved from the SkeletonAnimation and SkeletonUtility component inspectors into its own utility window. You can access "Skeleton Debug" under the `Advanced...` foldout in the SkeletonAnimation inspector, or in SkeletonAnimation's right-click/context menu.
    * **Skeleton Baking Window** The old Skeleton Baking feature is also now accessible through the SkeletonDataAsset's right-click/context menu.
  * **AttachmentTools source material**. `AttachmentTools` methods can now accept a `sourceMaterial` argument to copy material properties from.
  * **AttachmentTools Skin Extensions**. Using AttachmentTools, you can now add entries by slot name by also providing a skeleton argument. Also `Append(Skin)`, `RemoveAttachment` and `Clear` have been added.

+ 82 - 0
spine-unity/Assets/Examples/Scripts/Sample Components/SpineEventUnityHandler.cs

@@ -0,0 +1,82 @@
+/******************************************************************************
+ * Spine Runtimes Software License v2.5
+ *
+ * Copyright (c) 2013-2016, Esoteric Software
+ * All rights reserved.
+ *
+ * You are granted a perpetual, non-exclusive, non-sublicensable, and
+ * non-transferable license to use, install, execute, and perform the Spine
+ * Runtimes software and derivative works solely for personal or internal
+ * use. Without the written permission of Esoteric Software (see Section 2 of
+ * the Spine Software License Agreement), you may not (a) modify, translate,
+ * adapt, or develop new applications using the Spine Runtimes or otherwise
+ * create derivative works or improvements of the Spine Runtimes or (b) remove,
+ * delete, alter, or obscure any trademarks or any copyright, trademark, patent,
+ * or other intellectual property or proprietary rights notices on or in the
+ * Software, including any copy thereof. Redistributions in binary or source
+ * form must include this license and terms.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF
+ * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.Events;
+
+namespace Spine.Unity.Modules {
+
+	public class SpineEventUnityHandler : MonoBehaviour {
+
+		[System.Serializable]
+		public class EventPair {
+			[SpineEvent] public string spineEvent;
+			public UnityEvent unityHandler;
+			public AnimationState.TrackEntryEventDelegate eventDelegate;
+		}
+
+		public List<EventPair> events = new List<EventPair>();
+
+		ISkeletonComponent skeletonComponent;
+		IAnimationStateComponent animationStateComponent;
+
+		void Start () {
+			skeletonComponent = skeletonComponent ?? GetComponent<ISkeletonComponent>();
+			if (skeletonComponent == null) return;
+			animationStateComponent = animationStateComponent ?? skeletonComponent as IAnimationStateComponent;
+			if (animationStateComponent == null) return;
+			var skeleton = skeletonComponent.Skeleton;
+			if (skeleton == null) return;
+
+
+			var skeletonData = skeleton.Data;
+			var state = animationStateComponent.AnimationState;
+			foreach (var ep in events) {
+				var eventData = skeletonData.FindEvent(ep.spineEvent);
+				ep.eventDelegate = ep.eventDelegate ?? delegate(TrackEntry trackEntry, Event e) { if (e.Data == eventData) ep.unityHandler.Invoke(); };
+				state.Event += ep.eventDelegate;
+			}
+		}
+
+		void OnDestroy () {
+			animationStateComponent = animationStateComponent ?? GetComponent<IAnimationStateComponent>();
+			if (animationStateComponent == null) return;
+
+			var state = animationStateComponent.AnimationState;
+			foreach (var ep in events) {
+				if (ep.eventDelegate != null) state.Event -= ep.eventDelegate;
+				ep.eventDelegate = null;
+			}
+		}
+
+	}
+}
+

+ 12 - 0
spine-unity/Assets/Examples/Scripts/Sample Components/SpineEventUnityHandler.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 90293750f472d3340b452cec6fea2606
+timeCreated: 1495263964
+licenseType: Free
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 1 - 1
spine-unity/Assets/spine-unity/Asset Types/Editor/AtlasAssetInspector.cs

@@ -52,7 +52,7 @@ namespace Spine.Unity.Editor {
 				if (spriteSlicesLabel == null) {
 					spriteSlicesLabel = new GUIContent(
 						"Apply Regions as Texture Sprite Slices",
-						SpineInspectorUtility.UnityIcon(typeof(SceneAsset)),
+						SpineEditorUtilities.Icons.unity,
 						"Adds Sprite slices to atlas texture(s). " +
 						"Updates existing slices if ones with matching names exist. \n\n" +
 						"If your atlas was exported with Premultiply Alpha, " +

+ 2 - 2
spine-unity/Assets/spine-unity/Asset Types/Editor/SkeletonDataAssetInspector.cs

@@ -259,10 +259,10 @@ namespace Spine.Unity.Editor {
 		void DrawUnityTools () {
 			#if SPINE_SKELETON_ANIMATOR
 			using (new SpineInspectorUtility.BoxScope()) {
-				isMecanimExpanded = EditorGUILayout.Foldout(isMecanimExpanded, SpineInspectorUtility.TempContent("SkeletonAnimator", SpineInspectorUtility.UnityIcon(typeof(SceneAsset))));
+				isMecanimExpanded = EditorGUILayout.Foldout(isMecanimExpanded, SpineInspectorUtility.TempContent("SkeletonAnimator", SpineInspectorUtility.UnityIcon<SceneAsset>()));
 				if (isMecanimExpanded) {
 					EditorGUI.indentLevel++;
-					EditorGUILayout.PropertyField(controller, SpineInspectorUtility.TempContent("Controller", SpineInspectorUtility.UnityIcon(typeof(Animator))));		
+					EditorGUILayout.PropertyField(controller, SpineInspectorUtility.TempContent("Controller", SpineInspectorUtility.UnityIcon<Animator>()));		
 					if (controller.objectReferenceValue == null) {
 
 						// Generate Mecanim Controller Button

+ 19 - 2
spine-unity/Assets/spine-unity/Editor/SkeletonDebugWindow.cs

@@ -60,6 +60,7 @@ namespace Spine.Unity.Editor {
 		static AnimBool showConstraintsTree = new AnimBool(false);
 		static AnimBool showDrawOrderTree = new AnimBool(false);
 		static AnimBool showEventDataTree = new AnimBool(false);
+		static AnimBool showDataTree = new AnimBool(false);
 		static AnimBool showInspectBoneTree = new AnimBool(false);
 
 		Vector2 scrollPos;
@@ -488,9 +489,25 @@ namespace Spine.Unity.Editor {
 					}
 				}
 
-				// TODO: Data counts. bones, slots, constraints, skins, etc...
+				showDataTree.target = EditorGUILayout.Foldout(showDataTree.target, SpineInspectorUtility.TempContent("Data Counts", Icons.spine), BoldFoldoutStyle);
+				if (showDataTree.faded > 0) {
+					using (new SpineInspectorUtility.IndentScope()) {
+						using (new EditorGUILayout.FadeGroupScope(showDataTree.faded)) {
+							using (new SpineInspectorUtility.LabelWidthScope()) {
+								var skeletonData = skeleton.Data;
+								EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Bones", Icons.bone, "Skeleton.Data.Bones"), new GUIContent(skeletonData.Bones.Count.ToString()));
+								EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Slots", Icons.slotRoot, "Skeleton.Data.Slots"), new GUIContent(skeletonData.Slots.Count.ToString()));
+								EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Skins", Icons.skinsRoot, "Skeleton.Data.Skins"), new GUIContent(skeletonData.Skins.Count.ToString()));
+								EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Events", Icons.userEvent, "Skeleton.Data.Events"), new GUIContent(skeletonData.Events.Count.ToString()));
+								EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("IK Constraints", Icons.constraintIK, "Skeleton.Data.IkConstraints"), new GUIContent(skeletonData.IkConstraints.Count.ToString()));
+								EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Transform Constraints", Icons.constraintTransform, "Skeleton.Data.TransformConstraints"), new GUIContent(skeletonData.TransformConstraints.Count.ToString()));
+								EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Path Constraints", Icons.constraintPath, "Skeleton.Data.PathConstraints"), new GUIContent(skeletonData.PathConstraints.Count.ToString()));
+							}
+						}
+					}
+				}
 
-				if (IsAnimating(showSlotsTree, showSkeleton, showConstraintsTree, showDrawOrderTree, showEventDataTree, showInspectBoneTree))
+				if (IsAnimating(showSlotsTree, showSkeleton, showConstraintsTree, showDrawOrderTree, showEventDataTree, showInspectBoneTree, showDataTree))
 					Repaint();
 			}
 

+ 1 - 1
spine-unity/Assets/spine-unity/Editor/SkeletonRendererInspector.cs

@@ -294,7 +294,7 @@ namespace Spine.Unity.Editor {
 						EditorGUILayout.Space();
 
 						using (new SpineInspectorUtility.LabelWidthScope()) {
-							EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Vertex Data", SpineInspectorUtility.UnityIcon(typeof(MeshFilter))), EditorStyles.boldLabel);
+							EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Vertex Data", SpineInspectorUtility.UnityIcon<MeshFilter>()), EditorStyles.boldLabel);
 							if (pmaVertexColors != null) EditorGUILayout.PropertyField(pmaVertexColors, PMAVertexColorsLabel);
 							EditorGUILayout.PropertyField(tintBlack, TintBlackLabel);
 

+ 58 - 0
spine-unity/Assets/spine-unity/Editor/SpineAttributeDrawers.cs

@@ -245,6 +245,64 @@ namespace Spine.Unity.Editor {
 
 	}
 
+	[CustomPropertyDrawer(typeof(SpineIkConstraint))]
+	public class SpineIkConstraintDrawer : SpineTreeItemDrawerBase<SpineIkConstraint> {
+
+		protected override Texture2D Icon {	get { return SpineEditorUtilities.Icons.constraintIK; } }
+
+		protected override void PopulateMenu (GenericMenu menu, SerializedProperty property, SpineIkConstraint targetAttribute, SkeletonData data) {
+			var constraints = skeletonDataAsset.GetSkeletonData(false).IkConstraints;
+
+			if (TargetAttribute.includeNone)
+				menu.AddItem(new GUIContent(NoneString), 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));
+			}
+		}
+
+	}
+
+	[CustomPropertyDrawer(typeof(SpineTransformConstraint))]
+	public class SpineTransformConstraintDrawer : SpineTreeItemDrawerBase<SpineTransformConstraint> {
+
+		protected override Texture2D Icon {	get { return SpineEditorUtilities.Icons.constraintTransform; } }
+
+		protected override void PopulateMenu (GenericMenu menu, SerializedProperty property, SpineTransformConstraint targetAttribute, SkeletonData data) {
+			var constraints = skeletonDataAsset.GetSkeletonData(false).TransformConstraints;
+
+			if (TargetAttribute.includeNone)
+				menu.AddItem(new GUIContent(NoneString), 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));
+			}
+		}
+	}
+
+	[CustomPropertyDrawer(typeof(SpinePathConstraint))]
+	public class SpinePathConstraintDrawer : SpineTreeItemDrawerBase<SpinePathConstraint> {
+
+		protected override Texture2D Icon {	get { return SpineEditorUtilities.Icons.constraintPath; } }
+
+		protected override void PopulateMenu (GenericMenu menu, SerializedProperty property, SpinePathConstraint targetAttribute, SkeletonData data) {
+			var constraints = skeletonDataAsset.GetSkeletonData(false).PathConstraints;
+
+			if (TargetAttribute.includeNone)
+				menu.AddItem(new GUIContent(NoneString), 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));
+			}
+		}
+	}
+
 	[CustomPropertyDrawer(typeof(SpineAttachment))]
 	public class SpineAttachmentDrawer : SpineTreeItemDrawerBase<SpineAttachment> {
 

+ 2 - 2
spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs

@@ -82,7 +82,7 @@ namespace Spine.Unity.Editor {
 
 			public static Texture2D info;
 
-//			public static Texture2D unityIcon;
+			public static Texture2D unity;
 //			public static Texture2D controllerIcon;
 
 			public static void Initialize () {
@@ -120,7 +120,7 @@ namespace Spine.Unity.Editor {
 				path = (Texture2D)AssetDatabase.LoadMainAssetAtPath(SpineEditorUtilities.editorGUIPath + "/icon-path.png");
 
 				info = EditorGUIUtility.FindTexture("console.infoicon.sml");
-//				unityIcon = EditorGUIUtility.FindTexture("SceneAsset Icon");
+				unity = EditorGUIUtility.FindTexture("SceneAsset Icon");
 //				controllerIcon = EditorGUIUtility.FindTexture("AnimatorController Icon");
 			}
 

+ 5 - 1
spine-unity/Assets/spine-unity/Editor/SpineInspectorUtility.cs

@@ -75,7 +75,11 @@ namespace Spine.Unity.Editor {
 			return current.type == EventType.ValidateCommand && current.commandName == "UndoRedoPerformed";
 		}
 
-		public static Texture2D UnityIcon (System.Type type) {
+		public static Texture2D UnityIcon<T>() {
+			return EditorGUIUtility.ObjectContent(null, typeof(T)).image as Texture2D;
+		}
+
+		public static Texture2D UnityIcon(System.Type type) {
 			return EditorGUIUtility.ObjectContent(null, type).image as Texture2D;
 		}
 

+ 4 - 0
spine-unity/Assets/spine-unity/Mesh Generation/DoubleBuffered.cs

@@ -34,6 +34,10 @@ namespace Spine.Unity {
 		readonly T b = new T();
 		bool usingA;
 
+		public T GetCurrent () {
+			return usingA ? a : b;
+		}
+
 		public T GetNext () {
 			usingA = !usingA;
 			return usingA ? a : b;

+ 11 - 28
spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/Editor/SkeletonGraphicInspector.cs

@@ -113,7 +113,17 @@ namespace Spine.Unity.Editor {
 		[MenuItem("CONTEXT/SkeletonGraphic/Match RectTransform with Mesh Bounds")]
 		static void MatchRectTransformWithBounds (MenuCommand command) {
 			var skeletonGraphic = (SkeletonGraphic)command.context;
-			var mesh = skeletonGraphic.GetComponent<MeshFilter>().sharedMesh;
+			Mesh mesh = skeletonGraphic.GetLastMesh();
+			if (mesh == null) {
+				Debug.Log("Mesh was not previously generated.");
+				return;
+			}
+
+			if (mesh.vertexCount == 0) {
+				skeletonGraphic.rectTransform.sizeDelta = new Vector2(50f, 50f);
+				skeletonGraphic.rectTransform.pivot = new Vector2(0.5f, 0.5f);
+				return;
+			}
 
 			mesh.RecalculateBounds();
 			var bounds = mesh.bounds;
@@ -143,33 +153,6 @@ namespace Spine.Unity.Editor {
 			EditorGUIUtility.PingObject(Selection.activeObject);
 		}
 
-//		[MenuItem("Assets/Spine/Instantiate (UnityUI)", false, 20)]
-//		static void InstantiateSkeletonGraphic () {
-//			Object[] arr = Selection.objects;
-//			foreach (Object o in arr) {
-//				string guid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(o));
-//				string skinName = EditorPrefs.GetString(guid + "_lastSkin", "");
-//
-//				InstantiateSkeletonGraphic((SkeletonDataAsset)o, skinName);
-//				SceneView.RepaintAll();
-//			}
-//		}
-//
-//		[MenuItem("Assets/Spine/Instantiate (UnityUI)", true, 20)]
-//		static bool ValidateInstantiateSkeletonGraphic () {
-//			Object[] arr = Selection.objects;
-//
-//			if (arr.Length == 0)
-//				return false;
-//
-//			foreach (var selected in arr) {
-//				if (selected.GetType() != typeof(SkeletonDataAsset))
-//					return false;
-//			}
-//
-//			return true;
-//		}
-
 		// SpineEditorUtilities.InstantiateDelegate. Used by drag and drop.
 		public static Component SpawnSkeletonGraphicFromDrop (SkeletonDataAsset data) {
 			return InstantiateSkeletonGraphic(data);

+ 16 - 0
spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/SkeletonGraphic.cs

@@ -67,6 +67,18 @@ namespace Spine.Unity {
 						Debug.LogError("Unity UI does not support multiple textures per Renderer. Your skeleton will not be rendered correctly. Recommend using SkeletonAnimation instead. This requires the use of a Screen space camera canvas.");
 				} else {
 					if (freeze) return;
+
+					if (!string.IsNullOrEmpty(initialSkinName)) {
+						var skin = skeleton.data.FindSkin(initialSkinName);
+						if (skin != null) {
+							if (skin == skeleton.data.defaultSkin)
+								skeleton.SetSkin((Skin)null);
+							else
+								skeleton.SetSkin(skin);
+						}
+							
+					}
+
 					skeleton.SetToSetupPose();
 					if (!string.IsNullOrEmpty(startingAnimation))
 						skeleton.PoseWithAnimation(startingAnimation, 0f, false);
@@ -171,6 +183,10 @@ namespace Spine.Unity {
 		DoubleBuffered<Spine.Unity.MeshRendererBuffers.SmartMesh> meshBuffers;
 		SkeletonRendererInstruction currentInstructions = new SkeletonRendererInstruction();
 
+		public Mesh GetLastMesh () {
+			return meshBuffers.GetCurrent().mesh;
+		}
+
 		public event UpdateBonesDelegate UpdateLocal;
 		public event UpdateBonesDelegate UpdateWorld;
 		public event UpdateBonesDelegate UpdateComplete;