diff --git a/CHANGELOG.md b/CHANGELOG.md index c0b1cdf57..72e4e19d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -83,8 +83,13 @@ * Timeline clips now offer an additional `Alpha` parameter for setting a custom constant mix alpha value other than 1.0, just as `TrackEntry.Alpha`. Defaults to 1.0. * `GetRemappedClone` copying from `Sprite` now provides additional `pmaCloneTextureFormat` and `pmaCloneMipmaps` parameters to explicitly specify the texture format of a newly created PMA texture. * Spine property Inspector fields (`Animation Name`, `Bone Name`, `Slot` and similar) now display the name in red when the respective animation/bone/etc no longer exists at the skeleton data. This may be helpful when such items have been renamed or deleted. - + * Added `UnscaledTime` property at `SkeletonAnimation` as well, behaving like `SkeletonGraphic.UnscaledTime`. If enabled, AnimationState uses unscaled game time (`Time.unscaledDeltaTime`), running animations independent of e.g. game pause (`Time.timeScale`). + * `SkeletonAnimation`, `SkeletonMecanim` and `SkeletonGraphic` now provide an additional `OnAnimationRebuild` callback delegate which is issued after both the skeleton and the animation state have been initialized. + * Timeline `SkeletonAnimation Track` and `SkeletonGraphic Track` now provide an `Unscaled Time` property. Whenever starting a new animation clip of this track, `SkeletonAnimation.UnscaledTime` or `SkeletonGraphic.UnscaledTime` will be set to this value. This allows you to play back Timeline clips either in normal game time or unscaled game time. Note that `PlayableDirector.UpdateMethod` is ignored and replaced by this property, which allows more fine-granular control per Timeline track. + * **Breaking changes** + * Made `SkeletonGraphic.unscaledTime` parameter protected, use the new property `UnscaledTime` instead. + * `SkeletonGraphic` `OnRebuild` callback delegate is now issued after the skeleton has been initialized, before the `AnimationState` component is initialized. This makes behaviour consistent with `SkeletonAnimation` and `SkeletonMecanim` component behaviour. Use the new callback `OnAnimationRebuild` if you want to receive a callback after the `SkeletonGraphic` `AnimationState` has been initialized. * **Changes of default values** @@ -245,7 +250,6 @@ Also removed less commonly used extension methods: `TrackEntry.AllowImmediateQueue()`, `Animation.SetKeyedItemsToSetupPose()` and `Attachment.IsRenderable()`. - * Made `SkeletonGraphic.unscaledTime` parameter protected, use the new property `UnscaledTime` instead. * **`SkeletonGraphic` now no longer uses a `RawImage` component at each submesh renderer** GameObject when `allowMultipleCanvasRenderers` is true. Instead, a new custom component `SkeletonSubmeshGraphic` is used which is more resource friendly. Replacement of these components will be performed automatically through editor scripting, saving scenes or prefabs will persist the upgrade. * **Linear color space:** Previously Slot colors were not displayed the same in Unity as in the Spine Editor. This is now fixed at all shaders, including URP and LWRP shaders. See section *Additions* below for more details. If you have tweaked Slot colors to look correct in `Linear` color space in Unity but incorrect in Spine, you might want to adjust the tweaked colors. Slot colors displayed in Unity should now match colors displayed in the Spine Editor when configured to display as `Linear` color space in the Spine Editor Settings. @@ -312,7 +316,6 @@ * Added example component `SkeletonRenderTexture` to render a `SkeletonRenderer` to a `RenderTexture`, mainly for proper transparency. Added an example scene named `RenderTexture FadeOut Transparency` that demonstrates usage for a fadeout transparency effect. * Added another fadeout example component named `SkeletonRenderTextureFadeout` which takes over transparency fadeout when enabled. You can use this component as-is, attach it in disabled state and enable it to start a fadeout effect. * Timeline clips now offer an additional `Alpha` parameter for setting a custom constant mix alpha value other than 1.0, just as `TrackEntry.Alpha`. Defaults to 1.0. - * Added `UnscaledTime` property at `SkeletonAnimation` as well, behaving like `SkeletonGraphic.UnscaledTime`. If enabled, AnimationState uses unscaled game time (`Time.unscaledDeltaTime`), running animations independent of e.g. game pause (`Time.timeScale`). * **Changes of default values** diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonRenderer.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonRenderer.java index 505028dea..31d7c9125 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonRenderer.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonRenderer.java @@ -33,9 +33,7 @@ import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.Batch; import com.badlogic.gdx.graphics.g2d.PolygonSpriteBatch; -import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.utils.FloatArray; -import com.badlogic.gdx.utils.Null; import com.badlogic.gdx.utils.NumberUtils; import com.badlogic.gdx.utils.ShortArray; @@ -53,12 +51,6 @@ public class SkeletonRenderer { private boolean pmaColors, pmaBlendModes; private final FloatArray vertices = new FloatArray(32); private final SkeletonClipping clipper = new SkeletonClipping(); - private final Vector2 temp = new Vector2(); - private final Vector2 temp2 = new Vector2(); - private final Color temp3 = new Color(); - private final Color temp4 = new Color(); - private final Color temp5 = new Color(); - private final Color temp6 = new Color(); /** Renders the specified skeleton. If the batch is a PolygonSpriteBatch, {@link #draw(PolygonSpriteBatch, Skeleton)} is * called. If the batch is a TwoColorPolygonBatch, {@link #draw(TwoColorPolygonBatch, Skeleton)} is called. Otherwise the @@ -143,10 +135,6 @@ public class SkeletonRenderer { if (batch == null) throw new IllegalArgumentException("batch cannot be null."); if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null."); - Vector2 tempPosition = this.temp, tempUV = this.temp2; - Color tempLight1 = this.temp3, tempDark1 = this.temp4; - Color tempLight2 = this.temp5, tempDark2 = this.temp6; - boolean pmaColors = this.pmaColors, pmaBlendModes = this.pmaBlendModes; BlendMode blendMode = null; int verticesLength = 0; @@ -245,10 +233,6 @@ public class SkeletonRenderer { if (batch == null) throw new IllegalArgumentException("batch cannot be null."); if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null."); - Vector2 tempPosition = this.temp, tempUV = this.temp2; - Color tempLight1 = this.temp3, tempDark1 = this.temp4; - Color tempLight2 = this.temp5, tempDark2 = this.temp6; - boolean pmaColors = this.pmaColors, pmaBlendModes = this.pmaBlendModes; batch.setPremultipliedAlpha(pmaColors); BlendMode blendMode = null; @@ -348,44 +332,6 @@ public class SkeletonRenderer { clipper.clipEnd(); } - private void applyVertexEffect (float[] vertices, int verticesLength, int stride, float light, float dark) { - Vector2 tempPosition = this.temp, tempUV = this.temp2; - Color tempLight1 = this.temp3, tempDark1 = this.temp4; - Color tempLight2 = this.temp5, tempDark2 = this.temp6; - tempLight1.set(NumberUtils.floatToIntColor(light)); - tempDark1.set(NumberUtils.floatToIntColor(dark)); - if (stride == 5) { - for (int v = 0; v < verticesLength; v += stride) { - tempPosition.x = vertices[v]; - tempPosition.y = vertices[v + 1]; - tempUV.x = vertices[v + 3]; - tempUV.y = vertices[v + 4]; - tempLight2.set(tempLight1); - tempDark2.set(tempDark1); - vertices[v] = tempPosition.x; - vertices[v + 1] = tempPosition.y; - vertices[v + 2] = tempLight2.toFloatBits(); - vertices[v + 3] = tempUV.x; - vertices[v + 4] = tempUV.y; - } - } else { - for (int v = 0; v < verticesLength; v += stride) { - tempPosition.x = vertices[v]; - tempPosition.y = vertices[v + 1]; - tempUV.x = vertices[v + 4]; - tempUV.y = vertices[v + 5]; - tempLight2.set(tempLight1); - tempDark2.set(tempDark1); - vertices[v] = tempPosition.x; - vertices[v + 1] = tempPosition.y; - vertices[v + 2] = tempLight2.toFloatBits(); - vertices[v + 3] = tempDark2.toFloatBits(); - vertices[v + 4] = tempUV.x; - vertices[v + 5] = tempUV.y; - } - } - } - public boolean getPremultipliedAlphaColors () { return pmaColors; } diff --git a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Public/SpineSkeletonAnimationComponent.h b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Public/SpineSkeletonAnimationComponent.h index 53d0d5b4f..3cc75fe78 100644 --- a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Public/SpineSkeletonAnimationComponent.h +++ b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Public/SpineSkeletonAnimationComponent.h @@ -192,7 +192,7 @@ public: float getAnimationDuration() { return entry ? entry->getAnimation()->getDuration() : 0; } UFUNCTION(BlueprintCallable, Category = "Components|Spine|TrackEntry") - float isValidAnimation() { return entry != nullptr; } + bool isValidAnimation() { return entry != nullptr; } UPROPERTY(BlueprintAssignable, Category = "Components|Spine|TrackEntry") FSpineAnimationStartDelegate AnimationStart; diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonAnimationInspector.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonAnimationInspector.cs index 427ba6226..c5fa5b9f2 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonAnimationInspector.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonAnimationInspector.cs @@ -74,11 +74,11 @@ namespace Spine.Unity.Editor { EditorGUILayout.PropertyField(loop, LoopLabel); wasAnimationParameterChanged |= EditorGUI.EndChangeCheck(); // Value used in the next update. EditorGUILayout.PropertyField(timeScale, TimeScaleLabel); - EditorGUILayout.PropertyField(unscaledTime, UnscaledTimeLabel); foreach (var o in targets) { var component = o as SkeletonAnimation; component.timeScale = Mathf.Max(component.timeScale, 0); } + EditorGUILayout.PropertyField(unscaledTime, UnscaledTimeLabel); EditorGUILayout.Space(); SkeletonRootMotionParameter(); diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonAnimation.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonAnimation.cs index 962eb6f57..a8a5dc1ee 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonAnimation.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonAnimation.cs @@ -61,12 +61,16 @@ namespace Spine.Unity { private bool wasUpdatedAfterInit = true; #endregion - #region Bone Callbacks ISkeletonAnimation + #region Bone and Initialization Callbacks ISkeletonAnimation + protected event ISkeletonAnimationDelegate _OnAnimationRebuild; protected event UpdateBonesDelegate _BeforeApply; protected event UpdateBonesDelegate _UpdateLocal; protected event UpdateBonesDelegate _UpdateWorld; protected event UpdateBonesDelegate _UpdateComplete; + /// OnAnimationRebuild is raised after the SkeletonAnimation component is successfully initialized. + public event ISkeletonAnimationDelegate OnAnimationRebuild { add { _OnAnimationRebuild += value; } remove { _OnAnimationRebuild -= value; } } + /// /// Occurs before the animations are applied. /// Use this callback when you want to change the skeleton state before animations are applied on top. @@ -197,6 +201,9 @@ namespace Spine.Unity { #endif } } + + if (_OnAnimationRebuild != null) + _OnAnimationRebuild(this); } virtual protected void Update () { diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs index 7b1e244e7..fdadf6a72 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs @@ -490,6 +490,8 @@ namespace Spine.Unity { } } + /// OnAnimationRebuild is raised after the SkeletonAnimation component is successfully initialized. + public event ISkeletonAnimationDelegate OnAnimationRebuild; public event UpdateBonesDelegate BeforeApply; public event UpdateBonesDelegate UpdateLocal; public event UpdateBonesDelegate UpdateWorld; @@ -542,12 +544,6 @@ namespace Spine.Unity { if (skeletonDataAsset.atlasAssets.Length <= 0 || skeletonDataAsset.atlasAssets[0].MaterialCount <= 0) return; - this.state = new Spine.AnimationState(skeletonDataAsset.GetAnimationStateData()); - if (state == null) { - Clear(); - return; - } - this.skeleton = new Skeleton(skeletonData) { ScaleX = this.initialFlipX ? -1 : 1, ScaleY = this.initialFlipY ? -1 : 1 @@ -565,7 +561,16 @@ namespace Spine.Unity { for (int i = 0; i < separatorSlotNames.Length; i++) separatorSlots.Add(skeleton.FindSlot(separatorSlotNames[i])); + if (OnRebuild != null) + OnRebuild(this); + wasUpdatedAfterInit = false; + this.state = new Spine.AnimationState(skeletonDataAsset.GetAnimationStateData()); + if (state == null) { + Clear(); + return; + } + if (!string.IsNullOrEmpty(startingAnimation)) { var animationObject = skeletonDataAsset.GetSkeletonData(false).FindAnimation(startingAnimation); if (animationObject != null) { @@ -577,8 +582,8 @@ namespace Spine.Unity { } } - if (OnRebuild != null) - OnRebuild(this); + if (OnAnimationRebuild != null) + OnAnimationRebuild(this); } public void PrepareInstructionsAndRenderers () { @@ -648,7 +653,15 @@ namespace Spine.Unity { var smartMesh = meshBuffers.GetNext(); bool updateTriangles = SkeletonRendererInstruction.GeometryNotEqual(currentInstructions, smartMesh.instructionUsed); meshGenerator.Begin(); - if (currentInstructions.hasActiveClipping && currentInstructions.submeshInstructions.Count > 0) { + + bool useAddSubmesh = currentInstructions.hasActiveClipping && currentInstructions.submeshInstructions.Count > 0; +#if UNITY_EDITOR + // Editor triggers Graphic.Rebuild without prior LateUpdate call, which + // can lead to filling unprepared vertex buffer and out-of-bounds write access. + if (!Application.isPlaying) + useAddSubmesh = true; +#endif + if (useAddSubmesh) { meshGenerator.AddSubmesh(currentInstructions.submeshInstructions.Items[0], updateTriangles); } else { meshGenerator.BuildMeshWithArrays(currentInstructions, updateTriangles); diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonMecanim.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonMecanim.cs index f12ffb656..2f29cf3dd 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonMecanim.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonMecanim.cs @@ -39,12 +39,16 @@ namespace Spine.Unity { public MecanimTranslator Translator { get { return translator; } } private bool wasUpdatedAfterInit = true; - #region Bone Callbacks (ISkeletonAnimation) + #region Bone and Initialization Callbacks ISkeletonAnimation + protected event ISkeletonAnimationDelegate _OnAnimationRebuild; protected event UpdateBonesDelegate _BeforeApply; protected event UpdateBonesDelegate _UpdateLocal; protected event UpdateBonesDelegate _UpdateWorld; protected event UpdateBonesDelegate _UpdateComplete; + /// OnAnimationRebuild is raised after the SkeletonAnimation component is successfully initialized. + public event ISkeletonAnimationDelegate OnAnimationRebuild { add { _OnAnimationRebuild += value; } remove { _OnAnimationRebuild -= value; } } + /// /// Occurs before the animations are applied. /// Use this callback when you want to change the skeleton state before animations are applied on top. @@ -87,6 +91,9 @@ namespace Spine.Unity { if (translator == null) translator = new MecanimTranslator(); translator.Initialize(GetComponent(), this.skeletonDataAsset); wasUpdatedAfterInit = false; + + if (_OnAnimationRebuild != null) + _OnAnimationRebuild(this); } public virtual void Update () { diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/ISkeletonAnimation.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/ISkeletonAnimation.cs index c43489e89..89a25c854 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/ISkeletonAnimation.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/ISkeletonAnimation.cs @@ -43,11 +43,7 @@ namespace Spine.Unity { InFixedUpdate } - public enum UpdateTimeScale { - GameTime = 0, - UnscaledGameTime - } - + public delegate void ISkeletonAnimationDelegate (ISkeletonAnimation animated); public delegate void UpdateBonesDelegate (ISkeletonAnimation animated); public interface ISpineComponent { } @@ -60,6 +56,7 @@ namespace Spine.Unity { /// A Spine-Unity Component that animates a Skeleton but not necessarily with a Spine.AnimationState. public interface ISkeletonAnimation : ISpineComponent { + event ISkeletonAnimationDelegate OnAnimationRebuild; event UpdateBonesDelegate UpdateLocal; event UpdateBonesDelegate UpdateWorld; event UpdateBonesDelegate UpdateComplete; @@ -91,7 +88,7 @@ namespace Spine.Unity { /// (Time.unscaledDeltaTime instead of the default Game Time(Time.deltaTime). /// to animate independent of game Time.timeScale. /// Instance SkeletonGraphic.timeScale and SkeletonAnimation.timeScale will still be applied. - public bool UnscaledTime { get; set; } + bool UnscaledTime { get; set; } } /// A Spine-Unity Component that holds a reference to a SkeletonRenderer. diff --git a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Documentation/README.md b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Documentation/README.md index cd5a0b5b9..ebb3503e9 100644 --- a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Documentation/README.md +++ b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Documentation/README.md @@ -34,6 +34,8 @@ These track types can be used to set animations at the AnimationState of the tar - *Track Index.* The target AnimationState track index to set animations at. Do not forget to set this value accordingly when using multiple timeline tracks. > **Important Note:** Currently it is required to order the timeline tracks with base track at the top and overlay tracks below, otherwise the Editor Preview will display incorrect results. +- *Unscaled Time.* Whenever starting a new animation clip of this track, `SkeletonAnimation.UnscaledTime` (or `SkeletonGraphic.UnscaledTime` respectively) will be set to this value. This allows you to play back Timeline clips either in normal game time or unscaled game time. Note that `PlayableDirector.UpdateMethod` is ignored and replaced by this property, which allows more fine-granular control per Timeline track. + ##### Spine Animation State Clip You can add a `Spine Animation State Clip` to a `SkeletonAnimation Track` (or `SkeletonGraphic Track`) by dragging an `AnimationReferenceAsset` onto a Timeline track. See the [SkeletonData - Preview](#Preview) section on how to generate `AnimationReferenceAssets` for a `SkeletonDataAsset`. diff --git a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Documentation/animationstate-track-inspector.png b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Documentation/animationstate-track-inspector.png index e988e8f77..f6cd9bbfe 100644 Binary files a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Documentation/animationstate-track-inspector.png and b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Documentation/animationstate-track-inspector.png differ diff --git a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateGraphicTrack.cs b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateGraphicTrack.cs index 1c16f2f94..d8f48d241 100644 --- a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateGraphicTrack.cs +++ b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateGraphicTrack.cs @@ -30,6 +30,7 @@ #if UNITY_EDITOR using System.ComponentModel; #endif +using System.Collections.Generic; using UnityEngine; using UnityEngine.Playables; using UnityEngine.Timeline; @@ -43,11 +44,26 @@ namespace Spine.Unity.Playables { #endif public class SpineAnimationStateGraphicTrack : TrackAsset { public int trackIndex = 0; + [Tooltip("Whenever starting a new animation clip of this track, " + + "SkeletonGraphic.UnscaledTime will be set to this value. " + + "This allows you to play back Timeline clips either in normal game time " + + "or unscaled game time. Note that PlayableDirector.UpdateMethod " + + "is ignored and replaced by this property, which allows more fine-granular " + + "control per Timeline track.")] + public bool unscaledTime = false; public override Playable CreateTrackMixer (PlayableGraph graph, GameObject go, int inputCount) { + IEnumerable clips = this.GetClips(); + foreach (TimelineClip clip in clips) { + var animationStateClip = clip.asset as SpineAnimationStateClip; + if (animationStateClip != null) + animationStateClip.timelineClip = clip; + } + var scriptPlayable = ScriptPlayable.Create(graph, inputCount); var mixerBehaviour = scriptPlayable.GetBehaviour(); mixerBehaviour.trackIndex = this.trackIndex; + mixerBehaviour.unscaledTime = this.unscaledTime; return scriptPlayable; } } diff --git a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateMixerBehaviour.cs b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateMixerBehaviour.cs index 77dd3b983..5b4f5e342 100644 --- a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateMixerBehaviour.cs +++ b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateMixerBehaviour.cs @@ -40,6 +40,7 @@ namespace Spine.Unity.Playables { float[] lastInputWeights; bool lastAnyClipPlaying = false; public int trackIndex; + public bool unscaledTime; ScriptPlayable[] startingClips = new ScriptPlayable[2]; @@ -177,6 +178,8 @@ namespace Spine.Unity.Playables { state.SetEmptyAnimation(trackIndex, mixDuration); } else { if (clipData.animationReference.Animation != null) { + animationStateComponent.UnscaledTime = this.unscaledTime; + TrackEntry currentEntry = state.GetCurrent(trackIndex); Spine.TrackEntry trackEntry; float customMixDuration = clipData.customDuration ? GetCustomMixDuration(clipData) : 0.0f; diff --git a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateTrack.cs b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateTrack.cs index f62f4f88a..7a0f58f9d 100644 --- a/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateTrack.cs +++ b/spine-unity/Modules/com.esotericsoftware.spine.timeline/Runtime/SpineAnimationState/SpineAnimationStateTrack.cs @@ -44,6 +44,13 @@ namespace Spine.Unity.Playables { #endif public class SpineAnimationStateTrack : TrackAsset { public int trackIndex = 0; + [Tooltip("Whenever starting a new animation clip of this track, " + + "SkeletonAnimation.UnscaledTime will be set to this value. " + + "This allows you to play back Timeline clips either in normal game time " + + "or unscaled game time. Note that PlayableDirector.UpdateMethod " + + "is ignored and replaced by this property, which allows more fine-granular " + + "control per Timeline track.")] + public bool unscaledTime = false; public override Playable CreateTrackMixer (PlayableGraph graph, GameObject go, int inputCount) { IEnumerable clips = this.GetClips(); @@ -56,6 +63,7 @@ namespace Spine.Unity.Playables { var scriptPlayable = ScriptPlayable.Create(graph, inputCount); var mixerBehaviour = scriptPlayable.GetBehaviour(); mixerBehaviour.trackIndex = this.trackIndex; + mixerBehaviour.unscaledTime = this.unscaledTime; return scriptPlayable; } } diff --git a/spine-unity/Modules/com.esotericsoftware.spine.timeline/package-no-spine-unity-dependency.json b/spine-unity/Modules/com.esotericsoftware.spine.timeline/package-no-spine-unity-dependency.json index 56a626bf9..8fcd7fe8a 100644 --- a/spine-unity/Modules/com.esotericsoftware.spine.timeline/package-no-spine-unity-dependency.json +++ b/spine-unity/Modules/com.esotericsoftware.spine.timeline/package-no-spine-unity-dependency.json @@ -2,7 +2,7 @@ "name": "com.esotericsoftware.spine.timeline", "displayName": "Spine Timeline Extensions", "description": "This plugin provides integration of spine-unity for the Unity Timeline.\n\nPrerequisites:\nIt requires a working installation of the spine-unity runtime (via the spine-unity unitypackage), version 4.1.\n(See http://esotericsoftware.com/git/spine-runtimes/spine-unity)", - "version": "4.1.5", + "version": "4.1.6", "unity": "2018.3", "author": { "name": "Esoteric Software", diff --git a/spine-unity/Modules/com.esotericsoftware.spine.timeline/package.json b/spine-unity/Modules/com.esotericsoftware.spine.timeline/package.json index b4332da54..68c955c4d 100644 --- a/spine-unity/Modules/com.esotericsoftware.spine.timeline/package.json +++ b/spine-unity/Modules/com.esotericsoftware.spine.timeline/package.json @@ -2,7 +2,7 @@ "name": "com.esotericsoftware.spine.timeline", "displayName": "Spine Timeline Extensions", "description": "This plugin provides integration of spine-unity for the Unity Timeline.\n\nPrerequisites:\nIt requires a working installation of the spine-unity and spine-csharp runtimes as UPM packages (not as spine-unity unitypackage), version 4.1.\n(See http://esotericsoftware.com/git/spine-runtimes/spine-unity)", - "version": "4.1.5", + "version": "4.1.6", "unity": "2018.3", "author": { "name": "Esoteric Software",