Pausing Director from PlayableBehaviour will not allow Resume

I want to jump to different parts of a Timeline with a click of a button. Which means when one segment is over the Timeline needs to be paused before I change positions on the timeline. I got it working with an animation track and enable/disable the ForcePauseTimeline class. BUT I wanted to built this logic into a Playable (see below).

However when the playable stops the director it will not allow StepThruTimeline class to resume the Timeline.

Any thoughts?

This works!

public class ForcePauseTimeline : MonoBehaviour
{
    #region Vars
    public PlayableDirector director = null;
    #endregion
    #region  Methods
    /// <summary>
    /// Called when component is enabled
    /// </summary>
    private void OnEnable()
    {
        if (director)
        {
            director.Pause();
        }
    }
    #endregion
}

This does NOT work ( why?)
Here is my Playable code

public class PauseTimelineAsset : PlayableAsset
{
    public ExposedReference<PlayableDirector> directorReference;
    public override Playable CreatePlayable(PlayableGraph graph, GameObject go)
    {
        ScriptPlayable<PauseTimelinePlayable> playable = ScriptPlayable<PauseTimelinePlayable>.Create(graph);
        PlayableDirector director = directorReference.Resolve(graph.GetResolver());
        if (director != null)
        {
            playable.GetBehaviour().Initialize(director);
        }
        return playable;
    }
}

public class PauseTimelinePlayable : PlayableBehaviour
{
    private  PlayableDirector director = null;
    public void Initialize(PlayableDirector d)
    {
        director = d;

    }

    public override void OnBehaviourPlay(Playable playable, FrameData info)
    {
        base.OnBehaviourPlay(playable, info);
       
        if (director)
        {
            director.Pause();
        }
    }
}

Here is code to resume the director from buttons

public class StepThruTimeline : MonoBehaviour {
    #region Vars
    [Header("Director")]
    public PlayableDirector director = null;
    [Header("UI")]
    public Button nextButton = null;
    public Button prevButton = null;
    [Header("Step Data - Values in Seconds")]
    public int startIndex = 0;
    public float[] values;
    [ReadOnly()]
    public int currentIndex = -1;
    #endregion
    #region Methods
    /// <summary>
    /// Initialized array index and adds listeners to the prev/next buttons
    /// </summary>
    void Start ()
    {
        currentIndex = startIndex;

        if (nextButton)
        {
            nextButton.onClick.AddListener(onNextPressed);
        }
        if (prevButton)
        {
            prevButton.onClick.AddListener(onPrevPressed);
        }
    }

    /// <summary>
    /// Set time line to a specific time and press play
    /// </summary>
    /// <param name="val"></param>
    public void stepTo(int val)
    {
        if (val >= values.Length || val < 0)
        {
            Debug.LogError("<color= red>ERROR</color> Index Val "+ val + " is greater than values.Length of " + values.Length);
            return;
        }
        if(director)
        {
           // Debug.Log("Time will be for val: " + val +  " time: " + values[val]);
            director.time = values[val]; 
            if (val == 0)
            {
                director.Play();
            }
            else
            {
                director.Resume();
            }
        }
    }

    #region Listeners
    /// <summary>
    /// Decriments index and proceeds to the time value in the array 
    /// </summary>
    public void onPrevPressed()
    {
        currentIndex--;
        stepTo(currentIndex);
    }
    /// <summary>
    /// Incriments index and proceeds to the time value in the array 
    /// </summary>
    public void onNextPressed()
    {
        currentIndex++;
        stepTo(currentIndex);
    }



    #endregion
    #endregion

}

It’s a bit hard to tell, but I suspect that the director.Resume is invoking OnBehaviourPlay again and immediately re-pausing it.

PlayableDirector.Pause() will cause OnBehaviourPause() to invoke and Resume() will cause another OnBehaviourPlay(). An alternative to pausing is to change the playspeed of the timeline.

e.g. playableDirector.playableGraph.SetSpeed(0) (pause) or playableDirector.playableGraph.SetSpeed(1) (resume). This keeps the graph actually updating each frame, just not advancing, which seems like maybe the desired behaviour here.

1 Like

I don’t see that API in t 2017 or 2018

Oh, my mistake, I meant playableDirector.playableGraph.GetRootPlayable(0).Set/GetSpeed.

For timelines, the 0th root playable is the timeline playable that is controlling everything.

Also, important to check for playableGraph.IsValid() before accessing it. If the playableDirector is not playing, it will not be valid.

1 Like

That works!

1 Like