三連休
「三連休ですね~、何か予定があるんですか?」という質問が世の中で一番嫌いな皆さんこんにちは。オイオイ、いくら行楽の秋だからと言って誰もがドライブしたりBBQしたり観光したりするとは思うなよ、と言うことで、理容師のお姉さんへ、答えに窮する質問を投げかけるのはやめて下さい、それから髪を洗う時に不意に頭のツボを押すのもやめて下さい、変な声出そうになった。
この機会に知ってほしい事があるの~!!
というわけで、ダラダラ説明するよりまずは下の動画を見てほしい
まるで某巨大変身ヒーローみたいな仕草でキャラクターが画面外に飛んで行っていますが、別に意図的にそうした訳ではなく、本来は階段をジャンプしながら登って先に進む、という動作をDotweenのSequenceを使って実装した結果です。
Dotweenって何?Sequenceって美味しいの?っていう人は下のリンクを参照してください
要はGameObjectの移動を連続させて行う際に使用するAPIで、今回の場合はキャラクターに対して
- 階段までの経路を移動する
- 一段目の段差をジャンプして移動する
- 二段目の段差をジャンプして移動する
- 三段目の段差をジャンプして移動する
- 階段の端まで移動する
という動作を連続で行うように設定しています。
この時、1.と5.の移動にはDoPathによる経路移動を、2.3.4.のジャンプにはDoLocalJumpを使用します。
DoPathによる経路移動については下記参照
ソース的にはこんな感じです。
PathSeq = DOTween.Sequence(); // 階段までの経路移動 PathSeq.Append( myObj.transform.DOLocalPath(Path1Array, 6.0f, PathType.CatmullRom) .SetLookAt(0.05f, Vector3.forward) ); // 各段差をジャンプして移動 for(int iCnt = 0; iCnt < Jump1Array.Length; iCnt++) { PathSeq.Append( myObj.transform.DOLocalJump(Jump1Array[iCnt], 0.5f, 1, 1.0f) ); } // 階段の端まで移動する PathSeq.Append( myObj.transform.DOLocalPath(Path2Array, 4.0f, PathType.CatmullRom) .SetLookAt(0.05f, Vector3.forward) );
何故飛んで行ってしまうのか?
ソースだけを眺めていると特におかしな処理はしていないので、移動先の座標さえ間違っていなければ意図通りの動作をすると思うのですが、結果としては大ジャンプを繰り返して画面外へ消える動作となっています。
これはきっとDotweenのバグに違いない、ということで、下のモデルを使って検証してみることにしました。
赤いCubeをSequenceを使って移動させるのですが、図の通りに同じ高さの場所をDOLocalJumpで移動させる場合と、異なる高さをDOLocalJumpで移動させる場合について比較してみます。
まずは同じ高さを移動する場合
特に問題なく移動できます。
次は違う高さを移動する場合
想定以上に飛び上がって移動し、最終位置もずいぶん高い位置になっています。
これをSequenceを使用せずにDOLocalJumpを連続で使用した場合は
きちんと指定先にジャンプ移動します。
これは垂直方向へ飛びあがる場合も同じで、Sequenceを使った場合とDOLocalJumpを連続で使用した場合では動作が全く異なります。
Sequenceを使った場合
DOLocalJumpを連続で使用した場合
Sequenceを使った場合は指定した位置以上へ飛び上がる結果となります。
また、これは飛び上がる場合だけでなく下へ飛び降りる場合も同じで、ジャンプを繰り返すほど下へ落ち込む軌道になります。
想定するに最終的な高さ(Y座標)の差異が、次のジャンプの計算に影響していると思われ、ジャンプを繰り返すほど大きなジャンプ軌道を描くようになり、最終的な位置も異なるようになります。
まぁこれらの挙動(不具合)について言及しているサイトを見つけることが出来なかったので想像の範囲なのですが、これまでの事象をまとめると
SequenceでDOLocalJumpを使用する場合は同じ高さ(Y座標)を移動する場合に限る
ということになります。
対処法
まぁ、Sequenceを使用せずにその都度DOLocalJumpを使用すればいいことなんですが、どうしてもSequenceを使いたい、ジャンプの時だけ別口で処理をするのは面倒くさい、という場合は
SequenceではDOLocalJumpではなくDOJumpを使用してください
移動先の座標をローカル座標ではなくワールド座標に変更するもの忘れずに。
先程のソースでDOLocalJumpとなっている箇所をDOJumpに変更した結果が以下の動画になります。
きちんと想定通りに動作してくれました。めでたしめでたし。