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

This commit is contained in:
pharan 2017-05-22 16:30:52 +08:00
parent 812b78ddd4
commit f18a3cadb2
13 changed files with 216 additions and 39 deletions

View File

@ -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.

View File

@ -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;
}
}
}
}

View File

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

View File

@ -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, " +

View File

@ -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

View File

@ -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();
}

View File

@ -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);

View File

@ -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> {

View File

@ -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");
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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;