Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question Modify clip timings per-instance from code

Discussion in 'Timeline' started by jonagill, Apr 14, 2023.

  1. jonagill


    Oct 5, 2019
    Hi all,

    Does anyone know if it's possible to manually modify the start time of a Timeline clip in particular PlayableDirector's graph? My use case is that I have a lot of enemy objects, each with a PlayableDirector running an instance of the same TimelineAsset. To add some variety, there are some clips that I would like to randomly alter the start time of (without changing the graphs of any other enemies).

    I was hoping I'd be able to achieve this by calling
    in my
    method, but I'm not sure that works in practice. It looks like the clip timings get piped in each frame from
    , which reads in timing data from the serialized TimelineClip. I'm guessing this means I'd have to modify the TimelineClip to change the timings, which would then propagate the changes across every enemy, not just the ones I intend to modify.

    Thoughts or ideas would be appreciated!
    Yuchen_Chang likes this.
  2. Yuchen_Chang


    Apr 24, 2020
    If it's your custom playableBehaviour/track, I can think of some solutions:
    In your PlayableBehaviour, maybe you can postpone your process some seconds.
    Code (CSharp):
    1.         class SomePlayableBehaviour : PlayableBehaviour
    2.         {
    3.             // initialize this randomly:
    4.             private float randomWaitTime;
    5.             private float currentWaitedTime;
    7.             public override void ProcessFrame(Playable playable, FrameData info, object playerData)
    8.             {
    9.                 currentWaitedTime += info.deltaTime;
    10.                 if (currentWaitedTime < randomWaitTime) return;
    11.                 // do some work...
    12.             }
    13.         }
    Another solution:
    The RuntimeClip is created by
    , and both EvaluateAt() and CompileClips() are overridable, so I think you can create your own RuntimeClip child class, and then override both of them to customize.

    Code (CSharp):
    1.         class TimeOffsetRuntimeClip : RuntimeClip
    2.         {
    3.             // how to initialize this depends on you!
    4.             protected double timeOffset;
    6.             public override void EvaluateAt(double localTime, FrameData frameData)
    7.             {
    8.                 localTime += timeOffset; // I think there's a better solution, but this is just for demo
    9.                 base.EvaluateAt(localTime, frameData);
    10.             }
    11.             // ... you may also need to override other functions to get consistence
    12.         }
    14. // ... in your track asset
    16.         internal override Playable CompileClips(PlayableGraph graph, GameObject go, IList<TimelineClip> timelineClips, IntervalTree<RuntimeElement> tree)
    17.         {
    18.             // just copy the original function, but change RuntimeClip to your new clip
    19.             // ...
    20.             var clip = new TimeOffsetRuntimeClip(timelineClips[c], source, blend);
    21.             tree.Add(clip);
    22.             // ...
    23.         }
    One thing is that the access level of these functions are internal, so you may have to make .asmref to override them.
    Last edited: Apr 14, 2023
  3. jonagill


    Oct 5, 2019
    Whoah, I never considered using an asmref to modify an internal function. That's genius! I'll try these out for sure, thank you.
    Yuchen_Chang likes this.