Search Unity

Copy TimelineClips from one track to another using C#

Discussion in 'Timeline' started by KristofferH, May 7, 2021.

  1. KristofferH

    KristofferH

    Joined:
    Oct 27, 2012
    Posts:
    52
    I have multiple tracks in my TimelineAsset that should be animated in the same way, so I just want to add and setup all the clips on one track, and then run a script that copies all those clips and paste them into all the other tracks. I could of course do it manually using the ctrl+c, ctrl+v one track att the time, but it is to time consuming. I would also like to be able to copy clips from a track in one TimelineAsset to a track in another TimelineAsset if that is possible?

    I know there is a TrackAsset.GetClips() but how do I copy/duplicate them; can I use use Object.Instantiate()? But even after I have copied them, how do I add them to the new track? There is a TrackAsset.CreateClip() but it does not accept any parameters.

    It is a custom made animation track and animation clip, if that is an issue?

    @seant_unity Do you have any advice?
     
  2. DavidGeoffroy

    DavidGeoffroy

    Unity Technologies

    Joined:
    Sep 9, 2014
    Posts:
    542
  3. KristofferH

    KristofferH

    Joined:
    Oct 27, 2012
    Posts:
    52
    Thank you, I'll give it a go. But how do I copy a clip; do I use Object.Instantiate()?
     
  4. DavidGeoffroy

    DavidGeoffroy

    Unity Technologies

    Joined:
    Sep 9, 2014
    Posts:
    542
    That is a good question.
    I've been looking at the code for the past 20 minutes, and I don't see a straightforward way to clone a clip without access to some internal methods.

    You can't use Object.Instantiate, because the TimelineClip is not a ScriptableObject.
    You can try object.MemberwiseClone or you can do what we do in some cases: wrap it in a ScriptableObject, serialize it and use Object.Instantiate() to clone it.

    Even then, there are subtilities to be aware of. A lot of things are serialized by reference, and need a deep copy.

    If you use curves on your clips, you will need to clone them. Here is the code we use for this:
    Code (CSharp):
    1.  
    2. if (clip.curves != null)
    3. {
    4.     newClip.CreateCurves(AnimationTrackRecorder.GetUniqueRecordedClipName(newOwner, clip.curves.name));
    5.     EditorUtility.CopySerialized(clip.curves, newClip.curves);
    6.     TimelineCreateUtilities.SaveAssetIntoObject(newClip.curves, newOwner);
    7. }
    8.  
    Code (CSharp):
    1.  
    2. public static void SaveAssetIntoObject(Object childAsset, Object masterAsset)
    3. {
    4.         if (childAsset == null || masterAsset == null)
    5.             return;
    6.  
    7.         if ((masterAsset.hideFlags & HideFlags.DontSave) != 0)
    8.         {
    9.             childAsset.hideFlags |= HideFlags.DontSave;
    10.         }
    11.         else
    12.         {
    13.             childAsset.hideFlags |= HideFlags.HideInHierarchy;
    14. #if UNITY_EDITOR
    15.             if (!AssetDatabase.Contains(childAsset) && AssetDatabase.Contains(masterAsset))
    16.                 AssetDatabase.AddObjectToAsset(childAsset, masterAsset);
    17. #endif
    18.         }
    19.  }
    20.  
    And depending on your use case, you may want to duplicate the PlayableAsset associated to your TimelineClip.

    All in all, we should just expose a method to do this.
     
    mandisaw likes this.
  5. DavidGeoffroy

    DavidGeoffroy

    Unity Technologies

    Joined:
    Sep 9, 2014
    Posts:
    542
    If you want to see how we do it, you can look at the file
    Editor/TimelineHelpers.cs
    in the Timeline package.
     
  6. KristofferH

    KristofferH

    Joined:
    Oct 27, 2012
    Posts:
    52
    Hehe, yes please, that would be awesome if you could expose a method for this :) Extreamly usefull for automation.
     
  7. DavidGeoffroy

    DavidGeoffroy

    Unity Technologies

    Joined:
    Sep 9, 2014
    Posts:
    542
    There is the Duplicate method in
    Editor/Extensions/TrackExtensions.cs
    which is internal and probably does 90% of what you need. You should be able to access it with reflection.
     
    mandisaw likes this.