This commit is contained in:
badlogic 2019-10-03 16:50:06 +02:00
commit f619a972cb
17 changed files with 301 additions and 42 deletions

View File

@ -37,11 +37,15 @@ namespace Spine {
public class Animation {
internal String name;
internal ExposedList<Timeline> timelines;
internal HashSet<int> timelineIds;
internal float duration;
public Animation (string name, ExposedList<Timeline> timelines, float duration) {
if (name == null) throw new ArgumentNullException("name", "name cannot be null.");
if (timelines == null) throw new ArgumentNullException("timelines", "timelines cannot be null.");
this.timelineIds = new HashSet<int>();
foreach (Timeline timeline in timelines)
timelineIds.Add(timeline.PropertyId);
this.name = name;
this.timelines = timelines;
this.duration = duration;
@ -55,6 +59,11 @@ namespace Spine {
/// <summary>The animation's name, which is unique across all animations in the skeleton.</summary>
public string Name { get { return name; } }
/// <summary>Whether the timeline with the property id is contained in this animation.</summary>
public bool HasTimeline (int id) {
return timelineIds.Contains(id);
}
/// <summary>Applies all the animation's timelines to the specified skeleton.</summary>
/// <seealso cref="Timeline.Apply(Skeleton, float, float, ExposedList, float, MixBlend, MixDirection)"/>
public void Apply (Skeleton skeleton, float lastTime, float time, bool loop, ExposedList<Event> events, float alpha, MixBlend blend,

View File

@ -777,11 +777,11 @@ namespace Spine {
if (!propertyIDs.Add(id))
timelineMode[i] = AnimationState.Subsequent;
else if (to == null || timeline is AttachmentTimeline || timeline is DrawOrderTimeline
|| timeline is EventTimeline || !HasTimeline(to, id)) {
|| timeline is EventTimeline || !to.animation.HasTimeline(id)) {
timelineMode[i] = AnimationState.First;
} else {
for (TrackEntry next = to.mixingTo; next != null; next = next.mixingTo) {
if (HasTimeline(next, id)) continue;
if (next.animation.HasTimeline(id)) continue;
if (next.mixDuration > 0) {
timelineMode[i] = AnimationState.HoldMix;
timelineHoldMix[i] = next;
@ -809,13 +809,6 @@ namespace Spine {
}
}
static bool HasTimeline (TrackEntry entry, int id) {
var timelines = entry.animation.timelines.Items;
for (int i = 0, n = entry.animation.timelines.Count; i < n; i++)
if (timelines[i].PropertyId == id) return true;
return false;
}
/// <returns>The track entry for the animation currently playing on the track, or null if no animation is currently playing.</returns>
public TrackEntry GetCurrent (int trackIndex) {
if (trackIndex >= tracks.Count) return null;

View File

@ -138,6 +138,9 @@ namespace Spine.Unity.Editor {
const string MECANIM_EVENT_INCLUDE_FOLDERNAME_KEY = "SPINE_MECANIM_EVENT_INCLUDE_FOLDERNAME";
public static bool mecanimEventIncludeFolderName = SpinePreferences.DEFAULT_MECANIM_EVENT_INCLUDE_FOLDERNAME;
const string TIMELINE_USE_BLEND_DURATION_KEY = "SPINE_TIMELINE_USE_BLEND_DURATION_KEY";
public static bool timelineUseBlendDuration = SpinePreferences.DEFAULT_TIMELINE_USE_BLEND_DURATION;
static bool preferencesLoaded = false;
public static void Load () {
@ -154,6 +157,7 @@ namespace Spine.Unity.Editor {
mecanimEventIncludeFolderName = EditorPrefs.GetBool(MECANIM_EVENT_INCLUDE_FOLDERNAME_KEY, SpinePreferences.DEFAULT_MECANIM_EVENT_INCLUDE_FOLDERNAME);
atlasTxtImportWarning = EditorPrefs.GetBool(ATLASTXT_WARNING_KEY, SpinePreferences.DEFAULT_ATLASTXT_WARNING);
textureImporterWarning = EditorPrefs.GetBool(TEXTUREIMPORTER_WARNING_KEY, SpinePreferences.DEFAULT_TEXTUREIMPORTER_WARNING);
timelineUseBlendDuration = EditorPrefs.GetBool(TIMELINE_USE_BLEND_DURATION_KEY, SpinePreferences.DEFAULT_TIMELINE_USE_BLEND_DURATION);
SpineHandles.handleScale = EditorPrefs.GetFloat(SCENE_ICONS_SCALE_KEY, DEFAULT_SCENE_ICONS_SCALE);
preferencesLoaded = true;
@ -171,6 +175,7 @@ namespace Spine.Unity.Editor {
newPreferences.mecanimEventIncludeFolderName = EditorPrefs.GetBool(MECANIM_EVENT_INCLUDE_FOLDERNAME_KEY, SpinePreferences.DEFAULT_MECANIM_EVENT_INCLUDE_FOLDERNAME);
newPreferences.atlasTxtImportWarning = EditorPrefs.GetBool(ATLASTXT_WARNING_KEY, SpinePreferences.DEFAULT_ATLASTXT_WARNING);
newPreferences.textureImporterWarning = EditorPrefs.GetBool(TEXTUREIMPORTER_WARNING_KEY, SpinePreferences.DEFAULT_TEXTUREIMPORTER_WARNING);
newPreferences.timelineUseBlendDuration = EditorPrefs.GetBool(TIMELINE_USE_BLEND_DURATION_KEY, SpinePreferences.DEFAULT_TIMELINE_USE_BLEND_DURATION);
}
public static void SaveToEditorPrefs(SpinePreferences preferences) {
@ -184,6 +189,7 @@ namespace Spine.Unity.Editor {
EditorPrefs.SetBool(MECANIM_EVENT_INCLUDE_FOLDERNAME_KEY, preferences.mecanimEventIncludeFolderName);
EditorPrefs.SetBool(ATLASTXT_WARNING_KEY, preferences.atlasTxtImportWarning);
EditorPrefs.SetBool(TEXTUREIMPORTER_WARNING_KEY, preferences.textureImporterWarning);
EditorPrefs.SetBool(TIMELINE_USE_BLEND_DURATION_KEY, preferences.timelineUseBlendDuration);
}
#endif
@ -265,6 +271,12 @@ namespace Spine.Unity.Editor {
if (GUILayout.Button("Disable", GUILayout.Width(64)))
SpineTK2DEditorUtility.DisableTK2D();
}
GUILayout.Space(20);
EditorGUILayout.LabelField("Timeline Extension", EditorStyles.boldLabel);
{
SpineEditorUtilities.BoolPrefsField(ref timelineUseBlendDuration, TIMELINE_USE_BLEND_DURATION_KEY, new GUIContent("Use Blend Duration", "When enabled, MixDuration will be synced with timeline clip transition duration 'Ease In Duration'."));
}
}
#endif // !NEW_PREFERENCES_SETTINGS_PROVIDER
}

View File

@ -184,9 +184,7 @@ namespace Spine.Unity.Editor {
Debug.LogError("Could not export Spine Skeleton because SkeletonDataAsset is null or invalid!");
return;
}
#if !NEW_PREFAB_SYSTEM
if (outputPath == "") {
outputPath = System.IO.Path.GetDirectoryName(AssetDatabase.GetAssetPath(skeletonDataAsset)) + "/Baked";
System.IO.Directory.CreateDirectory(outputPath);
@ -281,7 +279,13 @@ namespace Spine.Unity.Editor {
Object prefab = AssetDatabase.LoadAssetAtPath(prefabPath, typeof(GameObject));
if (prefab == null) {
#if NEW_PREFAB_SYSTEM
GameObject emptyGameObject = new GameObject();
prefab = PrefabUtility.SaveAsPrefabAssetAndConnect(emptyGameObject, prefabPath, InteractionMode.AutomatedAction);
GameObject.DestroyImmediate(emptyGameObject);
#else
prefab = PrefabUtility.CreateEmptyPrefab(prefabPath);
#endif
newPrefab = true;
}
@ -428,14 +432,22 @@ namespace Spine.Unity.Editor {
}
if (newPrefab) {
#if NEW_PREFAB_SYSTEM
PrefabUtility.SaveAsPrefabAssetAndConnect(prefabRoot, prefabPath, InteractionMode.AutomatedAction);
#else
PrefabUtility.ReplacePrefab(prefabRoot, prefab, ReplacePrefabOptions.ConnectToPrefab);
#endif
} else {
foreach (string str in unusedMeshNames) {
Mesh.DestroyImmediate(meshTable[str], true);
}
#if NEW_PREFAB_SYSTEM
PrefabUtility.SaveAsPrefabAssetAndConnect(prefabRoot, prefabPath, InteractionMode.AutomatedAction);
#else
PrefabUtility.ReplacePrefab(prefabRoot, prefab, ReplacePrefabOptions.ReplaceNameBased);
#endif
}
@ -447,8 +459,6 @@ namespace Spine.Unity.Editor {
GameObject.DestroyImmediate(prefabRoot);
}
#endif
}
#region Attachment Baking

View File

@ -27,10 +27,6 @@
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/
#if UNITY_2018_3 || UNITY_2019 || UNITY_2018_3_OR_NEWER
#define NEW_PREFAB_SYSTEM
#endif
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
@ -44,7 +40,6 @@ namespace Spine.Unity.Editor {
public class SkeletonBakingWindow : EditorWindow {
const bool IsUtilityWindow = true;
#if !NEW_PREFAB_SYSTEM
[MenuItem("CONTEXT/SkeletonDataAsset/Skeleton Baking", false, 5000)]
public static void Init (MenuCommand command) {
var window = EditorWindow.GetWindow<SkeletonBakingWindow>(IsUtilityWindow);
@ -54,7 +49,6 @@ namespace Spine.Unity.Editor {
window.skeletonDataAsset = command.context as SkeletonDataAsset;
window.Show();
}
#endif
public SkeletonDataAsset skeletonDataAsset;
[SpineSkin(dataField:"skeletonDataAsset")]

View File

@ -92,6 +92,10 @@ namespace Spine.Unity.Editor {
public const bool DEFAULT_MECANIM_EVENT_INCLUDE_FOLDERNAME = true;
public bool mecanimEventIncludeFolderName = DEFAULT_MECANIM_EVENT_INCLUDE_FOLDERNAME;
// Timeline extension module
public const bool DEFAULT_TIMELINE_USE_BLEND_DURATION = true;
public bool timelineUseBlendDuration = DEFAULT_TIMELINE_USE_BLEND_DURATION;
#if NEW_PREFERENCES_SETTINGS_PROVIDER
public static void Load () {
SpineHandles.handleScale = EditorPrefs.GetFloat(SCENE_ICONS_SCALE_KEY, DEFAULT_SCENE_ICONS_SCALE);
@ -185,6 +189,12 @@ namespace Spine.Unity.Editor {
if (GUILayout.Button("Disable", GUILayout.Width(64)))
SpineEditorUtilities.SpineTK2DEditorUtility.DisableTK2D();
}
GUILayout.Space(20);
EditorGUILayout.LabelField("Timeline Extension", EditorStyles.boldLabel);
{
EditorGUILayout.PropertyField(settings.FindProperty("timelineUseBlendDuration"), new GUIContent("Use Blend Duration", "When enabled, MixDuration will be synced with timeline clip transition duration 'Ease In Duration'."));
}
}
EditorGUIUtility.labelWidth = prevLabelWidth;
}

View File

@ -96,8 +96,11 @@ namespace Spine.Unity {
}
}
set {
if (_animationName == value)
return;
if (_animationName == value) {
TrackEntry entry = state.GetCurrent(0);
if (entry != null && entry.loop == loop)
return;
}
_animationName = value;
if (string.IsNullOrEmpty(value)) {

View File

@ -288,6 +288,8 @@ namespace Spine.Unity {
if (!Application.isPlaying)
Update(0f);
#endif
if (freeze)
Update(0f);
}
}
}

View File

@ -580,7 +580,9 @@ namespace Spine.Unity.AttachmentTools {
static void CopyTextureAttributesFrom(this Texture2D destination, Texture2D source) {
destination.filterMode = source.filterMode;
destination.anisoLevel = source.anisoLevel;
#if UNITY_EDITOR
destination.alphaIsTransparency = source.alphaIsTransparency;
#endif
destination.wrapModeU = source.wrapModeU;
destination.wrapModeV = source.wrapModeV;
destination.wrapModeW = source.wrapModeW;

View File

@ -0,0 +1,116 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated May 1, 2019. Replaces all prior versions.
*
* Copyright (c) 2013-2019, Esoteric Software LLC
*
* Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license
*
* Otherwise, it is permitted to integrate the Spine Runtimes into software
* or otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice.
*
* THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE LLC "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 LLC 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 UnityEditor;
using Spine.Unity.Playables;
using UnityEngine.Timeline;
namespace Spine.Unity.Editor {
[CustomEditor(typeof(SpineAnimationStateClip))]
[CanEditMultipleObjects]
public class SpineAnimationStateClipInspector : UnityEditor.Editor {
protected SerializedProperty templateProp = null;
protected class ClipInfo {
public TimelineClip timelineClip;
public float previousBlendInDuration = -1.0f;
public float unblendedMixDuration = 0.2f;
}
protected ClipInfo[] clipInfo = null;
public void OnEnable () {
templateProp = serializedObject.FindProperty("template");
System.Array.Resize(ref clipInfo, targets.Length);
for (int i = 0; i < targets.Length; ++i) {
var clip = (SpineAnimationStateClip)targets[i];
clipInfo[i] = new ClipInfo();
clipInfo[i].timelineClip = FindTimelineClip(clip);
}
}
public override void OnInspectorGUI () {
serializedObject.Update();
EditorGUILayout.PropertyField(templateProp);
for (int i = 0; i < targets.Length; ++i) {
var targetClip = (SpineAnimationStateClip)targets[i];
if (targetClip.template.useBlendDuration)
AdjustMixDuration(targetClip, clipInfo[i]);
}
serializedObject.ApplyModifiedProperties();
}
protected void AdjustMixDuration(SpineAnimationStateClip targetClip, ClipInfo timelineClipInfo) {
if (timelineClipInfo == null)
return;
var timelineClip = timelineClipInfo.timelineClip;
if (timelineClip == null)
return;
float blendInDur = (float)timelineClip.blendInDuration;
bool isBlendingNow = blendInDur > 0;
bool wasBlendingBefore = timelineClipInfo.previousBlendInDuration > 0;
if (isBlendingNow) {
if (!wasBlendingBefore) {
timelineClipInfo.unblendedMixDuration = targetClip.template.mixDuration;
}
targetClip.template.mixDuration = blendInDur;
EditorUtility.SetDirty(targetClip);
}
else if (wasBlendingBefore) {
targetClip.template.mixDuration = timelineClipInfo.unblendedMixDuration;
EditorUtility.SetDirty(targetClip);
}
timelineClipInfo.previousBlendInDuration = blendInDur;
}
protected TimelineClip FindTimelineClip(SpineAnimationStateClip targetClip) {
string[] guids = AssetDatabase.FindAssets("t:TimelineAsset");
foreach (string guid in guids) {
TimelineAsset timeline = (TimelineAsset)AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(guid), typeof(TimelineAsset));
foreach (var track in timeline.GetOutputTracks()) {
foreach (var clip in track.GetClips()) {
if (clip.asset.GetType() == typeof(SpineAnimationStateClip) && object.ReferenceEquals(clip.asset, targetClip)) {
return clip;
}
}
}
}
return null;
}
}
}

View File

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

View File

@ -32,30 +32,39 @@ using UnityEngine;
using Spine;
using Spine.Unity;
using Spine.Unity.Playables;
using Spine.Unity.Editor;
//[CustomPropertyDrawer(typeof(SpineAnimationStateBehaviour))]
[CustomPropertyDrawer(typeof(SpineAnimationStateBehaviour))]
public class SpineAnimationStateDrawer : PropertyDrawer {
/*
public override float GetPropertyHeight (SerializedProperty property, GUIContent label) {
const int fieldCount = 8;
return fieldCount * EditorGUIUtility.singleLineHeight;
}
public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) {
SerializedProperty skeletonDataAssetProp = property.FindPropertyRelative("skeletonDataAsset");
SerializedProperty animationNameProp = property.FindPropertyRelative("animationName");
SerializedProperty animationReferenceProp = property.FindPropertyRelative("animationReference");
SerializedProperty loopProp = property.FindPropertyRelative("loop");
SerializedProperty customDurationProp = property.FindPropertyRelative("customDuration");
SerializedProperty useBlendDurationProp = property.FindPropertyRelative("useBlendDuration");
SerializedProperty mixDurationProp = property.FindPropertyRelative("mixDuration");
SerializedProperty eventProp = property.FindPropertyRelative("eventThreshold");
SerializedProperty attachmentProp = property.FindPropertyRelative("attachmentThreshold");
SerializedProperty drawOrderProp = property.FindPropertyRelative("drawOrderThreshold");
// initialize useBlendDuration parameter according to preferences
SerializedProperty isInitializedProp = property.FindPropertyRelative("isInitialized");
if (!isInitializedProp.hasMultipleDifferentValues && isInitializedProp.boolValue == false) {
useBlendDurationProp.boolValue = SpineEditorUtilities.Preferences.timelineUseBlendDuration;
isInitializedProp.boolValue = true;
}
Rect singleFieldRect = new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight);
EditorGUI.PropertyField(singleFieldRect, skeletonDataAssetProp);
float lineHeightWithSpacing = EditorGUIUtility.singleLineHeight + 2f;
singleFieldRect.y += lineHeightWithSpacing;
EditorGUI.PropertyField(singleFieldRect, animationNameProp);
EditorGUI.PropertyField(singleFieldRect, animationReferenceProp);
singleFieldRect.y += lineHeightWithSpacing;
EditorGUI.PropertyField(singleFieldRect, loopProp);
@ -65,6 +74,19 @@ public class SpineAnimationStateDrawer : PropertyDrawer {
singleFieldRect.y += lineHeightWithSpacing;
EditorGUI.LabelField(singleFieldRect, "Mixing Settings", EditorStyles.boldLabel);
singleFieldRect.y += lineHeightWithSpacing;
EditorGUI.PropertyField(singleFieldRect, customDurationProp);
bool greyOutCustomDurations = (!customDurationProp.hasMultipleDifferentValues &&
customDurationProp.boolValue == false);
using (new EditorGUI.DisabledGroupScope(greyOutCustomDurations)) {
singleFieldRect.y += lineHeightWithSpacing;
EditorGUI.PropertyField(singleFieldRect, useBlendDurationProp);
singleFieldRect.y += lineHeightWithSpacing;
EditorGUI.PropertyField(singleFieldRect, mixDurationProp);
}
singleFieldRect.y += lineHeightWithSpacing;
EditorGUI.PropertyField(singleFieldRect, eventProp);
@ -74,5 +96,4 @@ public class SpineAnimationStateDrawer : PropertyDrawer {
singleFieldRect.y += lineHeightWithSpacing;
EditorGUI.PropertyField(singleFieldRect, drawOrderProp);
}
*/
}

View File

@ -0,0 +1,51 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated May 1, 2019. Replaces all prior versions.
*
* Copyright (c) 2013-2019, Esoteric Software LLC
*
* Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license
*
* Otherwise, it is permitted to integrate the Spine Runtimes into software
* or otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice.
*
* THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE LLC "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 LLC 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 UnityEditor;
using Spine.Unity.Playables;
namespace Spine.Unity.Editor {
[CustomEditor(typeof(SpineSkeletonFlipClip))]
[CanEditMultipleObjects]
public class SpineSkeletonFlipClipInspector : UnityEditor.Editor {
protected SerializedProperty templateProp = null;
public void OnEnable () {
templateProp = serializedObject.FindProperty("template");
}
public override void OnInspectorGUI () {
serializedObject.Update();
EditorGUILayout.PropertyField(templateProp);
serializedObject.ApplyModifiedProperties();
}
}
}

View File

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

View File

@ -44,8 +44,11 @@ namespace Spine.Unity.Playables {
public AnimationReferenceAsset animationReference;
public bool loop;
[Header("Mix Properties")]
// Mix Properties
public bool customDuration = false;
public bool useBlendDuration = true;
[SerializeField]
private bool isInitialized = false; // required to read preferences values from editor side.
public float mixDuration = 0.1f;
[Range(0, 1f)]

View File

@ -37,13 +37,21 @@ namespace Spine.Unity.Playables {
public class SpineAnimationStateClip : PlayableAsset, ITimelineClipAsset {
public SpineAnimationStateBehaviour template = new SpineAnimationStateBehaviour();
public ClipCaps clipCaps { get { return ClipCaps.None; } }
public ClipCaps clipCaps { get { return ClipCaps.Blending | ClipCaps.ClipIn | ClipCaps.SpeedMultiplier | (template.loop ? ClipCaps.Looping : 0); } }
public override Playable CreatePlayable (PlayableGraph graph, GameObject owner) {
var playable = ScriptPlayable<SpineAnimationStateBehaviour>.Create(graph, template);
playable.GetBehaviour();
return playable;
}
public override double duration {
get {
if (template.animationReference == null)
return 0;
return template.animationReference.Animation.Duration;
}
}
}
}

View File

@ -70,7 +70,7 @@ namespace Spine.Unity.Playables {
for (int i = 0; i < inputCount; i++) {
float lastInputWeight = lastInputWeights[i];
float inputWeight = playable.GetInputWeight(i);
bool trackStarted = inputWeight > lastInputWeight;
bool trackStarted = lastInputWeight == 0 && inputWeight > 0;
lastInputWeights[i] = inputWeight;
if (trackStarted) {
@ -84,9 +84,10 @@ namespace Spine.Unity.Playables {
if (clipData.animationReference.Animation != null) {
Spine.TrackEntry trackEntry = state.SetAnimation(trackIndex, clipData.animationReference.Animation, clipData.loop);
//trackEntry.TrackTime = (float)inputPlayable.GetTime(); // More accurate time-start?
trackEntry.EventThreshold = clipData.eventThreshold;
trackEntry.DrawOrderThreshold = clipData.drawOrderThreshold;
trackEntry.TrackTime = (float)inputPlayable.GetTime() * (float)inputPlayable.GetSpeed();
trackEntry.TimeScale = (float)inputPlayable.GetSpeed();
trackEntry.AttachmentThreshold = clipData.attachmentThreshold;
if (clipData.customDuration)
@ -111,15 +112,15 @@ namespace Spine.Unity.Playables {
if (spineComponent == null) return;
int inputCount = playable.GetInputCount();
int lastOneWeight = -1;
int lastNonZeroWeightTrack = -1;
for (int i = 0; i < inputCount; i++) {
float inputWeight = playable.GetInputWeight(i);
if (inputWeight >= 1) lastOneWeight = i;
if (inputWeight > 0) lastNonZeroWeightTrack = i;
}
if (lastOneWeight != -1) {
ScriptPlayable<SpineAnimationStateBehaviour> inputPlayableClip = (ScriptPlayable<SpineAnimationStateBehaviour>)playable.GetInput(lastOneWeight);
if (lastNonZeroWeightTrack != -1) {
ScriptPlayable<SpineAnimationStateBehaviour> inputPlayableClip = (ScriptPlayable<SpineAnimationStateBehaviour>)playable.GetInput(lastNonZeroWeightTrack);
SpineAnimationStateBehaviour clipData = inputPlayableClip.GetBehaviour();
var skeleton = spineComponent.Skeleton;
@ -133,16 +134,16 @@ namespace Spine.Unity.Playables {
Animation fromAnimation = null;
float fromClipTime = 0;
bool fromClipLoop = false;
if (lastOneWeight != 0 && inputCount > 1) {
var fromClip = (ScriptPlayable<SpineAnimationStateBehaviour>)playable.GetInput(lastOneWeight - 1);
if (lastNonZeroWeightTrack != 0 && inputCount > 1) {
var fromClip = (ScriptPlayable<SpineAnimationStateBehaviour>)playable.GetInput(lastNonZeroWeightTrack - 1);
var fromClipData = fromClip.GetBehaviour();
fromAnimation = fromClipData.animationReference != null ? fromClipData.animationReference.Animation : null;
fromClipTime = (float)fromClip.GetTime();
fromClipTime = (float)fromClip.GetTime() * (float)fromClip.GetSpeed();
fromClipLoop = fromClipData.loop;
}
Animation toAnimation = clipData.animationReference != null ? clipData.animationReference.Animation : null;
float toClipTime = (float)inputPlayableClip.GetTime();
float toClipTime = (float)inputPlayableClip.GetTime() * (float)inputPlayableClip.GetSpeed();
float mixDuration = clipData.mixDuration;
if (!clipData.customDuration && fromAnimation != null && toAnimation != null) {