more attributes

more bug fixes
more helper menus
even more examples
This commit is contained in:
Fenrisul 2015-01-23 00:01:32 -08:00
parent 444a536dad
commit d60bc9241c
18 changed files with 620 additions and 86 deletions

View File

@ -71,17 +71,17 @@ public class BasicPlatformerController : MonoBehaviour {
#if UNITY_4_5
[Header("Animation")]
#endif
[SpineAnimation(dataSource: "skeletonAnimation")]
[SpineAnimation(dataField: "skeletonAnimation")]
public string walkName = "Walk";
[SpineAnimation(dataSource: "skeletonAnimation")]
[SpineAnimation(dataField: "skeletonAnimation")]
public string runName = "Run";
[SpineAnimation(dataSource: "skeletonAnimation")]
[SpineAnimation(dataField: "skeletonAnimation")]
public string idleName = "Idle";
[SpineAnimation(dataSource: "skeletonAnimation")]
[SpineAnimation(dataField: "skeletonAnimation")]
public string jumpName = "Jump";
[SpineAnimation(dataSource: "skeletonAnimation")]
[SpineAnimation(dataField: "skeletonAnimation")]
public string fallName = "Fall";
[SpineAnimation(dataSource: "skeletonAnimation")]
[SpineAnimation(dataField: "skeletonAnimation")]
public string crouchName = "Crouch";
#if UNITY_4_5

View File

@ -1,11 +1,45 @@
using UnityEngine;
/******************************************************************************
* Spine Runtimes Software License
* Version 2.1
*
* Copyright (c) 2013, Esoteric Software
* All rights reserved.
*
* You are granted a perpetual, non-exclusive, non-sublicensable and
* non-transferable license to install, execute and perform the Spine Runtimes
* Software (the "Software") solely for internal use. Without the written
* permission of Esoteric Software (typically granted by licensing Spine), you
* may not (a) modify, translate, adapt or otherwise create derivative works,
* improvements of the Software or develop new applications using the Software
* 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 SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) 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.
*****************************************************************************/
/*****************************************************************************
* Basic Platformer Controller created by Mitch Thompson
* Full irrevocable rights and permissions granted to Esoteric Software
*****************************************************************************/
using UnityEngine;
using System.Collections;
public class Chimera : MonoBehaviour {
public SkeletonDataAsset skeletonDataSource;
[SpineAttachment(currentSkinOnly: false, returnFullPath: true, dataSource: "skeletonDataSource")]
[SpineAttachment(currentSkinOnly: false, returnAttachmentPath: true, dataField: "skeletonDataSource")]
public string attachmentPath;
[SpineSlot]

View File

@ -0,0 +1,66 @@
using UnityEngine;
using System.Collections;
public class DynamicSpineBone : MonoBehaviour {
public Transform speedReference;
[SpineBone]
public string boneName;
[Range(-90, 90)]
public float minRotation = -45;
[Range(-90, 90)]
public float maxRotation = 45;
[Range(-2000, 2000)]
public float rotationFactor = 300;
[Range(5, 30)]
public float returnSpeed = 10;
[Range(100, 1000)]
public float boneSpeed = 300;
public float returnThreshhold = 0.01f;
public bool useAcceleration;
SkeletonAnimation skeletonAnimation;
float goalRotation;
Spine.Bone bone;
Vector3 velocity;
Vector3 acceleration;
Vector3 lastPosition;
void Start() {
if (speedReference == null)
speedReference = transform;
skeletonAnimation = GetComponent<SkeletonAnimation>();
bone = SpineBone.GetBone(boneName, skeletonAnimation);
skeletonAnimation.UpdateLocal += UpdateLocal;
lastPosition = speedReference.position;
}
void FixedUpdate() {
acceleration = (speedReference.position - lastPosition) - velocity;
velocity = speedReference.position - lastPosition;
lastPosition = speedReference.position;
}
void UpdateLocal(SkeletonAnimation animation) {
Vector3 vec = useAcceleration ? acceleration : velocity;
if (Mathf.Abs(vec.x) < returnThreshhold)
goalRotation = Mathf.Lerp(goalRotation, 0, returnSpeed * Time.deltaTime);
else
goalRotation += vec.x * rotationFactor * Time.deltaTime * (bone.WorldFlipX ? -1 : 1);
goalRotation = Mathf.Clamp(goalRotation, minRotation, maxRotation);
bone.Rotation = Mathf.Lerp(bone.Rotation, bone.Rotation + goalRotation, boneSpeed * Time.deltaTime);
}
}

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 7dae3f4db9a24bf4abe2059526bfd689
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@ -1,4 +1,38 @@
using UnityEngine;
/******************************************************************************
* Spine Runtimes Software License
* Version 2.1
*
* Copyright (c) 2013, Esoteric Software
* All rights reserved.
*
* You are granted a perpetual, non-exclusive, non-sublicensable and
* non-transferable license to install, execute and perform the Spine Runtimes
* Software (the "Software") solely for internal use. Without the written
* permission of Esoteric Software (typically granted by licensing Spine), you
* may not (a) modify, translate, adapt or otherwise create derivative works,
* improvements of the Software or develop new applications using the Software
* 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 SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) 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.
*****************************************************************************/
/*****************************************************************************
* FootSoldierExample created by Mitch Thompson
* Full irrevocable rights and permissions granted to Esoteric Software
*****************************************************************************/
using UnityEngine;
using System.Collections;
public class FootSoldierExample : MonoBehaviour {
@ -11,10 +45,10 @@ public class FootSoldierExample : MonoBehaviour {
[SpineSlot]
public string eyesSlot;
[SpineAttachment(currentSkinOnly: true, slot: "eyesSlot")]
[SpineAttachment(currentSkinOnly: true, slotField: "eyesSlot")]
public string eyesOpenAttachment;
[SpineAttachment(currentSkinOnly: true, slot: "eyesSlot")]
[SpineAttachment(currentSkinOnly: true, slotField: "eyesSlot")]
public string blinkAttachment;
[Range(0, 0.2f)]

View File

@ -1,4 +1,38 @@
using UnityEngine;
/******************************************************************************
* Spine Runtimes Software License
* Version 2.1
*
* Copyright (c) 2013, Esoteric Software
* All rights reserved.
*
* You are granted a perpetual, non-exclusive, non-sublicensable and
* non-transferable license to install, execute and perform the Spine Runtimes
* Software (the "Software") solely for internal use. Without the written
* permission of Esoteric Software (typically granted by licensing Spine), you
* may not (a) modify, translate, adapt or otherwise create derivative works,
* improvements of the Software or develop new applications using the Software
* 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 SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) 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.
*****************************************************************************/
/*****************************************************************************
* SpineboyController created by Mitch Thompson
* Full irrevocable rights and permissions granted to Esoteric Software
*****************************************************************************/
using UnityEngine;
using System.Collections;
[RequireComponent(typeof(SkeletonAnimation), typeof(Rigidbody2D))]

View File

@ -0,0 +1,36 @@
using UnityEngine;
using System.Collections;
using Spine;
public class CustomSkin : MonoBehaviour {
[System.Serializable]
public class SkinPair {
[SpineAttachment(currentSkinOnly: false, returnAttachmentPath: true, dataField: "skinSource")]
public string sourceAttachment;
[SpineSlot]
public string targetSlot;
[SpineAttachment(currentSkinOnly: true, placeholdersOnly: true)]
public string targetAttachment;
}
public SkeletonDataAsset skinSource;
public SkinPair[] skinning;
public Skin customSkin;
SkeletonRenderer skeletonRenderer;
void Start() {
skeletonRenderer = GetComponent<SkeletonRenderer>();
Skeleton skeleton = skeletonRenderer.skeleton;
customSkin = new Skin("CustomSkin");
foreach (var pair in skinning) {
var attachment = SpineAttachment.GetAttachment(pair.sourceAttachment, skinSource);
customSkin.AddAttachment(skeleton.FindSlotIndex(pair.targetSlot), pair.targetAttachment, attachment);
}
skeleton.SetSkin(customSkin);
}
}

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6e55c8477eccddc4cb5c3551a3945ca7
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@ -50,9 +50,27 @@ public class AtlasAssetInspector : Editor {
serializedObject.Update();
AtlasAsset asset = (AtlasAsset)target;
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(atlasFile);
EditorGUILayout.PropertyField(materials, true);
if (EditorGUI.EndChangeCheck())
serializedObject.ApplyModifiedProperties();
if (materials.arraySize == 0) {
EditorGUILayout.LabelField(new GUIContent("Error: Missing materials", SpineEditorUtilities.Icons.warning));
return;
}
for (int i = 0; i < materials.arraySize; i++) {
SerializedProperty prop = materials.GetArrayElementAtIndex(i);
Material mat = (Material)prop.objectReferenceValue;
if (mat == null) {
EditorGUILayout.LabelField(new GUIContent("Error: Materials cannot be null", SpineEditorUtilities.Icons.warning));
return;
}
}
if (atlasFile.objectReferenceValue != null) {
Atlas atlas = asset.GetAtlas();

View File

@ -21,7 +21,7 @@ TextureImporter:
grayScaleToAlpha: 0
generateCubemap: 0
seamlessCubemap: 0
textureFormat: -1
textureFormat: -3
maxTextureSize: 1024
textureSettings:
filterMode: -1

View File

@ -102,12 +102,18 @@ public class SkeletonDataAssetInspector : Editor {
EditorGUILayout.PropertyField(skeletonJSON);
EditorGUILayout.PropertyField(scale);
if (EditorGUI.EndChangeCheck()) {
if (m_previewUtility != null) {
m_previewUtility.Cleanup();
m_previewUtility = null;
}
if (serializedObject.ApplyModifiedProperties()) {
RepopulateWarnings();
if (m_previewUtility != null) {
m_previewUtility.Cleanup();
m_previewUtility = null;
}
RepopulateWarnings();
OnEnable();
return;
}
}
@ -118,6 +124,8 @@ public class SkeletonDataAssetInspector : Editor {
DrawSlotList();
} else {
DrawReimportButton();
//Show Warnings
foreach (var str in warnings)
EditorGUILayout.LabelField(new GUIContent(str, SpineEditorUtilities.Icons.warning));
@ -132,6 +140,24 @@ public class SkeletonDataAssetInspector : Editor {
}
}
void DrawReimportButton() {
EditorGUI.BeginDisabledGroup(skeletonJSON.objectReferenceValue == null);
if (GUILayout.Button(new GUIContent("Attempt Reimport", SpineEditorUtilities.Icons.warning))) {
SpineEditorUtilities.ImportSpineContent(new string[] { AssetDatabase.GetAssetPath(skeletonJSON.objectReferenceValue) }, true);
if (m_previewUtility != null) {
m_previewUtility.Cleanup();
m_previewUtility = null;
}
RepopulateWarnings();
OnEnable();
return;
}
EditorGUI.EndDisabledGroup();
}
void DrawAnimationStateInfo() {
showAnimationStateData = EditorGUILayout.Foldout(showAnimationStateData, "Animation State Data");
if (!showAnimationStateData)

View File

@ -1,4 +1,38 @@
using UnityEngine;
/******************************************************************************
* Spine Runtimes Software License
* Version 2.1
*
* Copyright (c) 2013, Esoteric Software
* All rights reserved.
*
* You are granted a perpetual, non-exclusive, non-sublicensable and
* non-transferable license to install, execute and perform the Spine Runtimes
* Software (the "Software") solely for internal use. Without the written
* permission of Esoteric Software (typically granted by licensing Spine), you
* may not (a) modify, translate, adapt or otherwise create derivative works,
* improvements of the Software or develop new applications using the Software
* 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 SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) 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.
*****************************************************************************/
/*****************************************************************************
* Spine Attribute Drawers created by Mitch Thompson
* Full irrevocable rights and permissions granted to Esoteric Software
*****************************************************************************/
using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;
@ -32,13 +66,13 @@ public class SpineSlotDrawer : PropertyDrawer {
SpineSlot attrib = (SpineSlot)attribute;
var skeletonDataAssetProperty = property.serializedObject.FindProperty(attrib.dataSource);
var dataProperty = property.serializedObject.FindProperty(attrib.dataField);
if (skeletonDataAssetProperty != null) {
if (skeletonDataAssetProperty.objectReferenceValue is SkeletonDataAsset) {
skeletonDataAsset = (SkeletonDataAsset)skeletonDataAssetProperty.objectReferenceValue;
} else if (skeletonDataAssetProperty.objectReferenceValue is SkeletonRenderer) {
var renderer = (SkeletonRenderer)skeletonDataAssetProperty.objectReferenceValue;
if (dataProperty != null) {
if (dataProperty.objectReferenceValue is SkeletonDataAsset) {
skeletonDataAsset = (SkeletonDataAsset)dataProperty.objectReferenceValue;
} else if (dataProperty.objectReferenceValue is SkeletonRenderer) {
var renderer = (SkeletonRenderer)dataProperty.objectReferenceValue;
if (renderer != null)
skeletonDataAsset = renderer.skeletonDataAsset;
} else {
@ -102,7 +136,6 @@ public class SpineSlotDrawer : PropertyDrawer {
public class SpineSkinDrawer : PropertyDrawer {
SkeletonDataAsset skeletonDataAsset;
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
if (property.propertyType != SerializedPropertyType.String) {
EditorGUI.LabelField(position, "ERROR:", "May only apply to type string");
@ -111,13 +144,13 @@ public class SpineSkinDrawer : PropertyDrawer {
SpineSkin attrib = (SpineSkin)attribute;
var skeletonDataAssetProperty = property.serializedObject.FindProperty(attrib.dataSource);
var dataProperty = property.serializedObject.FindProperty(attrib.dataField);
if (skeletonDataAssetProperty != null) {
if (skeletonDataAssetProperty.objectReferenceValue is SkeletonDataAsset) {
skeletonDataAsset = (SkeletonDataAsset)skeletonDataAssetProperty.objectReferenceValue;
} else if (skeletonDataAssetProperty.objectReferenceValue is SkeletonRenderer) {
var renderer = (SkeletonRenderer)skeletonDataAssetProperty.objectReferenceValue;
if (dataProperty != null) {
if (dataProperty.objectReferenceValue is SkeletonDataAsset) {
skeletonDataAsset = (SkeletonDataAsset)dataProperty.objectReferenceValue;
} else if (dataProperty.objectReferenceValue is SkeletonRenderer) {
var renderer = (SkeletonRenderer)dataProperty.objectReferenceValue;
if (renderer != null)
skeletonDataAsset = renderer.skeletonDataAsset;
} else {
@ -256,13 +289,13 @@ public class SpineAnimationDrawer : PropertyDrawer {
SpineAnimation attrib = (SpineAnimation)attribute;
var skeletonDataAssetProperty = property.serializedObject.FindProperty(attrib.dataSource);
var dataProperty = property.serializedObject.FindProperty(attrib.dataField);
if (skeletonDataAssetProperty != null) {
if (skeletonDataAssetProperty.objectReferenceValue is SkeletonDataAsset) {
skeletonDataAsset = (SkeletonDataAsset)skeletonDataAssetProperty.objectReferenceValue;
} else if (skeletonDataAssetProperty.objectReferenceValue is SkeletonRenderer) {
var renderer = (SkeletonRenderer)skeletonDataAssetProperty.objectReferenceValue;
if (dataProperty != null) {
if (dataProperty.objectReferenceValue is SkeletonDataAsset) {
skeletonDataAsset = (SkeletonDataAsset)dataProperty.objectReferenceValue;
} else if (dataProperty.objectReferenceValue is SkeletonRenderer) {
var renderer = (SkeletonRenderer)dataProperty.objectReferenceValue;
if (renderer != null)
skeletonDataAsset = renderer.skeletonDataAsset;
} else {
@ -332,13 +365,13 @@ public class SpineAttachmentDrawer : PropertyDrawer {
SpineAttachment attrib = (SpineAttachment)attribute;
var skeletonDataAssetProperty = property.serializedObject.FindProperty(attrib.dataSource);
var dataProperty = property.serializedObject.FindProperty(attrib.dataField);
if (skeletonDataAssetProperty != null) {
if (skeletonDataAssetProperty.objectReferenceValue is SkeletonDataAsset) {
skeletonDataAsset = (SkeletonDataAsset)skeletonDataAssetProperty.objectReferenceValue;
} else if (skeletonDataAssetProperty.objectReferenceValue is SkeletonRenderer) {
var renderer = (SkeletonRenderer)skeletonDataAssetProperty.objectReferenceValue;
if (dataProperty != null) {
if (dataProperty.objectReferenceValue is SkeletonDataAsset) {
skeletonDataAsset = (SkeletonDataAsset)dataProperty.objectReferenceValue;
} else if (dataProperty.objectReferenceValue is SkeletonRenderer) {
var renderer = (SkeletonRenderer)dataProperty.objectReferenceValue;
if (renderer != null)
skeletonDataAsset = renderer.skeletonDataAsset;
else {
@ -381,8 +414,11 @@ public class SpineAttachmentDrawer : PropertyDrawer {
List<Skin> validSkins = new List<Skin>();
if (skeletonRenderer != null && attrib.currentSkinOnly) {
if (skeletonRenderer.skeleton.Skin != null)
if (skeletonRenderer.skeleton.Skin != null) {
validSkins.Add(skeletonRenderer.skeleton.Skin);
} else {
validSkins.Add(data.Skins[0]);
}
} else {
foreach (Skin skin in data.Skins) {
if (skin != null)
@ -392,6 +428,8 @@ public class SpineAttachmentDrawer : PropertyDrawer {
GenericMenu menu = new GenericMenu();
List<string> attachmentNames = new List<string>();
List<string> placeholderNames = new List<string>();
string prefix = "";
if (skeletonRenderer != null && attrib.currentSkinOnly)
@ -405,7 +443,7 @@ public class SpineAttachmentDrawer : PropertyDrawer {
Skin defaultSkin = data.Skins[0];
SerializedProperty slotProperty = property.serializedObject.FindProperty(attrib.slotSource);
SerializedProperty slotProperty = property.serializedObject.FindProperty(attrib.slotField);
string slotMatch = "";
if (slotProperty != null) {
if (slotProperty.propertyType == SerializedPropertyType.String) {
@ -424,18 +462,31 @@ public class SpineAttachmentDrawer : PropertyDrawer {
continue;
attachmentNames.Clear();
placeholderNames.Clear();
skin.FindNamesForSlot(i, attachmentNames);
if (skin != defaultSkin)
if (skin != defaultSkin) {
defaultSkin.FindNamesForSlot(i, attachmentNames);
skin.FindNamesForSlot(i, placeholderNames);
}
for (int a = 0; a < attachmentNames.Count; a++) {
string attachmentPath = attachmentNames[a];
string menuPath = prefix + data.Slots[i].Name + "/" + attachmentPath;
string name = attachmentNames[a];
if (attrib.returnFullPath)
if (attrib.returnAttachmentPath)
name = skin.Name + "/" + data.Slots[i].Name + "/" + attachmentPath;
menu.AddItem(new GUIContent(menuPath), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property));
if (attrib.placeholdersOnly && placeholderNames.Contains(attachmentPath) == false) {
menu.AddDisabledItem(new GUIContent(menuPath));
} else {
menu.AddItem(new GUIContent(menuPath), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property));
}
}
}
}
@ -454,3 +505,81 @@ public class SpineAttachmentDrawer : PropertyDrawer {
return 18;
}
}
[CustomPropertyDrawer(typeof(SpineBone))]
public class SpineBoneDrawer : PropertyDrawer {
SkeletonDataAsset skeletonDataAsset;
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
if (property.propertyType != SerializedPropertyType.String) {
EditorGUI.LabelField(position, "ERROR:", "May only apply to type string");
return;
}
SpineBone attrib = (SpineBone)attribute;
var dataProperty = property.serializedObject.FindProperty(attrib.dataField);
if (dataProperty != null) {
if (dataProperty.objectReferenceValue is SkeletonDataAsset) {
skeletonDataAsset = (SkeletonDataAsset)dataProperty.objectReferenceValue;
} else if (dataProperty.objectReferenceValue is SkeletonRenderer) {
var renderer = (SkeletonRenderer)dataProperty.objectReferenceValue;
if (renderer != null)
skeletonDataAsset = renderer.skeletonDataAsset;
} else {
EditorGUI.LabelField(position, "ERROR:", "Invalid reference type");
return;
}
} else if (property.serializedObject.targetObject is Component) {
var component = (Component)property.serializedObject.targetObject;
if (component.GetComponent<SkeletonRenderer>() != null) {
var skeletonRenderer = component.GetComponent<SkeletonRenderer>();
skeletonDataAsset = skeletonRenderer.skeletonDataAsset;
}
}
if (skeletonDataAsset == null) {
EditorGUI.LabelField(position, "ERROR:", "Must have reference to a SkeletonDataAsset");
return;
}
position = EditorGUI.PrefixLabel(position, label);
if (GUI.Button(position, property.stringValue, EditorStyles.popup)) {
Selector(property);
}
}
void Selector(SerializedProperty property) {
SpineBone attrib = (SpineBone)attribute;
SkeletonData data = skeletonDataAsset.GetSkeletonData(true);
if (data == null)
return;
GenericMenu menu = new GenericMenu();
menu.AddDisabledItem(new GUIContent(skeletonDataAsset.name));
menu.AddSeparator("");
for (int i = 0; i < data.Bones.Count; i++) {
string name = data.Bones[i].Name;
if (name.StartsWith(attrib.startsWith))
menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property));
}
menu.ShowAsContext();
}
void HandleSelect(object val) {
var pair = (SpineDrawerValuePair)val;
pair.property.stringValue = pair.str;
pair.property.serializedObject.ApplyModifiedProperties();
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label) {
return 18;
}
}

View File

@ -209,8 +209,10 @@ public class SpineEditorUtilities : AssetPostprocessor {
}
static void OnPostprocessAllAssets(string[] imported, string[] deleted, string[] moved, string[] movedFromAssetPaths) {
ImportSpineContent(imported, false);
}
public static void ImportSpineContent(string[] imported, bool reimport = false) {
List<string> atlasPaths = new List<string>();
List<string> imagePaths = new List<string>();
@ -242,6 +244,9 @@ public class SpineEditorUtilities : AssetPostprocessor {
//import atlases first
foreach (string ap in atlasPaths) {
if (!reimport && CheckForValidAtlas(ap))
continue;
TextAsset atlasText = (TextAsset)AssetDatabase.LoadAssetAtPath(ap, typeof(TextAsset));
AtlasAsset atlas = IngestSpineAtlas(atlasText);
atlases.Add(atlas);
@ -250,7 +255,14 @@ public class SpineEditorUtilities : AssetPostprocessor {
//import skeletons and match them with atlases
bool abortSkeletonImport = false;
foreach (string sp in skeletonPaths) {
if (!reimport && CheckForValidSkeletonData(sp)) {
Debug.Log("Automatically skipping: " + sp);
continue;
}
string dir = Path.GetDirectoryName(sp);
var localAtlases = FindAtlasesAtPath(dir);
var requiredPaths = GetRequiredAtlasRegions(sp);
var atlasMatch = GetMatchingAtlas(requiredPaths, localAtlases);
@ -307,6 +319,48 @@ public class SpineEditorUtilities : AssetPostprocessor {
//TODO: any post processing of images
}
static bool CheckForValidSkeletonData(string skeletonJSONPath) {
string dir = Path.GetDirectoryName(skeletonJSONPath);
TextAsset textAsset = (TextAsset)AssetDatabase.LoadAssetAtPath(skeletonJSONPath, typeof(TextAsset));
DirectoryInfo dirInfo = new DirectoryInfo(dir);
FileInfo[] files = dirInfo.GetFiles("*.asset");
foreach (var f in files) {
string localPath = dir + "/" + f.Name;
var obj = AssetDatabase.LoadAssetAtPath(localPath, typeof(Object));
if (obj is SkeletonDataAsset) {
var skeletonDataAsset = (SkeletonDataAsset)obj;
if (skeletonDataAsset.skeletonJSON == textAsset)
return true;
}
}
return false;
}
static bool CheckForValidAtlas(string atlasPath) {
string dir = Path.GetDirectoryName(atlasPath);
TextAsset textAsset = (TextAsset)AssetDatabase.LoadAssetAtPath(atlasPath, typeof(TextAsset));
DirectoryInfo dirInfo = new DirectoryInfo(dir);
FileInfo[] files = dirInfo.GetFiles("*.asset");
foreach (var f in files) {
string localPath = dir + "/" + f.Name;
var obj = AssetDatabase.LoadAssetAtPath(localPath, typeof(Object));
if (obj is AtlasAsset) {
var atlasAsset = (AtlasAsset)obj;
if (atlasAsset.atlasFile == textAsset)
return true;
}
}
return false;
}
static List<AtlasAsset> MultiAtlasDialog(List<string> requiredPaths, string initialDirectory, string header = "") {
List<AtlasAsset> atlasAssets = new List<AtlasAsset>();

View File

@ -1,87 +1,138 @@
using UnityEngine;
/******************************************************************************
* Spine Runtimes Software License
* Version 2.1
*
* Copyright (c) 2013, Esoteric Software
* All rights reserved.
*
* You are granted a perpetual, non-exclusive, non-sublicensable and
* non-transferable license to install, execute and perform the Spine Runtimes
* Software (the "Software") solely for internal use. Without the written
* permission of Esoteric Software (typically granted by licensing Spine), you
* may not (a) modify, translate, adapt or otherwise create derivative works,
* improvements of the Software or develop new applications using the Software
* 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 SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) 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.
*****************************************************************************/
/*****************************************************************************
* Spine Attributes created by Mitch Thompson
* Full irrevocable rights and permissions granted to Esoteric Software
*****************************************************************************/
using UnityEngine;
using System.Collections;
public class SpineSlot : PropertyAttribute {
public string startsWith = "";
public string dataSource = "";
public string dataField = "";
/// <summary>
///
/// Smart popup menu for Spine Slots
/// </summary>
/// <param name="startsWith"></param>
/// <param name="dataSource">SerializedProperty name containing a reference to either a SkeletonRenderer or a SkeletonDataAsset</param>
public SpineSlot(string startsWith = "", string dataSource = "") {
/// <param name="startsWith">Filters popup results to elements that begin with supplied string.</param>
/// <param name="dataField">If specified, a locally scoped field with the name supplied by in dataField will be used to fill the popup results.
/// 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 = "") {
this.startsWith = startsWith;
this.dataSource = dataSource;
this.dataField = dataField;
}
}
public class SpineSkin : PropertyAttribute {
public string startsWith = "";
public string dataSource = "";
public string dataField = "";
/// <summary>
///
/// Smart popup menu for Spine Skins
/// </summary>
/// <param name="startsWith"></param>
/// <param name="dataSource">SerializedProperty name containing a reference to either a SkeletonRenderer or a SkeletonDataAsset</param>
public SpineSkin(string startsWith = "", string dataSource = "") {
/// <param name="startsWith">Filters popup results to elements that begin with supplied string.</param>
/// <param name="dataField">If specified, a locally scoped field with the name supplied by in dataField will be used to fill the popup results.
/// 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 SpineSkin(string startsWith = "", string dataField = "") {
this.startsWith = startsWith;
this.dataSource = dataSource;
this.dataField = dataField;
}
}
public class SpineAtlasRegion : PropertyAttribute {
}
public class SpineAnimation : PropertyAttribute {
public string startsWith = "";
public string dataSource = "";
public string dataField = "";
/// <summary>
///
/// Smart popup menu for Spine Animations
/// </summary>
/// <param name="startsWith"></param>
/// <param name="dataSource">SerializedProperty name containing a reference to either a SkeletonRenderer or a SkeletonDataAsset</param>
public SpineAnimation(string startsWith = "", string dataSource = "") {
/// <param name="startsWith">Filters popup results to elements that begin with supplied string.</param>
/// <param name="dataField">If specified, a locally scoped field with the name supplied by in dataField will be used to fill the popup results.
/// 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 SpineAnimation(string startsWith = "", string dataField = "") {
this.startsWith = startsWith;
this.dataSource = dataSource;
this.dataField = dataField;
}
}
public class SpineAttachment : PropertyAttribute {
public bool returnFullPath;
public bool currentSkinOnly;
public string dataSource = "";
public string slotSource = "";
public bool returnAttachmentPath = false;
public bool currentSkinOnly = false;
public bool placeholdersOnly = false;
public string dataField = "";
public string slotField = "";
public SpineAttachment() {
}
public SpineAttachment(bool currentSkinOnly = true, bool returnFullPath = false, string slot = "", string dataSource = "") {
/// <summary>
/// Smart popup menu for Spine Attachments
/// </summary>
/// <param name="currentSkinOnly">Filters popup results to only include the current Skin. Only valid when a SkeletonRenderer is the data source.</param>
/// <param name="returnAttachmentPath">Returns a fully qualified path for an Attachment in the format "Skin/Slot/AttachmentName"</param>
/// <param name="placeholdersOnly">Filters popup results to exclude attachments that are not children of Skin Placeholders</param>
/// <param name="slotField">If specified, a locally scoped field with the name supplied by in slotField will be used to limit the popup results to children of a named slot</param>
/// <param name="dataField">If specified, a locally scoped field with the name supplied by in dataField will be used to fill the popup results.
/// 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 SpineAttachment(bool currentSkinOnly = true, bool returnAttachmentPath = false, bool placeholdersOnly = false, string slotField = "", string dataField = "") {
this.currentSkinOnly = currentSkinOnly;
this.returnFullPath = returnFullPath;
this.slotSource = slot;
this.dataSource = dataSource;
this.returnAttachmentPath = returnAttachmentPath;
this.placeholdersOnly = placeholdersOnly;
this.slotField = slotField;
this.dataField = dataField;
}
public static Hierarchy GetHierarchy(string fullPath) {
return new Hierarchy(fullPath);
}
public static Spine.Attachment GetAttachment(string fullPath, Spine.SkeletonData skeletonData) {
var hierarchy = SpineAttachment.GetHierarchy(fullPath);
public static Spine.Attachment GetAttachment(string attachmentPath, Spine.SkeletonData skeletonData) {
var hierarchy = SpineAttachment.GetHierarchy(attachmentPath);
if (hierarchy.name == "")
return null;
return skeletonData.FindSkin(hierarchy.skin).GetAttachment(skeletonData.FindSlotIndex(hierarchy.slot), hierarchy.name);
}
public static Spine.Attachment GetAttachment(string fullPath, SkeletonDataAsset skeletonDataAsset) {
return GetAttachment(fullPath, skeletonDataAsset.GetSkeletonData(true));
public static Spine.Attachment GetAttachment(string attachmentPath, SkeletonDataAsset skeletonDataAsset) {
return GetAttachment(attachmentPath, skeletonDataAsset.GetSkeletonData(true));
}
public struct Hierarchy {
@ -108,4 +159,40 @@ public class SpineAttachment : PropertyAttribute {
}
}
}
}
public class SpineBone : PropertyAttribute {
public string startsWith = "";
public string dataField = "";
/// <summary>
/// Smart popup menu for Spine Bones
/// </summary>
/// <param name="startsWith">Filters popup results to elements that begin with supplied string.</param>
/// <param name="dataField">If specified, a locally scoped field with the name supplied by in dataField will be used to fill the popup results.
/// 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 SpineBone(string startsWith = "", string dataField = "") {
this.startsWith = startsWith;
this.dataField = dataField;
}
public static Spine.Bone GetBone(string boneName, SkeletonRenderer renderer) {
if (renderer.skeleton == null)
return null;
return renderer.skeleton.FindBone(boneName);
}
public static Spine.BoneData GetBoneData(string boneName, SkeletonDataAsset skeletonDataAsset) {
var data = skeletonDataAsset.GetSkeletonData(true);
return data.FindBone(boneName);
}
}
public class SpineAtlasRegion : PropertyAttribute {
//TODO: Standardize with Skeleton attributes
//NOTE: For now, relies on locally scoped field named "atlasAsset" for source.
}