【Unity】オブジェクトの移動パターンをBGCurveで作ってタイムラインで制御してみる【Timeline】
動機
エネミーの移動パターンをUnityのTimelineで確認しながら調整したかった。
結果
想定通り出来ました。
概要
オブジェクトの移動のためBGCurveでパスを作り、Timeline上に移動パスクリップを組み合わせて軌道を制御します。
詳細
パスを作るにあたって、初期は UnityのLineRenderer でラインを作成し、TCBSplineCurve でスプラインを作成し座標を求めていましたが、エディットのやりにくさや見た目の悪さから、スプラインを作成するアセットを探してみたところ BG Curve という無料のアセットを見つけました。
エディットのしやすさや、スプラインの座標だけ取得できるプレハブも作成できるので、これに依存した PlayableAsset を作成することにしました。
BG Curve を作成
メニューから Component > BansheeGz > BGCurve > Components > BGCcMath を選択し、 BGCurve を作成します。
初期状態では何も設定されてません。
+を押すことに制御ポイントが追加されるのでパスを作っていきます。
出来上がったオブジェクトは プレハブ化して適当なフォルダに入れておきます。何パターンか用意しておいて良いと思います。
PathPlayableAsset の作成
出来上がったCurveを見ながらオブジェクトを移動させる PlayableAsset を作成します。
PlayableAssetは以下のとおりです。
using System;
using System.Linq;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;
[Serializable]
public class CurveRange
{
[Range(0, 1)]
public float begin = 0;
[Range(0, 1)]
public float end = 1;
} // class CurveRange
public class PathPlayableAsset : PlayableAsset
{
[SerializeField]
private ExposedReference<BansheeGz.BGSpline.Components.BGCcMath> Curve;
[SerializeField]
private CurveRange range;
//----------------------------------------------------------------------------
public override Playable CreatePlayable( PlayableGraph graph, GameObject owner)
{
var behaviour = new PathPlayableBehaviour();
behaviour.Curve = Curve.Resolve( graph.GetResolver());
behaviour.begin = range.begin;
behaviour.end = range.end;
behaviour.owner = owner;
return ScriptPlayable<PathPlayableBehaviour>.Create( graph, behaviour);
}
} // class PathPlayableAsset
Curve には BGCurveのプレハブを設定。
range.begin はカーブの開始ポイント0~1
range.end はカーブの終了ポイント
例えば bigin = 0.5 end = 1.0 の場合、1クリップで カーブの中間から最後まで再生されます。
制御コード
using System;
using System.Linq;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;
public class PathPlayableBehaviour : PlayableBehaviour
{
public BansheeGz.BGSpline.Components.BGCcMath Curve{ get; set; }
public GameObject owner{ get; set; }
public float begin{ get; set; }
public float end{ get; set; }
private float oldRatio = -1;
//----------------------------------------------------------------------------
// PlayState.Pausedに変更されたときに呼び出される
public override void OnBehaviourPause(
UnityEngine.Playables.Playable playable,
UnityEngine.Playables.FrameData info
)
{
}
//----------------------------------------------------------------------------
// PlayState.Playingに変更されたときに呼び出される
public override void OnBehaviourPlay(
UnityEngine.Playables.Playable playable,
UnityEngine.Playables.FrameData info
)
{
oldRatio = -1;
}
//----------------------------------------------------------------------------
// PlayableGraphのProcessFrameフェーズの間に呼び出される
// ProcessFrameはあなたのPlayableがその仕事をする段階です。
// PlayableがPlayPlayableOutputを直接または間接的に再生して接続するときに、各フレームに対して呼び出されます。
public override void ProcessFrame(
UnityEngine.Playables.Playable playable,
UnityEngine.Playables.FrameData info,
object playerData
)
{
if( owner == null) return;
if( Curve == null) return;
var duration = UnityEngine.Playables.PlayableExtensions.GetDuration( playable); // クリップの長さ
var localTime = UnityEngine.Playables.PlayableExtensions.GetPreviousTime( playable); // 現在の時間
float ratio = (float)( localTime / duration);
if( oldRatio >= 0 && oldRatio < ratio)
{
float rangeDist = end - begin;
var oldPos = Curve.CalcPositionByDistanceRatio( begin + rangeDist * oldRatio );
var nowPos = Curve.CalcPositionByDistanceRatio( begin + rangeDist * ratio );
oldRatio = ratio;
var diff = nowPos - oldPos;
owner.transform.position += diff;
}
oldRatio = ratio;
}
} // class PathPlayableBehaviour
悩んだところが、計算結果を絶対座標で設定すると、バリエーションが作りにくくなるのでありえない。タイムラインのプレビューで挙動を見たいため 前フレームからの差分を足して相対座標を計算しています。そのため、開始位置の設定はしていません。別途 Signal や 管理モジュールが座標を設定する必要があります。このあたりはいい感じに調整してください。
Timelineにおいて調整する。
TimelineにPlayableTrack を作成します。
PathPlayableAssetをおいていきます。
PathPlayableAsset の Inspector の Curve に 作成した BGCurve を設定します。
PathPlayableAssetは複数配置してキャラの動きを制御していきます。
ゲームオブジェクトに Timeline を設定する
適当に作ったゲームオブジェクトに Playable Director を追加し、先程作成した Timeline を設定してみます。
これで再生してみた結果がこうなります。
前回PostしたLuaPlayableAsset と組み合わせてみる。
まだまだ調整が甘いですが、遊べるものができたら公開しようかと思います。