Merge pull request #499 from EsotericSoftware/unity-autoreset

[Unity] SkeletonAnimation Update

Built-in, Opt-in, generic Autoreset handling (under the Advanced foldout).
Inspector tooltips.
XML docs for public members.
This commit is contained in:
John 2015-12-30 15:13:56 +08:00
commit da10b70b84
2 changed files with 71 additions and 16 deletions

View File

@ -36,19 +36,20 @@ using Spine;
[CustomEditor(typeof(SkeletonAnimation))]
public class SkeletonAnimationInspector : SkeletonRendererInspector {
protected SerializedProperty animationName, loop, timeScale;
protected bool isPrefab;
protected SerializedProperty animationName, loop, timeScale, autoReset;
protected bool m_isPrefab;
protected GUIContent autoResetLabel;
protected override void OnEnable () {
base.OnEnable();
animationName = serializedObject.FindProperty("_animationName");
loop = serializedObject.FindProperty("loop");
timeScale = serializedObject.FindProperty("timeScale");
autoReset = serializedObject.FindProperty("autoReset");
autoResetLabel = new GUIContent("Generic Auto-reset");
if (PrefabUtility.GetPrefabType(this.target) == PrefabType.Prefab)
isPrefab = true;
m_isPrefab = true;
}
protected override void gui () {
@ -96,11 +97,12 @@ public class SkeletonAnimationInspector : SkeletonRendererInspector {
EditorGUILayout.PropertyField(loop);
EditorGUILayout.PropertyField(timeScale);
EditorGUILayout.PropertyField(autoReset, autoResetLabel);
component.timeScale = Math.Max(component.timeScale, 0);
EditorGUILayout.Space();
if (!isPrefab) {
if (!m_isPrefab) {
if (component.GetComponent<SkeletonUtility>() == null) {
if (GUILayout.Button(new GUIContent("Add Skeleton Utility", SpineEditorUtilities.Icons.skeletonUtility), GUILayout.Height(30))) {
component.gameObject.AddComponent<SkeletonUtility>();

View File

@ -30,7 +30,6 @@
*****************************************************************************/
using System;
using System.IO;
using System.Collections.Generic;
using UnityEngine;
using Spine;
@ -38,12 +37,12 @@ using Spine;
[ExecuteInEditMode]
[AddComponentMenu("Spine/SkeletonAnimation")]
public class SkeletonAnimation : SkeletonRenderer, ISkeletonAnimation {
public float timeScale = 1;
public bool loop;
/// <summary>
/// This is the Spine.AnimationState object of this SkeletonAnimation. You can control animations through it.
/// Note that this object, like .skeleton, is not guaranteed to exist in Awake. Do all accesses and caching to it in Start</summary>
public Spine.AnimationState state;
public event UpdateBonesDelegate UpdateLocal {
add { _UpdateLocal += value; }
remove { _UpdateLocal -= value; }
@ -63,18 +62,21 @@ public class SkeletonAnimation : SkeletonRenderer, ISkeletonAnimation {
protected event UpdateBonesDelegate _UpdateWorld;
protected event UpdateBonesDelegate _UpdateComplete;
// TODO: Make this a safe getter. Lazy-initialize and avoid double-initialization.
public Skeleton Skeleton {
get {
return this.skeleton;
}
get { return this.skeleton; }
}
[SerializeField]
private String
_animationName;
private String _animationName;
public String AnimationName {
get {
if (!valid) {
Debug.LogWarning("You tried access AnimationName but the SkeletonAnimation was not valid. Try checking your Skeleton Data for errors.");
return null;
}
TrackEntry entry = state.GetCurrent(0);
return entry == null ? null : entry.Animation.Name;
}
@ -82,6 +84,12 @@ public class SkeletonAnimation : SkeletonRenderer, ISkeletonAnimation {
if (_animationName == value)
return;
_animationName = value;
if (!valid) {
Debug.LogWarning("You tried to change AnimationName but the SkeletonAnimation was not valid. Try checking your Skeleton Data for errors.");
return;
}
if (value == null || value.Length == 0)
state.ClearTrack(0);
else
@ -89,17 +97,62 @@ public class SkeletonAnimation : SkeletonRenderer, ISkeletonAnimation {
}
}
/// <summary>Whether or not an animation should loop. This only applies to the initial animation specified in the inspector, or any subsequent Animations played through .AnimationName. Animations set through state.SetAnimation are unaffected.</summary>
#if UNITY_5
[Tooltip("Whether or not an animation should loop. This only applies to the initial animation specified in the inspector, or any subsequent Animations played through .AnimationName. Animations set through state.SetAnimation are unaffected.")]
#endif
public bool loop;
/// <summary>
/// The rate at which animations progress over time. 1 means 100%. 0.5 means 50%.
/// AnimationState and TrackEntry also have their own timeScale. These are combined multiplicatively.</summary>
#if UNITY_5
[Tooltip("The rate at which animations progress over time. 1 means 100%. 0.5 means 50%.")]
#endif
public float timeScale = 1;
#if UNITY_5
[Tooltip("Setting this to true makes the SkeletonAnimation behave similar to Spine editor. New animations will not inherit the pose from a previous animation. If you need to intermittently and programmatically pose your skeleton, leave this false.")]
#endif
[SerializeField]
protected bool autoReset = false;
/// <summary>
/// Setting this to true makes the SkeletonAnimation behave similar to Spine editor.
/// New animations will not inherit the pose from a previous animation.
/// If you need to intermittently and programmatically pose your skeleton, leave this false.</summary>
public bool AutoReset {
get { return this.autoReset; }
set {
if (!autoReset && value) {
state.Start -= HandleNewAnimationAutoreset; // make sure there isn't a double-subscription.
state.Start += HandleNewAnimationAutoreset;
}
autoReset = value;
}
}
public override void Reset () {
base.Reset();
if (!valid)
return;
state = new Spine.AnimationState(skeletonDataAsset.GetAnimationStateData());
if (autoReset) {
state.Start += HandleNewAnimationAutoreset;
}
if (_animationName != null && _animationName.Length > 0) {
state.SetAnimation(0, _animationName, loop);
Update(0);
}
}
protected virtual void HandleNewAnimationAutoreset (Spine.AnimationState state, int trackIndex) {
if (!autoReset) return;
if (skeleton != null) skeleton.SetToSetupPose();
}
public virtual void Update () {
Update(Time.deltaTime);