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
にわたすことで実現ができる