Unityのタイムラインのカスタムトラックを実装する際に、PlayableBehaviour内(特にTrackMixer内)でクリップの開始時間や終了時間を取得したくなったが、
簡単に取得できなかったので、メモがてらにブログに残すことにします。
PlayableBehaviour内でクリップタイミングを取得する
こちらのフォーラムの情報を参考にしました。
まず、お目当てのクリップのタイミングは、TimelineClipのプロパティより取得できます。
https://docs.unity3d.com/Packages/[email protected]/api/UnityEngine.Timeline.TimelineClip.html
具体的には、あるクリップの開始フレームが取得したければ、startプロパティから取得できます。
今回実現したいことへの課題は、TrackMixerからTimelineClipを参照できない点です。
ですが、TrackMixerを作成する際に通るTrackAsset.CreateTrackMixer内でGetClipsメソッドを利用することで、
各クリップのTimelineClipインスタンスを取得できます。
// https://forum.unity.com/threads/how-to-access-the-clip-timing-start-end-time-in-playablebehaviour-functions.494344/
public class LoopTrack : TrackAsset
{
public override Playable CreateTrackMixer(PlayableGraph graph, GameObject go, int inputCount)
{
var clips = GetClips();
foreach(var clip in clips)
{
// clipがお目当てのインスタンス
}
return ScriptPlayable<LoopMixer>.Create(graph, inputCount);
}
}TrackMixer内(この例ではLoopMixer)で触ることができるのは各クリップのPlayableBehaviourなので、
下記のLoopDataに示すように、Clipを定義します。
// https://forum.unity.com/threads/how-to-access-the-clip-timing-start-end-time-in-playablebehaviour-functions.494344/
public class LoopData : PlayableBehaviour
{
// PlayableBehaviour内にクリップ情報を保持する変数を定義しておく
[NonSerialized]public TimelineClip Clip;
}では、CreateTrackMixerメソッド内で取得したTimelineClipをどうやって渡すかというと、
下記に示すように、クリップアセットであるPlayableAsset(この例ではLoopClip)に一度TimelineClipを渡してやり、
その後、クリップアセットからPlayableBehaviourを生成するPlayableAsset.CreatePlayableメソッド内で、
保持していたTimelineClipを渡すことで実現できます。
// https://forum.unity.com/threads/how-to-access-the-clip-timing-start-end-time-in-playablebehaviour-functions.494344/
[Serializable]
public class LoopClip : PlayableAsset, ITimelineClipAsset
{
[NonSerialized]public TimelineClip clipPassthrough = null;
public LoopData template = new LoopData ();
public ClipCaps clipCaps
{
get { return ClipCaps.None; }
}
public override Playable CreatePlayable(PlayableGraph graph, GameObject owner)
{
// 保持しているTimelineClipをPlayableBehaviourに渡す
template.Clip = clipPassthrough;
var playable = ScriptPlayable<LoopData>.Create (graph, template);
return playable;
}
}public class LoopTrack : TrackAsset
{
public override Playable CreateTrackMixer(PlayableGraph graph, GameObject go, int inputCount)
{
var clips = GetClips();
foreach(var clip in clips)
{
// CreateTrackMixer内で、各クリップの自身のTimelineClipをPlayableAssetに渡す
var loopClip = clip.asset as LoopClip;
loopClip.clipPassthrough = clip;
}
return ScriptPlayable<LoopMixer>.Create(graph, inputCount);
}
}こうすることで各々のクリップのTimelineClipに、トラックのPlayableBehaviourからアクセスすることができます。
// https://forum.unity.com/threads/how-to-access-the-clip-timing-start-end-time-in-playablebehaviour-functions.494344/
public class LoopMixer
{
public override void ProcessFrame(Playable playable, FrameData info, object playerData)
{
var selectedPlayable = (ScriptPlayable<LoopData>)playable.GetInput(0);
LoopData selectedPlayer = selectedPlayable.GetBehaviour();
// indexが0のクリップのクリップタイミングを取得している
// 先程定義したClipプロパティにTimelineClipが渡っている
Debug.Log("Clip Start: " + selectedPlayer.Clip.start);
}
}まとめ
PlayableBehaviour内ではTimelineClipインスタンスを取得できないため、クリップの開始や終了タイミングを取得することができないTrackAsset内でGetClipsメソッドによりTimelineClipが取得できるので、取得したクリップをPlayableBehaviourにわたすことで実現ができる