1
Help us understand the problem. What are the problem?
Organization

Unityタイムラインでベジェ曲線に沿ってオブジェクトを移動する

はじめに

タイムラインで軌道にそってオブジェクトを動かすことはアニメーションでも実現可能ですが、軌跡が見えないのでタイムラインを拡張して実装しようと思いました。
GitHubに公開していて、OpenUPMにも登録してあります。

143799354-433e3214-bd28-4a22-a105-77f4bce7dc58.png

使い方

使い方はGitHubのReadMeに記述してあるので、こちらをご参照ください。

こちらの記事では上記パッケージを例にタイムラインの拡張方法を書いていきます。

タイムライン拡張

WayPointSystemForTimelineを例に拡張方法を書いていきます。

タイムライン拡張に必要な3大クラス

今回はトラック同士をブレンドしないので、タイムライン拡張に必要なクラスは3つになります。

PlayableTrack

トラック作成を担うクラスです
image.png

[Serializable]
[TrackClipType(typeof(WaypointTimelineClip))]
[TrackBindingType(typeof(WaypointComponent))]
public class WaypointTimelineTrack : PlayableTrack {

}

ブレンドが必要な場合はTrackAssetを継承するようです。
[参考(https://light11.hatenadiary.com/entry/2019/05/16/214328#Clip%E3%82%92%E4%BD%9C%E3%82%8B)

Serializable
タイムラインで編集した情報はファイルに保存して、実行時にはそこからオブジェクトを作る必要があるので、これから作成するクラスにこちらの属性はつけるようにしています。(つけなくても良い場合もあると思いますが、基本的につけていれば間違いないと思います)

TrackClipType
トラック上に配置するクリップのタイプの指定します。
WaypointTimelineClipの詳細は後述のPlayableAssetをご参照ください。

TrackBindingType
トラックに参照を持たせたいオブジェクトがある場合に指定します。
image.png

後述のPlayableBehaviourでこちらを取得して操作することが可能です。

PlayableAsset

タイムライン上のクリップに該当します。
image.png

[Serializable]
public class WaypointTimelineClip :  PlayableAsset, ITimelineClipAsset {
    public WaypointTimelinePlayableBehaviour template = new WaypointTimelinePlayableBehaviour();

    public ClipCaps clipCaps => ClipCaps.SpeedMultiplier;

    public override Playable CreatePlayable(PlayableGraph graph, GameObject owner) {
        var playable = ScriptPlayable<WaypointTimelinePlayableBehaviour>.Create(graph, template);
        return playable;
    }
}

後述のPlayableBehaviourとPlayableGraphからScriptPlayableを生成します。
おまじないのようなものでほとんどケースで書き方はあまり変わらないかと思います。

ITimelineClipAssetはクリップの性質を決めるもので指定したいときに継承します。
clipCapsプロパティを実装して性質を指定します。
今回はブレンドを対応しないためSpeedMultiplierのみを指定しました。(これもなくてもいいかも)
複数指定したい場合は|でつなげて指定していきます。

今回のSpeedMultiplierのみの指定だと以下のようになります。
image.png

また、ITimelineClipAssetを継承しない場合はクリップのインスペクターは以下のようになります。
image.png
指定しない場合はClipCaps.Blendingが設定されるようです。

PlayableBehaviour

クリップが再生されているときのふるまいを実装します。

[Serializable]
public class WaypointTimelinePlayableBehaviour : PlayableBehaviour {
    public override void ProcessFrame(Playable playable, FrameData info, object playerData) {
        if (playerData == null) {
            return;
        }

        var wayPointsComponent = playerData as WaypointComponent;

        double t = playable.GetTime() / playable.GetDuration();
        wayPointsComponent.SetPosition((float)t);
    }
}

今回はProcessFrameのみを使用して1フレームごとの更新処理を記述します。
他にもポーズ時やクリップ再生が始まったときなどの処理を書くことができます。
PlayableTrackのTrackBindingTypeで指定したものがobjectで渡されてくるのでキャストでコンポーネントにアクセスすることができます。
WaypointComponentに0.0f~1.0fの補完値を渡すことでベジェ曲線上の位置にPositionを変更することができるので、クリップの現在の時間をクリップの長さで割って正規化して渡しています。

ベジェ曲線上に移動させているMonoBehaviour

タイムライン側は3つのクラスを作成して、それらの中身も少ない記述量で今回のシステムを実現しています。
ベジェ曲線に関する計算はWaypointComponentですべて実装されています。

今回の記事はベジェ曲線の計算に関する内容ではないので説明は省かさせていただきます。

ベジェ曲線を編集するためのエディター拡張

上記と同じくエディタ拡張に関する記事ではないので説明は省かさせていただきます。

現状ベジェ曲線の編集がしやすいかどうかがいまいちなのでこちらは改善する余地はありそうです・・・

(余談)クリップのインスペクター上でPlayableBehaviourのフィールドを設定する

今回のシステムは特に設定することはないのでなくても大丈夫ですが、インスペクターで値を設定することが可能です。
(今後機能追加するときに必要になるかも)
WaypointTimelinePlayableBehaviourに

public int test;

を追加すると以下のように表示されます
image.png

Spine公式のタイムライン拡張のスクリプトを参考にさせて頂いたのですが、割と力技でした。
スクリプトはこちらになります。

最後に

タイムライン拡張はとっかかりがないとなかなか手を付けにくいのですが、一度簡単なものを作ると今後スムーズに作れるようになると思います。
これからタイムライン拡張をしようと思われている方に参考になれば幸いです。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
1
Help us understand the problem. What are the problem?