Search Unity

  1. Calling all beginners! Join the FPS Beginners Mods Challenge until December 13.
    Dismiss Notice
  2. It's Cyber Week at the Asset Store!
    Dismiss Notice

Code Example: How To Execute Logic At The Beginning And End Of A Clip

Discussion in 'Timeline' started by f0ff886f, Apr 14, 2019.

  1. f0ff886f

    f0ff886f

    Joined:
    Nov 1, 2015
    Posts:
    167
    Inspired by this post: https://forum.unity.com/threads/code-example-how-to-detect-the-end-of-the-playable-clip.659617/, and enabled by @drihpee to execute this, I wanted to share some simple code that lets you do two things:

    When Timeline enters a Behaviour (clip, in my mind), run some code, and when it exits (this is possible again by @drihpee in the above thread), run other code.

    I wanted to enable some clips where for the course of an animation, I can disable player input, for example, and be able to do that straight from a timeline. Or, trigger a script function just on the start to initiate some other script.

    This is the entire set of code you need to create a custom track that handles these clips, so it looks something like this, just simple blocks that will set some state for their duration:
    upload_2019-4-14_14-8-11.png

    I hope this helps someone else who just wants to do basic things with Timelines. If you want to learn how to do more with blending, I recommend the Subtitle Example available here: https://forum.unity.com/threads/tim...s-of-custom-script-clips.477017/#post-3113560

    If any of the information is incorrect please let me know so I can update this post.

    SimpleBehaviour.cs implements your actual runtime logic in the context of the clip on the timeline:
    Code (CSharp):
    1. using System;
    2. using UnityEngine;
    3. using UnityEngine.Playables;
    4.  
    5. [Serializable]
    6. public class SimpleBehaviour : PlayableBehaviour
    7. {
    8.     public override void OnBehaviourPlay(Playable playable, FrameData info)
    9.     {
    10.         // Only execute in Play mode
    11.         if (Application.isPlaying)
    12.         {
    13.             // Execute your starting logic here, calling into a singleton for example
    14.             Debug.Log("Clip started!")
    15.         }
    16.     }
    17.  
    18.     // source: https://forum.unity.com/threads/code-example-how-to-detect-the-end-of-the-playable-clip.659617/
    19.     public override void OnBehaviourPause(Playable playable, FrameData info)
    20.     {
    21.         // Only execute in Play mode
    22.         if (Application.isPlaying)
    23.         {
    24.             var duration = playable.GetDuration();
    25.             var time = playable.GetTime();
    26.             var count = time + info.deltaTime;
    27.            
    28.             if ((info.effectivePlayState == PlayState.Paused && count > duration) || Mathf.Approximately((float)time, (float)duration))
    29.             {
    30.                 // Execute your finishing logic here:
    31.                 Debug.Log("Clip done!")
    32.             }
    33.             return;
    34.         }
    35.     }
    36. }
    SimpleClip.cs takes care of storing the clip as a PlayableAsset:
    Code (CSharp):
    1. using System;
    2. using UnityEngine;
    3. using UnityEngine.Playables;
    4. using UnityEngine.Timeline;
    5.  
    6. [Serializable]
    7. public class SimpleClip : PlayableAsset, ITimelineClipAsset
    8. {
    9.     // Create the runtime version of the clip, by creating a copy of the template
    10.     public override Playable CreatePlayable(PlayableGraph graph, GameObject go)
    11.     {
    12.         return ScriptPlayable<SimpleBehaviour>.Create(graph);
    13.     }
    14.  
    15.     // Make sure we disable all blending since we aren't handling that in the mixer
    16.     public ClipCaps clipCaps
    17.     {
    18.         get { return ClipCaps.None; }
    19.     }
    20. }
    21.  
    SimpleMixerBehaviour.cs is required since we are implementing a custom track, maybe there is a way around not needing a mixer but I haven't found how:
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Playables;
    3.  
    4. public class SimpleMixerBehaviour : PlayableBehaviour
    5. {
    6.     // Override the ProcessFrame because we want to have our own color coded tracks
    7.     // to keep things in the Editor visually clean
    8.     public override void ProcessFrame(Playable playable, FrameData info, object playerData) { }
    9. }
    10.  
    SimpleTrack.cs instantiates the mixer at runtime and specifies what kind of clips it handles:
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Playables;
    3. using UnityEngine.Timeline;
    4.  
    5. [TrackColor(1.0f, 0.0f, 0.0f)]
    6. [TrackClipType(typeof(SimpleClip))]
    7. // No track binding since we're executing general logic during our scene
    8. public class SimpleTrack : TrackAsset
    9. {
    10.     public override Playable CreateTrackMixer(PlayableGraph graph, GameObject go, int inputCount)
    11.     {
    12.         // This Mixer won't do anything, but I want to use our own track type instead of a PlayableTrack to keep things simple
    13.         return ScriptPlayable<SimpleMixerBehaviour>.Create(graph, inputCount);
    14.     }
    15. }
    16.  
     
    Last edited: Apr 14, 2019
    seant_unity and tarahugger like this.