256 lines
9.7 KiB
C#
256 lines
9.7 KiB
C#
![]() |
using System;
|
||
|
using System.Collections.Generic;
|
||
|
using UnityEngine;
|
||
|
using UnityEngine.Timeline;
|
||
|
using UnityEngine.Playables;
|
||
|
using UnityEngineInternal; // for metro type extensions
|
||
|
|
||
|
namespace UnityEngine.Timeline
|
||
|
{
|
||
|
public partial class TimelineAsset
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// Allows you to create a track and add it to the Timeline.
|
||
|
/// </summary>
|
||
|
/// <param name="type">The type of track to create. Must derive from TrackAsset.</param>
|
||
|
/// <param name="parent">Track to parent to. This can be null.</param>
|
||
|
/// <param name="name">Name to give the track.</param>
|
||
|
/// <returns>The created track.</returns>
|
||
|
/// <remarks>
|
||
|
/// This method will throw an InvalidOperationException if the parent is not valid. The parent can be any GroupTrack, or a supported parent type of track. For example, this can be used to create override tracks in AnimationTracks.
|
||
|
/// </remarks>
|
||
|
public TrackAsset CreateTrack(Type type, TrackAsset parent, string name)
|
||
|
{
|
||
|
if (parent != null && parent.timelineAsset != this)
|
||
|
throw new InvalidOperationException("Addtrack cannot parent to a track not in the Timeline");
|
||
|
|
||
|
if (!typeof(TrackAsset).IsAssignableFrom(type))
|
||
|
throw new InvalidOperationException("Supplied type must be a track asset");
|
||
|
|
||
|
if (parent != null)
|
||
|
{
|
||
|
if (!TimelineCreateUtilities.ValidateParentTrack(parent, type))
|
||
|
throw new InvalidOperationException("Cannot assign a child of type " + type.Name + " to a parent of type " + parent.GetType().Name);
|
||
|
}
|
||
|
|
||
|
|
||
|
var actualParent = parent != null ? parent as PlayableAsset : this;
|
||
|
TimelineUndo.PushUndo(actualParent, "Create Track");
|
||
|
|
||
|
var baseName = name;
|
||
|
if (string.IsNullOrEmpty(baseName))
|
||
|
{
|
||
|
baseName = type.Name;
|
||
|
#if UNITY_EDITOR
|
||
|
baseName = UnityEditor.ObjectNames.NicifyVariableName(baseName);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
var trackName = baseName;
|
||
|
if (parent != null)
|
||
|
trackName = TimelineCreateUtilities.GenerateUniqueActorName(parent.subTracksObjects, baseName);
|
||
|
else
|
||
|
trackName = TimelineCreateUtilities.GenerateUniqueActorName(trackObjects, baseName);
|
||
|
|
||
|
TrackAsset newTrack = AllocateTrack(parent, trackName, type);
|
||
|
if (newTrack != null)
|
||
|
{
|
||
|
newTrack.name = trackName;
|
||
|
TimelineCreateUtilities.SaveAssetIntoObject(newTrack, actualParent);
|
||
|
}
|
||
|
return newTrack;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates a track and adds it to the Timeline Asset.
|
||
|
/// </summary>
|
||
|
/// <param name="parent">Track to parent to. This can be null.</param>
|
||
|
/// <param name="trackName">The name of the track being created.</param>
|
||
|
/// <typeparam name="T">The type of track being created. The track type must be derived from TrackAsset.</typeparam>
|
||
|
/// <returns>Returns the created track.</returns>
|
||
|
/// <remarks>
|
||
|
/// This method will throw an InvalidOperationException if the parent is not valid. The parent can be any GroupTrack, or a supported parent type of track. For example, this can be used to create override tracks in AnimationTracks.
|
||
|
/// </remarks>
|
||
|
public T CreateTrack<T>(TrackAsset parent, string trackName) where T : TrackAsset, new()
|
||
|
{
|
||
|
return (T)CreateTrack(typeof(T), parent, trackName);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates a track and adds it to the Timeline Asset.
|
||
|
/// </summary>
|
||
|
/// <param name="trackName">The name of the track being created.</param>
|
||
|
/// <typeparam name="T">The type of track being created. The track type must be derived from TrackAsset.</typeparam>
|
||
|
/// <returns>Returns the created track.</returns>
|
||
|
public T CreateTrack<T>(string trackName) where T : TrackAsset, new()
|
||
|
{
|
||
|
return (T)CreateTrack(typeof(T), null, trackName);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates a track and adds it to the Timeline Asset.
|
||
|
/// </summary>
|
||
|
/// <typeparam name="T">The type of track being created. The track type must be derived from TrackAsset.</typeparam>
|
||
|
/// <returns>Returns the created track.</returns>
|
||
|
public T CreateTrack<T>() where T : TrackAsset, new()
|
||
|
{
|
||
|
return (T)CreateTrack(typeof(T), null, null);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Delete a clip from this timeline.
|
||
|
/// </summary>
|
||
|
/// <param name="clip">The clip to delete.</param>
|
||
|
/// <returns>Returns true if the removal was successful</returns>
|
||
|
/// <remarks>
|
||
|
/// This method will delete a clip and any assets owned by the clip.
|
||
|
/// </remarks>
|
||
|
public bool DeleteClip(TimelineClip clip)
|
||
|
{
|
||
|
if (clip == null || clip.GetParentTrack() == null)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
if (this != clip.GetParentTrack().timelineAsset)
|
||
|
{
|
||
|
Debug.LogError("Cannot delete a clip from this timeline");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
TimelineUndo.PushUndo(clip.GetParentTrack(), "Delete Clip");
|
||
|
if (clip.curves != null)
|
||
|
{
|
||
|
TimelineUndo.PushDestroyUndo(this, clip.GetParentTrack(), clip.curves);
|
||
|
}
|
||
|
|
||
|
// handle wrapped assets
|
||
|
if (clip.asset != null)
|
||
|
{
|
||
|
DeleteRecordedAnimation(clip);
|
||
|
|
||
|
// TODO -- we should flag assets and owned, instead of this check...
|
||
|
#if UNITY_EDITOR
|
||
|
string path = UnityEditor.AssetDatabase.GetAssetPath(clip.asset);
|
||
|
if (path == UnityEditor.AssetDatabase.GetAssetPath(this))
|
||
|
#endif
|
||
|
{
|
||
|
TimelineUndo.PushDestroyUndo(this, clip.GetParentTrack(), clip.asset);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var clipParentTrack = clip.GetParentTrack();
|
||
|
clipParentTrack.RemoveClip(clip);
|
||
|
clipParentTrack.CalculateExtrapolationTimes();
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Deletes a track from a timeline, including all clips and subtracks.
|
||
|
/// </summary>
|
||
|
/// <param name="track">The track to delete. It must be owned by this Timeline.</param>
|
||
|
/// <returns>True if the track was deleted successfully.</returns>
|
||
|
public bool DeleteTrack(TrackAsset track)
|
||
|
{
|
||
|
if (track.timelineAsset != this)
|
||
|
return false;
|
||
|
|
||
|
// push before we modify properties
|
||
|
TimelineUndo.PushUndo(track, "Delete Track");
|
||
|
TimelineUndo.PushUndo(this, "Delete Track");
|
||
|
|
||
|
TrackAsset parent = track.parent as TrackAsset;
|
||
|
if (parent != null)
|
||
|
TimelineUndo.PushUndo(parent, "Delete Track");
|
||
|
|
||
|
var children = track.GetChildTracks();
|
||
|
foreach (var child in children)
|
||
|
{
|
||
|
DeleteTrack(child);
|
||
|
}
|
||
|
|
||
|
DeleteRecordedAnimation(track);
|
||
|
|
||
|
var clipsToDelete = new List<TimelineClip>(track.clips);
|
||
|
foreach (var clip in clipsToDelete)
|
||
|
{
|
||
|
DeleteClip(clip);
|
||
|
}
|
||
|
RemoveTrack(track);
|
||
|
|
||
|
TimelineUndo.PushDestroyUndo(this, this, track);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
internal void MoveLastTrackBefore(TrackAsset asset)
|
||
|
{
|
||
|
if (m_Tracks == null || m_Tracks.Count < 2 || asset == null)
|
||
|
return;
|
||
|
|
||
|
var lastTrack = m_Tracks[m_Tracks.Count - 1];
|
||
|
if (lastTrack == asset)
|
||
|
return;
|
||
|
|
||
|
for (int i = 0; i < m_Tracks.Count - 1; i++)
|
||
|
{
|
||
|
if (m_Tracks[i] == asset)
|
||
|
{
|
||
|
for (int j = m_Tracks.Count - 1; j > i; j--)
|
||
|
m_Tracks[j] = m_Tracks[j - 1];
|
||
|
m_Tracks[i] = lastTrack;
|
||
|
Invalidate();
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal TrackAsset AllocateTrack(TrackAsset trackAssetParent, string trackName, Type trackType)
|
||
|
{
|
||
|
if (trackAssetParent != null && trackAssetParent.timelineAsset != this)
|
||
|
throw new InvalidOperationException("Addtrack cannot parent to a track not in the Timeline");
|
||
|
|
||
|
if (!typeof(TrackAsset).IsAssignableFrom(trackType))
|
||
|
throw new InvalidOperationException("Supplied type must be a track asset");
|
||
|
|
||
|
var asset = (TrackAsset)CreateInstance(trackType);
|
||
|
asset.name = trackName;
|
||
|
|
||
|
if (trackAssetParent != null)
|
||
|
trackAssetParent.AddChild(asset);
|
||
|
else
|
||
|
AddTrackInternal(asset);
|
||
|
|
||
|
return asset;
|
||
|
}
|
||
|
|
||
|
void DeleteRecordedAnimation(TrackAsset track)
|
||
|
{
|
||
|
var animTrack = track as AnimationTrack;
|
||
|
if (animTrack != null && animTrack.infiniteClip != null)
|
||
|
TimelineUndo.PushDestroyUndo(this, track, animTrack.infiniteClip);
|
||
|
|
||
|
if (track.curves != null)
|
||
|
TimelineUndo.PushDestroyUndo(this, track, track.curves);
|
||
|
}
|
||
|
|
||
|
void DeleteRecordedAnimation(TimelineClip clip)
|
||
|
{
|
||
|
if (clip == null)
|
||
|
return;
|
||
|
|
||
|
if (clip.curves != null)
|
||
|
TimelineUndo.PushDestroyUndo(this, clip.GetParentTrack(), clip.curves);
|
||
|
|
||
|
if (!clip.recordable)
|
||
|
return;
|
||
|
|
||
|
AnimationPlayableAsset asset = clip.asset as AnimationPlayableAsset;
|
||
|
if (asset == null || asset.clip == null)
|
||
|
return;
|
||
|
|
||
|
TimelineUndo.PushDestroyUndo(this, asset, asset.clip);
|
||
|
}
|
||
|
}
|
||
|
}
|