風邪の季節
今年は暖冬なのですっかり忘れていたのですが、やっぱり風邪の季節には変わらないようで、私の周りでもインフルエンザに罹患したという報告が聞こえてくるようになってきました。
それに加えて新型コロナでパンデミックが起こるか起こらないのか心配になる話題も世間では広まっていますが、それでも通勤通学のスケジュールには変わりのない皆さんこんにちは。
たぶん日本ってアイアムアヒーローみたいなウィルスが蔓延しても朝は相変わらず満員電車になると思う。
例えば
ゲームを作っていると移動するプレイヤーをカメラで追い続けるとか、他のキャラクターを後ろに並べて後を追わせるとか、何かしらの追従処理が必要となる場面がでてきたりします。
今回は下の図ような、白い玉を追いかける黄色の玉の制御について考えてみます。
白い玉の動きに合わせて一定距離の間隔をあけて黄色の玉が移動します、が、黄色の玉は白い玉の子オブジェクトではありません。
なので、追従させるにはUpdate関数で白い玉が移動した距離分、黄色の玉も動かすという処理を行いますが、今回の場合はキーが押下されたタイミングで黄色の玉は白い玉との相対位置を変更する、という処理も加えます。
キーを押すと黄色い玉が反対側のキューブの位置へ移動します。
各キューブは白い玉の子オブジェクトなので白い玉の動きに合わせて動いています。
まぁ、上の動画ぐらいの動作なら実装は難しくないと思うのですが玉の位置が一瞬で変わってしまうのは味気ないので、白い玉と一緒に動きつつ、相対位置も変わるように一定時間を掛けて移動させてたい。
DOTweenを使う
オブジェクトを動かすと言えばDOTweenなのでDOTweenのDoMoveで動かしてみます。キーを押したタイミングで
yellowBall.transform.DOMove(目的のキューブの位置, 移動時間)
上記のようにDOMoveを発行して移動を行います。目的地に達したら白い玉への追従を再開して一定距離の間隔をあけて移動するようにします。
。。。まぁそうなるわなぁ、ってことで、DOMoveで移動中も白い玉は動いているので、移動を開始した時のキューブの位置からキューブの位置は随時変わっていきます。
そのため、指定した移動時間後にはあさっての位置へ黄色い玉が移動したように見えてしまいます。
これを解消するにはTween発行後に目的地を変える必要がある、というわけで、そのような趣旨の為の関数がChangeEndValueとなっています。
ChangeEndValue
この関数はその名前の通り、発行したTweenの最終的な値を変える関数なのですがDoMoveとは異なりtransformではなく、Tween発行した際の戻り値(Tweener)に対して呼び出すことのできる関数です。
ChangeEndValue(新しい目標地点, 現在地点を開始地点にする[true/false])
この関数を使ってDOMove発行後、Update関数内で目的のキューブの位置を新しい目標地点としてフレーム毎に更新したら白い玉を追いかけながらキューブの位置へ移動する動きとなりそうです。
んー・・・何故か目標地点近くまでは移動するものの、白い玉が止まらない限り目的点に達することができない。
色々と試行錯誤してみましたが、この現象は変わりませんでした。
原因を考える
思うに、Update関数にて最初にDOMoveで目的地と移動時間を指定するわけですが、その後、フレーム毎にChangeEndValueで目的地を変更しても、そこからの移動時間は毎回同じなので、その間に目的地も前に移動してしまう、フレーム毎に目的地を変えてもその時間内に目的地が前に移動してしまうので、どんなにChangeEndValueを繰り返して目標地点を更新しても、その目的地点が前方に移動する限り延々と到着しないという、ちょっとした「アキレスと亀」みたいな状態に陥っているのではないかと推測されます。
分かりづらいですか?絵にかくとこんな感じ
目標地点Bに辿り着くには毎回必ずX秒間掛かるので、結局辿り着けない
なのでChangeEndValueを使う場合は毎度対象との距離を確認して、一定距離以下になった場合はDOTween.KillでTweenerを停止するか、移動時間の指定を小さく(早く)して強引にでも目標地点に到着させる必要があるかと思います。
幸い、移動時間の指定の変更はChangeEndValueのオーバロードで第二引数で指定することができます。
ChangeEndValue(新しい目標地点, 新しい移動時間, 現在地点を開始地点にする[true/false])
で、この対処を行った動作がこちら
辿り着くことは辿り着きますが、やっぱり最後がぎこちないですね。んー・・・パラメータの設定の仕方もあるかもしれませんが
ちなみに今回の主旨とは離れるのですがDOTweenを使わず、Vector3.Lerpを使ってみたら・・・
こちらの方が素直に移動します。
ようは、追従処理は無理にDOTweenを使わなくっても・・・という結論になりました。