Search Unity

jump to the position of the last custom marker?

Discussion in 'Timeline' started by ewanuno, Oct 4, 2019.

  1. ewanuno

    ewanuno

    Joined:
    May 11, 2017
    Posts:
    39
    i want to be able to jump back to the most recent custom marker in my timeline. triggered by a unity event.

    my project has a series of nested timelines so the markers span many timeline assets

    is there a better way than creating a big sorted list of all the markers in all the timelines and jumping to the last one before the current time in the highest level timeline?

    and if that is the best way, is there a way that i can avoid having to keep track of all the time offsets of the child timelines?
     
  2. seant_unity

    seant_unity

    Unity Technologies

    Joined:
    Aug 25, 2015
    Posts:
    1,082
    I don't think there is a better way. That's exactly the path I'd recommend.
     
    ewanuno likes this.
  3. ewanuno

    ewanuno

    Joined:
    May 11, 2017
    Posts:
    39
    it wasn't so bad after all, and a it was good opportunity to understand how timeline works on the inside.
     
  4. ewanuno

    ewanuno

    Joined:
    May 11, 2017
    Posts:
    39
    here is the code i ended up writing, i ended up implementing both jumping and rewinding to the custom marker.
    notes:
    the markers are always in the second level timeline.
    the custom marker is called JumpMarker
    the timeline sequences are nested like this:
    Chapter >
    scene1>
    frame1
    frame2
    scene2>
    frame1
    frame2

    hopefully somebody will find this useful.

    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using UnityEngine.Timeline;
    6. using UnityEngine.Playables;
    7.  
    8. public class AV_Rewind : MonoBehaviour
    9. {
    10.     public PlayableDirector chapterPlayableDirector;
    11.     public List<double> jumplist;
    12.     public bool pauseAfterJump;
    13.     public float timeMultiplier;
    14.     public bool rewinding;
    15.  
    16.     //public TimelineAsset ChapterTimelineAsset;
    17.     // Start is called before the first frame update
    18.     void Start()
    19.     {
    20.         //generate the marker list before the game starts
    21.  
    22.         //adds timeofsets becuase not all scenes start at 0
    23.         //adds option to pause after jumping.
    24.        
    25.         //todo, currently only gets markers from scene timeline, maybe we should get them from frametimelines too.
    26.  
    27.        
    28.  
    29.         // get the tracks for the scene timeline
    30.         TimelineAsset ChapterTimelineAsset = (TimelineAsset)chapterPlayableDirector.playableAsset;
    31.         IEnumerable<TrackAsset> chapterTracks = ChapterTimelineAsset.GetOutputTracks();
    32.  
    33.  
    34.         foreach (var chapterTrack in chapterTracks)
    35.         {
    36.             //Debug.Log("chapter track: " + chapterTrack.name);
    37.             // get the clips from each track
    38.             IEnumerable<TimelineClip> timelineClips = chapterTrack.GetClips();
    39.  
    40.  
    41.             foreach (var clip in timelineClips)
    42.             {
    43.                 //Debug.Log("chapter clip: " + clip.displayName);
    44.  
    45.                 // have fun resolving the scene gameobject from the clip
    46.                 ControlPlayableAsset sceneControlPlayableAsset = (ControlPlayableAsset)clip.asset;
    47.                 ExposedReference<GameObject> sceneTimelineSourceGameObject = sceneControlPlayableAsset.sourceGameObject;
    48.                 GameObject SceneGameobject = sceneTimelineSourceGameObject.Resolve(chapterPlayableDirector);
    49.  
    50.                 //Debug.Log("SceneGameobject: " +SceneGameobject.name);
    51.  
    52.                 PlayableDirector ScenePlayableDierctor = SceneGameobject.GetComponent<PlayableDirector>();
    53.  
    54.                 TimelineAsset sceneTimelineAsset = (TimelineAsset)ScenePlayableDierctor.playableAsset;
    55.  
    56.                 IEnumerable<TrackAsset> sceneTrackAssets = sceneTimelineAsset.GetOutputTracks();
    57.  
    58.                 foreach (var sceneTrack in sceneTrackAssets)
    59.                 {
    60.                     //Debug.Log("sceneTrack: " + sceneTrack.name);
    61.                     //get markers for the scene track
    62.                     IEnumerable<IMarker> sceneimarkers = sceneTrack.GetMarkers();
    63.  
    64.                     foreach (IMarker sceneimarker in sceneimarkers)
    65.                     {
    66.                         //Debug.Log("marker at : " + sceneimarker.time + sceneimarker.GetType());
    67.                         //Debug.Log("clip time ofset" + clip.start);
    68.                         Type markertype = sceneimarker.GetType();
    69.                         if (markertype == typeof(JumpMarker))
    70.                         {
    71.                             //put the markers in the jump list add the clip time ofset.
    72.                             jumplist.Add(sceneimarker.time + clip.start);
    73.  
    74.                         }
    75.                     }
    76.  
    77.                 }
    78.  
    79.  
    80.  
    81.             }
    82.  
    83.         }
    84.  
    85.         jumplist.Sort();
    86.         //Debug.Log("sorted jumplist");
    87.         //Debug.Log("jumplist size :" + jumplist.Count);
    88.         //foreach (var markertime in jumplist)
    89.         //{
    90.            
    91.         //    Debug.Log("markertime" + markertime);
    92.            
    93.         //}
    94.  
    95.     }
    96.  
    97.     public void JumpToLastmarker()
    98.     {
    99.         PlayState oldstate = chapterPlayableDirector.state;
    100.  
    101.         //Debug.Log("jump!");
    102.  
    103.         double t = GetLastMarkerTime();
    104.         chapterPlayableDirector.time = t;
    105.         Debug.Log("jump! to: "+t);
    106.  
    107.  
    108.         if (pauseAfterJump &&(oldstate == PlayState.Playing))
    109.         {
    110.             chapterPlayableDirector.Pause();
    111.         }
    112.  
    113.     }
    114.  
    115.     public void RewindToLastMarker() {
    116.  
    117.         double targetTime = GetLastMarkerTime();
    118.         //show rewind icon
    119.         var coroutine = Rewind(targetTime);
    120.         StartCoroutine(coroutine);
    121.  
    122.     }
    123.  
    124.     IEnumerator Rewind(double rewindTargetTime) {
    125.  
    126.         rewinding = true;
    127.        Debug.Log("rewinding to..." + rewindTargetTime);
    128.  
    129.         // save state
    130.  
    131.         DirectorUpdateMode oldUpdateMode = chapterPlayableDirector.timeUpdateMode;
    132.         double oldplayheadtime = chapterPlayableDirector.time;
    133.  
    134.         // pause the timeline
    135.         chapterPlayableDirector.Stop();
    136.         chapterPlayableDirector.time = oldplayheadtime;
    137.        
    138.  
    139.         // enable manual time updates
    140.         chapterPlayableDirector.timeUpdateMode = DirectorUpdateMode.Manual;
    141.  
    142.  
    143.         // Debug.Log("time =" + chapterPlayableDirector.time);
    144.  
    145.         while (chapterPlayableDirector.time > rewindTargetTime)
    146.         {
    147.             double t = chapterPlayableDirector.time - Time.deltaTime;
    148.  
    149.             //Debug.Log("manualy set to new time : ");
    150.  
    151.             if (t < 0) {
    152.                 Debug.Log("attempted to rewind back past 0!!");
    153.                 t = 0;
    154.  
    155.                     }; //don't rewind past 0!!
    156.  
    157.             chapterPlayableDirector.time = t;
    158.  
    159.             chapterPlayableDirector.Evaluate();
    160.  
    161.             if (t < 0)
    162.             {
    163.                 //chapterPlayableDirector.Stop();
    164.                 //enabled = false;
    165.                 break;
    166.             }
    167.  
    168.             //yield return null;
    169.             yield return new WaitForSecondsRealtime(Time.deltaTime * timeMultiplier);
    170.         }
    171.  
    172.  
    173.         chapterPlayableDirector.timeUpdateMode = oldUpdateMode;
    174.  
    175.         rewinding = false;
    176.     }      
    177.  
    178.     private double GetLastMarkerTime()
    179.     {
    180.         double playheadtime = chapterPlayableDirector.time;
    181.         double lastmarkertime = 0;
    182.  
    183.        
    184.         foreach (var time in jumplist)
    185.         {
    186.            
    187.             if (time >= playheadtime)
    188.             {
    189.                 //Debug.Log("lastmarkertime "+ lastmarkertime);
    190.                 return lastmarkertime;
    191.             }
    192.             else
    193.             {
    194.                 //Debug.Log("not there yet");
    195.                 lastmarkertime = time;
    196.             }
    197.            
    198.         }
    199.  
    200.         //if there is no marker return the current time.
    201.         Debug.Log("no marker found");
    202.         return playheadtime;
    203.     }
    204.  
    205.     void Update()
    206.     {
    207.         //Debug.Log("Status:"+ chapterPlayableDirector.state+" current frame: " + chapterPlayableDirector.time + "last Marker is : " + GetLastMarkerTime());
    208.        
    209.     }
    210.  
    211. }
    212.  
     
    seant_unity likes this.