Is Anyway to Change the Speed Multiplier of Timeline at runtime in unity c#


Is Anyway to Change the Speed Multiplier of Timeline at runtime in unity c#
Could Someone can tell me the process?

You can find the correct track using TimelineAsset.GetOutputTracks(), then find the correct clip using TrackAsset.GetClips(), then change the speed of the clip using TimelineClip.timeScale;

Normally changes to the timeline itself does not change any instances of that timeline currently playing…but changing the speed of the clip will - Timeline uses a reference to the clip to convert to the local time of the clip.

If you want to change the speed at which the entire timeline plays, after the timeline starts playing, you can modify the instance (playableGraph) directly. E.g. playableDirector.playableGraph.GetRootPlayable(0).SetSpeed(newSpeed);

10 Likes

U R A Great…!!!

1 Like

Wow, this just saved me hours of adjusting my clips in my 50+ tracks timeline :wink:
Just to add the full code below, if anybody needs it (add this script to the timeline, drag timeline object into field pd and set new Speed in Inspector)

using UnityEngine;
using UnityEngine.Playables;
public class TimelineSpeed : MonoBehaviour
{
public float newSpeed;
public PlayableDirector pd;

void Start()
{
pd = GetComponent();
pd.playableGraph.GetRootPlayable(0).SetSpeed(newSpeed);
}

5 Likes

Thanks for sharing, straight to the point!

I implemented this as a fork of the Time dilation sample (available in the package) which now gives a IsGlobal boolean. And it seems to work pretty well, so now you can use timeline clip to directly control its speed (getting a kind of an inception vibe here …)

@julienb Would this be good to be added to the sample for it to be available to everyone ?

namespace Timeline.Samples
{
    // Runtime representation of a time dilation clip.
    // The Serializable attribute is required to be animated by timeline, and used as a template.
    [Serializable]
    public class TimeDilationBehaviour : PlayableBehaviour
    {
        [Tooltip("Time.timeScale replacement value.")]
        public float timeScale = 1f;

        [Tooltip("Targets global game time or only current root timeline")]
        public bool isGlobal = false;
    }
}
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;

namespace Timeline.Samples
{
    // A track mixer behaviour that modifies the timeScale. This affects how fast the game plays back
    public class TimeDilationMixerBehaviour : PlayableBehaviour
    {
        private float m_DefaultTimeScale = 1;
        private float m_DefaultPlayableSpeed;

        // Called every frame that the timeline is Evaluated.
        public override void ProcessFrame(Playable playable, FrameData info, object playerData)
        {
            int inputCount = playable.GetInputCount();
            float timeScale = 0f;
            float playableSpeed = 0f;
            float totalWeight = 0f;
            float totalWeightSpeed = 0f;

            // blend clips together
            for (int i = 0; i < inputCount; i++)
            {
                float inputWeight = playable.GetInputWeight(i);

                ScriptPlayable<TimeDilationBehaviour> playableInput = (ScriptPlayable<TimeDilationBehaviour>)playable.GetInput(i);
                TimeDilationBehaviour input = playableInput.GetBehaviour();

                if (input.isGlobal)
                {
                    timeScale += inputWeight * input.timeScale;
                    totalWeight += inputWeight;
                }
                else
                {
                    playableSpeed += inputWeight * input.timeScale;
                    totalWeightSpeed += inputWeight;
                }

            }

            if (totalWeight > 0)
            {
                // blend to/from the default timeline
                Time.timeScale = Mathf.Max(0.0001f, Mathf.Lerp(m_DefaultTimeScale, timeScale, Mathf.Clamp01(totalWeight)));
            }

            if (totalWeightSpeed > 0)
            {
                GetRootTimeline(playable).SetSpeed(Mathf.Max(0.0001f, Mathf.Lerp(m_DefaultPlayableSpeed, playableSpeed, Mathf.Clamp01(totalWeightSpeed))));
            }
        
        }

        private static Playable GetRootTimeline(Playable playable)
        {
            return playable.GetGraph().GetRootPlayable(0);
        }

        // Called when the playable graph is created, typically when the timeline is played.
        public override void OnPlayableCreate(Playable playable)
        {
            m_DefaultTimeScale = Time.timeScale;
            m_DefaultPlayableSpeed = (float)GetRootTimeline(playable).GetSpeed();
        }

        // Called when the playable is destroyed, typically when the timeline stops.
        public override void OnPlayableDestroy(Playable playable)
        {
            Time.timeScale = m_DefaultTimeScale;
            playable.SetSpeed(m_DefaultPlayableSpeed);//Needed ?
        }
    }
}

[Edit] : Fixed, our .gitignore had filtered out folder with "Samples’ in the name.
The timeline speed works good within the editor both at play and edit time. However it does not modify the speed the in build. Is there somehting I’m overlooking on how playables work ?