Search Unity

  1. All Pro and Enterprise subscribers: find helpful & inspiring creative, tech, and business know-how in the new Unity Success Hub. Sign in to stay up to date.
    Dismiss Notice
  2. Dismiss Notice

We need a timeline scripting FAQ

Discussion in 'Timeline' started by fastgamedev, Sep 4, 2017.

  1. fastgamedev


    Mar 27, 2014
    Working with the timeline over the last month, we accumulated several questions that are not answered anywhere in the docs or in the forum. Can someone from Unity answer these please. Perhaps this can become the beginning of an FAQ.
    1. Is a very short playable clip (say 1 frame long) guaranteed to run, ie receive at least one ProcessFrame() call? Or can the timeline, due to low frame rate hiccup, skip a few frames completely bypassing the short clip? This is critical for EventTracks.
    2. How to access trackBinding object in OnGraphStart() in behaviors?
    3. How to access trackBinding object in CreateTrackMixer() in TrackAsset?
    4. How to add serialized fields to TrackAsset that are exposed in the Editor? (Similar to "Post-playback state" on the default ActivationTrack) Just adding [Serializable] to the TrackAsset and a public field doesn't work.
    5. The default ActivationTrack has a strange feature that when the timeline is paused in playmode in the middle of an Activation clip, it deactivates the GameObject, instead of keeping it unchanged as you would expect. Is this a bug?
    Thank you!
  2. seant_unity


    Unity Technologies

    Aug 25, 2015
    1. It is not guaranteed to run. A single frame clip will get bypassed if a framerate hiccup causes it to be missed.

    2/3. In CreateTrackMixer(), the gameObject passed in as the second parameter contains the PlayableDirector that is building the graph. You can do go.GetComponent<PlayableDirector>().GetGenericBinding(this) to get the binding for that track. You can assign the binding to the mixer playable in that method.

    If you need it in your clip behaviours, you will need to assign it to your PlayableAsset on the clips, and in turn assign it to the playables they create. Definitely not ideal behaviour, and we are currently looking into how to provided better timeline-relevant information to custom clips and tracks.

    4. You can write your own inspector for the Track to make them show up for now. I think that's a bug we should address that it does not by default.

    5. That's a bug, and a fix will be available in the next betas/patches.
  3. fastgamedev


    Mar 27, 2014
    @seant_unity , thank you for quick response.

    1. It follows then that in extreme cases of computer slowdown, any number of frames can be skipped. Therefore, no gameplay mechanics can ever be keyed off a timeline. Even, for example, a 60 frame activation track that loads the next scene can be skipped, breaking the game.

    Is anything guaranteed to run? OnGraphStart? OnPlayableCreate? OnBehaviorPlay?

    2. Once I followed your instructions for getting TrackBinding in CreateTrackMixer(), then getting it in behaviors is not so bad:

    Code (CSharp):
    2. public class MyPlayableMixerBehaviour: PlayableBehaviour {
    3.     public GameObject TrackBinding { get; set; }
    5.     public override void OnGraphStart(Playable playable) {
    6.       for (int i = 0; i < inputCount; i++) {
    7.         var inputPlayable = (ScriptPlayable<MyPlayableBehaviour>) playable.GetInput(i);
    8.         MyPlayableBehaviour input = inputPlayable.GetBehaviour();
    9.         input.Mixer = this;
    10.       }
    11.     }
    13. public class MyPlayableBehaviour : PlayableBehaviour {
    14.     public MyPlayableMixerBehaviour Mixer { get; set; }
    16.     // Get binding via Mixer.TrackBinding
    17. }
    19. public class MyTrackAsset : TrackAsset {
    20.     public override Playable CreateTrackMixer(PlayableGraph graph, GameObject go, int inputCount) {
    21.         var result = ScriptPlayable<MyPlayableMixerBehaviour>.Create(graph, inputCount);
    22.         result.GetBehaviour().TrackBinding = go.GetComponent<PlayableDirector>().GetGenericBinding(this) as GameObject;
    23.         return result;
    24.     }
    25. }