動く足場の上に乗った物体を足場と一緒に動かしたい場合、足場のオブジェクトと親子関係にするのが定番だが、親子関係にすると不都合が出る場合がある。
たとえば、CharacterControllerで制御しているプレイヤーを動くオブジェクトの子供にすると、CharacterControllerの動作が怪しくなることなどがあった。
そのような場合に、なるべく簡単かつ軽量に同様の処理を実装したい。
前提として
・「足場」は次frameでどのように移動できるか予測できない
・「上に乗っている物体」は、足場の上で好きに動く(乗り物の上にいる操作キャラのように)
のような状態でも使える方法とする。
実装1:計算でゴリ押し実装
親子関係で無い以上、LateUpdate()内で、動く足場が前フレームの位置からどれだけ移動したか?どれだけ回転したか?を確認する方法になるが、ややこしい計算になる。
「平行移動」については、足場のposition変化量を物体のpositionに加算するだけで良いが、足場のrotationについては、足場の回転軸と物体の位置関係も考慮する必要がある。
Vector3系関数を使って計算する場合、お互いのlossyScaleに影響しないように考慮が必要な場合もある。
一応はそれっぽく動いたが、複雑な計算だと分かりづらく、意図的にイレギュラーな動きをさせたい場合などに応用が難しそうだったため、もっと簡単な方法を模索
実装2:目印オブジェクトを使う
動く足場の子オブジェクトとして、目印のオブジェクトを用意する。RigidbodyもColliderもRendererも無いEmptyオブジェクトで良い。
動く足場に乗った物体ごとに1つずつの目印を用意する
LateUpdate()内でやることは、
①目印のpositionが前フレームの目印のpositionと異なる場合
②物体のposition += 目印のposition - 前フレームの目印のposition
③目印のposition = 物体のposition
④目印のpositionを変数に格納(次フレームに①②で利用)
⑤目印のrotationがQuaternion(0f, 0f, 0f, 1f)と異なる場合
⑥物体のrotation = 物体のrotation * 目印のrotation
⑦目印のrotation = Quaternion(0f, 0f, 0f, 1f)
つまり、目印のrotationを毎フレーム「物体の座標」、「固定の方向」に合わせておく。
目印は足場の子オブジェクトなので、「物体が子オブジェクトだったらどれだけ動くか?」をトレースしてくれる。なので、次フレームでは物体の座標を「目印の座標変化量」だけ移動させ、物体の回転を「目印の回転」だけ回転させるだけ。
工夫したところは、前フレームの目印のrotationを覚えておいたり、物体のrotationと合わせたりしなくても、毎フレームQuaternion(0f, 0f, 0f, 1f)で固定しておけば、次フレームで変化分を簡単に反映できるところ。
処理がシンプルなので、「足場の動きの変化にあわせて揺らしたい」「移動や回転速度が一定以上になると追従を弱めたい」「足場から離れた時の慣性の計算に使いたい」ような場合にも工夫しやすい。
毎フレームの計算になるので、目印と物体のtransformを変数に入れておくこと。Quaternion(0f, 0f, 0f, 1f)も事前にnewで作って使い回すことを忘れずに。