Search Unity

Runtime modification of bindings

Discussion in 'Timeline' started by Ziboo, Apr 24, 2017.

  1. Ziboo

    Ziboo

    Joined:
    Aug 30, 2011
    Posts:
    356
    Hi,

    I need to do some sort of Ability System for my game.
    I think Timeline could be a really cool thing to use for that.

    In the big lines I need for instance:
    - Play animation
    - Play Fx @ time x
    - Move Fx to Target
    - Play Die animation on Target

    Works fine in editor, but of course, you can fire an ability on any target in the game.

    I was wondering if it's possible to instanciate a Director with the right Timeline asset, and being able to modify a reference.

    In my case, I would need to change the Target, to reflect the one you are targeting.

    I saw that the Director has SetGenericBinding and SetReferenceValue.

    First, I'm not quite sure the difference between the two.
    And Second, it asks for a key, and don't know where to reference that...

    Thanks
     
  2. gekidoslayer

    gekidoslayer

    Unity Technologies

    Joined:
    Sep 27, 2016
    Posts:
    134
    you definitely can do this - the demo I'm working on for the Vision Summit next week uses this quite extensively.

    Here is a sample script that does dynamic timeline binding of tracks:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.Playables;
    5. using UnityEngine.Timeline;
    6.  
    7. namespace PixelWizards.Shared.Utiltiies
    8. {
    9.  
    10.     public class DynamicTimelineBinding : MonoBehaviour
    11.     {
    12.         public List<GameObject> trackList = new List<GameObject>();
    13.         public PlayableDirector timeline;
    14.         public TimelineAsset timelineAsset;
    15.         public bool autoBindTracks = true;
    16.  
    17.         // Use this for initialization
    18.         private void Start()
    19.         {
    20.             if (autoBindTracks)
    21.                 BindTimelineTracks();
    22.         }
    23.  
    24.         public void BindTimelineTracks()
    25.         {
    26.             Debug.Log("Binding Timeline Tracks!");
    27.             timelineAsset = (TimelineAsset)timeline.playableAsset;
    28.             // iterate through tracks and map the objects appropriately
    29.             for( var i = 0; i < trackList.Count; i ++)
    30.             {
    31.                 if( trackList[i] != null)
    32.                 {
    33.                     var track = (TrackAsset)timelineAsset.outputs[i].sourceObject;
    34.                     timeline.SetGenericBinding(track, trackList[i]);
    35.                 }
    36.             }
    37.         }
    38.     }
    39. }
    What this looks like is this:

    DynamicTimelineBinding.jpg

    Basically the 'track list' on the dynamic binding script mirrors the tracks in the timeline sequence.

    You can modify this base script to do specific lookups in the scene to bind to specific tracks etc. Currently the tracks are just an array you can access, so if you change the order of tracks, it breaks the binding, which isn't ideal, but otherwise works well.

    Something we are considering / investigating going forward is having tags for tracks (similar to the general unity tags) so you can mark a track as 'character 1' or something and then look it up while binding - in a similar manner to the GameObject.FindByTag() methods that are used throughout.

    Hope this helps!
     
  3. Ziboo

    Ziboo

    Joined:
    Aug 30, 2011
    Posts:
    356
    Hey,

    Thanks for the answer. At the end I figure it out, but I'm using the tracks list names.
    I also needed to modify Reference in some PlayableTrack , not very easy...

    Code (CSharp):
    1. public class Test01 : MonoBehaviour
    2. {
    3.     public GameObject Player;
    4.     public TimelineAsset TimlineAsset;
    5.     public string SourceTrackName;
    6.     public string TargetTrackName;
    7.     public string MoveParticleTrackName;
    8.  
    9.     private RaycastHit hit;
    10.    
    11.     void Update()
    12.     {
    13.         if (Input.GetMouseButtonDown(0))
    14.         {
    15.             if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out hit))
    16.             {
    17.                 var director = new GameObject("Ability").AddComponent<PlayableDirector>();
    18.                 director.playableAsset = TimlineAsset;
    19.  
    20.                 var target = hit.collider.gameObject;
    21.  
    22.                 foreach (var playableAssetOutput in director.playableAsset.outputs)
    23.                 {
    24.                     if (playableAssetOutput.streamName == SourceTrackName)
    25.                     {
    26.                         director.SetGenericBinding(playableAssetOutput.sourceObject, Player);
    27.                     }
    28.                     else if (playableAssetOutput.streamName == TargetTrackName)
    29.                     {
    30.                         director.SetGenericBinding(playableAssetOutput.sourceObject, target);
    31.                     }
    32.                     else if (playableAssetOutput.streamName == MoveParticleTrackName)
    33.                     {
    34.                         var tr = playableAssetOutput.sourceObject as PlayableTrack;
    35.                         foreach (var clip in tr.GetClips())
    36.                         {
    37.                             var t = clip.asset as MoveObjectPlayable;
    38.                             director.SetReferenceValue(t.LerpMoveTo.exposedName, target.transform);
    39.                             director.SetReferenceValue(t.LerpMoveFrom.exposedName, Player.transform);
    40.                         }
    41.                     }
    42.                 }
    43.                 director.Play();
    44.             }
    45.         }
    46.     }
    47. }
    I would agree that a Tag system would be nice.

    By the way, what's the "Control Track" ?

    Thanks
     
    BMRG14, N8W1nD and Mazak like this.
  4. gekidoslayer

    gekidoslayer

    Unity Technologies

    Joined:
    Sep 27, 2016
    Posts:
    134
    nice - yeah looking up track names is a good way to do this.

    Control Track is a special track that lets you control Timeline sequences in other game objects. You can think of it as a 'macro' timeline track.

    You can organize scenes in a movie, each as their own track (for example) and then add a control track to a master timeline, which then drives the other timelines. Or you could have different team members working in their own timelines and combine them together to create your master shot sequence.

    How to use:

    1) create control track
    2) create control track shot clip (right click on track -> create)
    3) select shot clip
    4) add the game object with the 'other' timeline into the 'game object' reference on the inspector

    Now when you scrub the control track, it will play the timeline sequence in the references gameobject.
     
    viscira and MadeFromPolygons like this.
  5. EliotVR

    EliotVR

    Joined:
    Jan 12, 2017
    Posts:
    14
    very useful! thanks all
     
  6. ModLunar

    ModLunar

    Joined:
    Oct 16, 2016
    Posts:
    374
    Not to be that person, lol, but I'm using my own class to manage timelines that I'm playing back during runtime as opposed to the PlayableDirector. So in my case, I don't have a PlayableDirector to do SetGenericBindings(...) for me -- instead, I'm managing my own PlayableGraph and inserting the playables generated by the TimelineAsset manually like this:

    Code (CSharp):
    1. //You can assume these variables existed already and were properly set
    2. PlayableGraph graph = //...;
    3. TimelineAsset timeline = //...;
    4.  
    5. Playable timelinePlayable = timeline.CreatePlayable(graph, gameObject);

    However, some of the AnimationTracks in my timeline sequence don't seem to be properly binding to my scene objects. Is there a way for me to set the bindings via the ScriptPlayable<TimelinePlayable> that was inserted into my PlayableGraph? I saw some stuff about UnityEngine.PlayableBinding, but it only seems to contain the key, which was weird to me -- where's the value associated with that key?
     
  7. seant_unity

    seant_unity

    Unity Technologies

    Joined:
    Aug 25, 2015
    Posts:
    1,516
    After the timelinePlayable is created, you can bind (or change bindings) on the PlayableOutputs of the graph. Each track (non-group, non-override track) creates a corresponding output in the graph. (side note: This is where timelineAsset.GetOutputTracks() get it's naming).

    Use AnimationPlayableOutput.SetTarget, AudioPlayableOutput.SetTarget for animation and audio tracks respectively, and PlayableOutput.SetUserData for all other track types (which are all ScriptPlayableOutputs).
     
  8. ModLunar

    ModLunar

    Joined:
    Oct 16, 2016
    Posts:
    374
    Ah, seant, you've come to my rescue again and again with the Timeline/Playables stuff! Thank you for your answer, I like the intuition that's behind those names, it makes more sense when you put it that way :)
     
    lfree and MadeFromPolygons like this.
  9. UnnamedGameDev

    UnnamedGameDev

    Joined:
    Jul 24, 2012
    Posts:
    15
    So i should call AnimationPlayableOutput.SetTarget on what?
    I want to have a timeline object in my scene which is referenced in my Player class. From the player class i want to tell the timeline to change the actor of the animation. Both uses humanoid rig's i just want to play the same animation with different models depending on certain conditions. Is this doable at all? Im having trouble understanding the naming and how the different components interact with eachother.
     
  10. seant_unity

    seant_unity

    Unity Technologies

    Joined:
    Aug 25, 2015
    Posts:
    1,516
    Let's see if I can clarify it.

    The playable director stores bindings between tracks and targets (i.e. animators, gameObjects, audioSources). When playableDirector.Play() is called it creates a PlayableGraph, which can be thought of as an instance of a timeline. Each track, creates a corresponding PlayableOutput in the graph, and the playable director sets the target of each PlayableOutput.

    This means that you can change targets prior to playing the graph using PlayableDirector.SetGenericBinding(track, target); Once the graph is playing, this will have no effect until you Stop (not Pause) the graph, and Play again - this is generally true of any changes to the timeline itself.

    Once the graph is playing, you can switch targets by modifying the PlayableOutputs on the graph directly. For example, if you know the first track is always an animation track, you can change the target using the following:

    var animationOutput = (AnimationPlayableOutput) playableDirector.playableGraph.GetOutput(0);
    animationOutput.SetTarget(myAnimator);

    Hopefully that makes it a bit more clear.
     
    nous likes this.
  11. UnnamedGameDev

    UnnamedGameDev

    Joined:
    Jul 24, 2012
    Posts:
    15
    EDIT: Apparently AnimationPlayableOutput is not a recognized type. Both AnimationPlayableAsset and AnimationPlayableUtilities is recognized, i have included the assembly references:
    using UnityEngine.Playables;
    using UnityEngine.TimeLine;
    This seems very strange...
    EDIT: Im using unity 2017.3
     
    Last edited: Mar 8, 2018
  12. UnnamedGameDev

    UnnamedGameDev

    Joined:
    Jul 24, 2012
    Posts:
    15
    So i've managed to create a function which sets the Actors of animationclips inside the timeline at runtime. It works fine if you only want to set the actors once.

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Playables;
    3. using UnityEngine.Timeline;
    4.  
    5.  
    6. public class DynamicActors : MonoBehaviour
    7. {
    8.  
    9.     public PlayableDirector playableDirector;
    10.     public PlayableAsset playableAsset;
    11.     public GameObject[] newTarget = new GameObject[2];
    12.  
    13.     public void ChangeActor()
    14.     {
    15.         var outputs = playableAsset.outputs;
    16.         foreach (var itm in outputs)
    17.         {
    18.             Debug.Log(itm.streamName);
    19.             if(itm.streamName == "Animation Track") {
    20.                 playableDirector.SetGenericBinding(itm.sourceObject, newTarget[0]);
    21.             }
    22.             else if(itm.streamName == "Animation Track1")
    23.             {
    24.                 playableDirector.SetGenericBinding(itm.sourceObject, newTarget[1]);
    25.             }
    26.         }
    27.     }
    28. }
    Thanks for the help Seant, this will do in my case, although i wonder why i cant access AnimationPlayableOutput.
    Cheers :)
     
    Last edited: Mar 8, 2018
    jeromeWork and cahumalu like this.
  13. seant_unity

    seant_unity

    Unity Technologies

    Joined:
    Aug 25, 2015
    Posts:
    1,516
    It's under UnityEngine.Animations (with an 's')
     
    UnnamedGameDev likes this.
  14. mradfo21

    mradfo21

    Joined:
    May 16, 2013
    Posts:
    194
    omg PLEASE implement a tag system. I'm dying for this right now
     
    EvOne and MadeFromPolygons like this.
  15. NezeqGaash

    NezeqGaash

    Joined:
    Feb 25, 2016
    Posts:
    5
    Hey,
    I really Enjoy to use and learn about the Timeline features,
    It looks like a great way to create tools for content and graphic designers.

    Can you please help out?

    How can I do a binding to a specific Object (GameObject) that is located on specific playable ?
    I dont want to bind a track but a playable: same as it is done on the control track.

    Thanks in advance
    Adi
     
  16. seant_unity

    seant_unity

    Unity Technologies

    Joined:
    Aug 25, 2015
    Posts:
    1,516
    Control Tracks clips use exposed references for bindings. The exposed reference is simply an ID, and the actually binding is stored inside the PlayableDirector using Set/GetReferenceValue.
     
  17. NezeqGaash

    NezeqGaash

    Joined:
    Feb 25, 2016
    Posts:
    5
  18. Dr-Game

    Dr-Game

    Joined:
    Mar 12, 2015
    Posts:
    161
    HIHI~How can I set the Animation Clip (Override) at RunTime??
    Is it only possible in custom track?
    I want use TimeLine as a template.Want to feed character ,animationclip,specific position at running time ~~
     
    Last edited: Feb 21, 2019
  19. seant_unity

    seant_unity

    Unity Technologies

    Joined:
    Aug 25, 2015
    Posts:
    1,516
    By default, timeline is a template, and the bindings are specific to the playable director playing it.

    You can modify the content of the timeline using the API - e.g. walk the timeline using TimelineAsset.GetOutputTracks(), TrackAsset.GetClips(), TimelineClip.asset, etc.. - and make changes before playing the timeline. That means you can have multiple playable directors modifying the timeline, playing it, and each will play the same timeline with their own parameters.

    If you want to modify it while it's playing, you can try using PlayableDirector.RebuildGraph() after making changes. Otherwise you need to modify the playable graph (the compiled instance of the timeline), which can be tricky.
     
  20. Dr-Game

    Dr-Game

    Joined:
    Mar 12, 2015
    Posts:
    161
    Thanks to seant_unity,You help me a lot.But a wierd thing is Where is the Graph??I never find the interface in unity editor.I can find the window" Playable Graph" in the image above
     
    Last edited: Feb 26, 2019
  21. seant_unity

    seant_unity

    Unity Technologies

    Joined:
    Aug 25, 2015
    Posts:
    1,516
    UnityEditor.Playables.Utility.GetAllGraphs() will get you all the current playable graphs. I believe that is what the visualizer is using.
     
  22. Dr-Game

    Dr-Game

    Joined:
    Mar 12, 2015
    Posts:
    161
    Sorry I put the code line UnityEditor.Playables.Utility.GetAllGraphs() in void Start() .But noting shows!!
    The is the visualizer window " Playable Graph" ????
     
  23. FutureWang

    FutureWang

    Joined:
    May 24, 2018
    Posts:
    22
    I am doing something to auto build timeline ControlPlayableAsset use code.
    Code (CSharp):
    1. void BlendTimeLine2Main(GameObject root, PlayableBinding item, int startIndex)
    2.     {
    3.         float fTime = 0;
    4.         for (int i = startIndex; i < cameraInfos.Count + startIndex; i++)
    5.         {
    6.             var track = item.sourceObject as ControlTrack;
    7.             var clip = track.CreateDefaultClip();
    8.             clip.displayName = cameraInfos[i - startIndex].nameCamera;
    9.             var clip1 = clip.asset as ControlPlayableAsset;
    10.             //clip1.name = cameraInfos[i - startIndex].nameCamera;
    11.             var ERValue = new ExposedReference<GameObject>();
    12.             ERValue.defaultValue = root.transform.GetChild(i).gameObject;
    13.             clip1.sourceGameObject = ERValue;
    14.             clip.duration = cameraInfos[i - startIndex].time;
    15.             clip.start = fTime;
    16.             //clip1.sourceGameObject.Resolve(
    17.             //    timelineMain.GetComponent<PlayableDirector>().playableGraph.GetResolver());
    18.  
    19.             fTime += cameraInfos[i - startIndex].time;
    20.         }
    21.     }
    I create a default clip and set the ControlPlayableAsset param in editor,but when i remove the test scene(with this plugin) in Hierarchy ,and drag the scene back ,the param in ControlPlayableAsset goon. Is there miss something?
    (unity 2018.3.5f1)
     
  24. seant_unity

    seant_unity

    Unity Technologies

    Joined:
    Aug 25, 2015
    Posts:
    1,516
    The defaultValue of the exposed reference won't serialize scene objects. You need to bind it using the PlayableDirector, using a name.

    e.g.
    clip1.sourceGameObject.exposedName = "myExposedName" + i;
    director.SetReferenceValue("myExposedName" + i, root.transform.GetChild(i).gameObject);
     
  25. mrtenda

    mrtenda

    Joined:
    Jun 6, 2017
    Posts:
    73
    This worked in 2018.2, but I'm having various issues with binding to the timeline in this way in 2019.1:
    • Using PlayableDirector.SetGenericBinding() on the *second* item in TimelineAsset.outputs results in binding to the *first* track in the timeline window (when I would expect it to bind to the second track in the timeline window).
    • For a timeline with 2 tracks in the timeline window, TimelineAsset.outputs.Count() returns 3, when I would expect it to return 2. (PlayableDirector.playableGraph.GetOutputCount() correctly returns 2)
    It seems like there is some new inconsistency between how a timeline's tracks are represented in the timeline window vs how TimelineAsset.outputs is structured. (It also seems odd that TimelineAsset.outputs.Count() != PlayableDirector.playableGraph.GetOutputCount())

    What would the recommended way be to bind to a particular timeline track at runtime (and before the graph is played) in 2019.1?

    Here's a sample unity 2019.1.2f1 project that reproduces the issue with SetGenericBinding: https://www.dropbox.com/s/34vpf07zbbjuj5k/Timeline 2019.1 Binding Test.zip?dl=0
     
    Last edited: May 16, 2019
  26. seant_unity

    seant_unity

    Unity Technologies

    Joined:
    Aug 25, 2015
    Posts:
    1,516
    Yes, there is! The inconsistency comes from animation tracks with humanoid characters. There are extra outputs in the playable graph that put a consistent T pose for the character inside the editor. In the player, or playmode, they outputs should be the same.

    You can iterate using timelineAsset.GetOutputTracks(). That gives a list of tracks that produce PlayableOutputs (i.e. excludes groups, override tracks, etc...). As in your code above the track is the input for SetGenericBinding.
     
  27. mrtenda

    mrtenda

    Joined:
    Jun 6, 2017
    Posts:
    73
    I'm not sure I understand... I'm seeing that timelineAsset.GetOutputTracks().Count() returns 3 for a timeline with two animation tracks:

    upload_2019-5-16_14-33-21.png

    Are you saying that timelineAsset.GetOutputTracks().Count() should return 2 in this case? I'm still not sure how I would correctly iterate timelineAsset.GetOutputTracks() to bind to this timeline.
     
  28. seant_unity

    seant_unity

    Unity Technologies

    Joined:
    Aug 25, 2015
    Posts:
    1,516
    Ah, there is an output track for the signals in 2019.1 as well. It's a hidden track that's exposed by the pin button.
     
    hoperin likes this.
  29. mrtenda

    mrtenda

    Joined:
    Jun 6, 2017
    Posts:
    73
    Oh, I see, that makes sense!

    Part of my confusion was because our unity project has many timelines created before signals were introduced, so our new timelines have the signals output track and our old ones don't. I was able to get things to work by checking if the first item in TimelineAsset.GetOutputTracks() was a MarkerTrack or not, and skipping over it if it is.

    Thanks again @seant_unity, you saved me again :)
     
  30. R1PFake

    R1PFake

    Joined:
    Aug 7, 2015
    Posts:
    540
    Is there some way to "tag" (string value?) a (animation) track somehow in the timeline window other than giving it a specific name? My timeline contains multiple animation tracks and for some of them I want to use SetGenericBinding to set a specific animator at runtime, with the above method I can get all the animation tracks, but I need a way to check for these specific animation tracks.
     
  31. seant_unity

    seant_unity

    Unity Technologies

    Joined:
    Aug 25, 2015
    Posts:
    1,516
    There isn't anything that I can think of on the track other than name to identify them. However, I do have a couple suggestions:
    • Put them inside a group, and use the group track name.
    • Inverse the relationship - you can keep a list of animation tracks that you'd like to bind at runtime in a list. They are scriptable objects, so they are can be referenced like any other scriptable objects. This is something you would need to script,
      • Create a menu item callback that is active when the current selection is an animation track
      • The item can check TimelineEditor.inspectedDirector gameObject for a monobehaviour that contains a list of AnimationTracks, and add it to the list
      • (If you are using timeline 1.4, you could instead use a TrackAction to put it in the context menu for the animation track)
    • You can unhide the animation tracks in the project window by removing HideFlag.hideInHierarchy on the hideFlags property (make sure to Save the Project afterwards or call AssetDatabase.SaveAssets()). They will appear as sub-objects of the timeline, similar to AnimationClips. They can then be used in drag and drop operations to store references to the tracks.
     
    zyzyx and R1PFake like this.
  32. LezCT

    LezCT

    Joined:
    Nov 15, 2014
    Posts:
    55
    Hello, I've been using this base code to my own timeline binder since version 2018.x
    But it's acting weird since the timeline signals have been introduced to 2019.x
    Do you guys have an updated version of the script that works properly on 2019.x?
    Thank you in advance!

     
  33. seant_unity

    seant_unity

    Unity Technologies

    Joined:
    Aug 25, 2015
    Posts:
    1,516
    The problem is likely that the built-in marker track has pushed eveything down one item on the list. If it exists, it's the first track reported.

    Replacing line 33 with something like
    Code (CSharp):
    1. var track = (TrackAsset) ((timelineAsset.markerTrack == null) ? timelineAsset.outputs[i].sourceObject : timelineAsset.outputs[i+1].sourceObject);
    might fix it.
     
    LezCT likes this.
  34. LezCT

    LezCT

    Joined:
    Nov 15, 2014
    Posts:
    55
    Thank you very much! It works with:
    Code (CSharp):
    1. var track = (TrackAsset)((timelineAsset.markerTrack == null) ? timelineAsset.GetOutputTrack(i) : timelineAsset.GetOutputTrack(i+1));
     
    Rodolfo-Rubens and seant_unity like this.
  35. hyeoman

    hyeoman

    Joined:
    Jan 23, 2019
    Posts:
    2
    Thanks to the information provided I was able to create a playable director that is able to find two game objects by tag name and bind them to the appropriate tracks. The key is making sure the track names in the timeline match the gameobject tag names.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.Playables;
    5.  
    6. public class TimelineBinder : MonoBehaviour
    7. {
    8.     public PlayableDirector playableDirector; //the playable director attached to this object
    9.  
    10.     public Animator firstObjectToBind; //the first game Object in scenes Animator to Bind
    11.     public Animator secondObjectToBind; //the second game Object in scenes Animator to Bind
    12.    
    13.     private void Start()
    14.     {
    15.         //Find the game objects in the scene with the tags "Team1" and "Team2"
    16.         firstObjectToBind = GameObject.FindGameObjectWithTag("Team1").GetComponent<Animator>();
    17.         secondObjectToBind = GameObject.FindGameObjectWithTag("Team2").GetComponent<Animator>();
    18.         //Find the playable director components attached to the object
    19.         playableDirector = GetComponent<PlayableDirector>();
    20.        
    21.     }
    22.  
    23.     private void Update()
    24.     {
    25.        // Call the PlayTimeLine method
    26.        PlayTimeLine();
    27.     }
    28.  
    29.     public void PlayTimeLine()
    30.     {
    31.         //The tracks in the playable director timeline
    32.         foreach (var playableAssetOutput in playableDirector.playableAsset.outputs)
    33.         {
    34.            
    35.            // Debug.Log(playableAssetOutput.streamName.ToString());
    36.             if (playableAssetOutput.streamName == firstObjectToBind.tag.ToString())
    37.             {
    38.                 playableDirector.SetGenericBinding(playableAssetOutput.sourceObject, firstObjectToBind);
    39.             }
    40.             else if (playableAssetOutput.streamName == secondObjectToBind.tag.ToString())
    41.             {
    42.                playableDirector.SetGenericBinding(playableAssetOutput.sourceObject, secondObjectToBind);
    43.             }
    44.             playableDirector.Play();
    45.        
    46.         }
    47.     }
    48.  
    49. }//end class
     
  36. Midiphony-panda

    Midiphony-panda

    Joined:
    Feb 10, 2020
    Posts:
    243
    If multiple playable directors share the same TimelineAsset and modify it, won't they play the same unique Timeline ? What do you mean by "own parameters" ? Do you mean the bindings ?

    It seems to me that, to use one TimelineAsset but modify the timeline for multiple playable directors, we need to edit the PlayableGraph.


    Sorry for the necro-bump, I am still getting a grasp on Timeline.
     
    ModLunar likes this.
  37. horatiu665

    horatiu665

    Joined:
    Nov 22, 2012
    Posts:
    24
    Hi! I think this whole system might not work anymore in unity 2021.3 because
    timelineAsset.outputs[ i ] cannot be accessed this way because outputs is no longer a list, but an IEnumerable. Also, it turns out the bindings are saved now based on the referenced timeline, so you can't really hotswap timelines in a PlayableDirector because the bindings are gone.

    I'm trying to implement a localization system that switches the timeline depending on the language needed. I would like to keep all the old bindings of the old PlayableDirector with the new TimelineAsset. Seems like I should be able to use the theory in this thread to transfer the bindings from script, but I am afraid the API has changed quite a bit and I can't find my way anymore. Any pointers?

    By the way, track references could also be AudioSources, not just GameObjects.

    LE: I have tried to save the references by sourceObject and apply them to a new timeline asset. It sometimes works, but sometimes breaks, especially when the number of tracks is not the same, or the order has changed, and I suspect it does not always remember the order so it's not really a reliable method. Maybe the logic of it is flawed - after all, the timeline asset doesn't know about the objects it references except through the tracks. But it would be nice if we had a way to reference the tracks besides drag and drop, say by name or unique ID or something, then we could make our own scripts to do this kinda stuff.
     
    Last edited: Dec 12, 2022