アイテムにつけたスクリプトに、レイの当たった場所を掴んで動かす処理を書いてみました。
まずクリックした時に呼ぶアイテムのメソッドの引数に、レイの当たった位置を渡して、アイテムではそれをローカル空間に変換します。メソッドを呼んだゲームオブジェクト(FPSカメラ)も記憶しておきます。
Vector3 effort;
GameObject manipulator;
// クリックされたとき
public void Touch(GameObject sender, Vector3 hitPoint)
{
effort = transform.InverseTransformPoint(hitPoint);
manipulator = sender;
// ...
}
そして、掴まれているときはUpdate()でリジッドボディのvelocityにアイテムを動かす方向を代入し続けます。
// 掴まれているときの処理
void Hold()
{
rb.velocity = (manipulator.transform.forward * 2f + manipulator.transform.position - transform.TransformPoint(effort)) * 10f;
}
velocityに代入した方向にアイテムが動きます。その方向を計算するためにまずはアイテムに来て欲しい位置を考えます。
まず①のようにプレイヤーの目の前に来て欲しいので、FPSカメラのtransform.positionとtransform.forwardを足します。正面から少し離したかったので、transform.forwardは2倍しています。
それに持ちたい地点からアイテムのピボットへのベクトルを足すと、アイテムの最終的な位置になります。
持ちたいのはレイが当たった地点です。アイテムは移動回転するので、クリックしたときにこれを一旦ローカル空間に変換して記憶しました。Update()でこれをワールド空間に戻しています。
transform.TransformPoint(effort)
この点の座標をアイテムのピボット座標から引くと、②の最後の緑色のベクトルになります。
transform.position - transform.TransformPoint(effort)
これにFPSカメラのtransform.positionとtransform.forwardを足せば最終的なアイテムの位置になりますが、Rigidbody.velocityに代入するのは、今のアイテムの位置からこの点への方向なので、今のアイテムの位置を引きます。
そのままではアイテムの動きが遅いので、そのベクトルを10倍にして代入しました。
rb.velocity = (manipulator.transform.forward * 2f + manipulator.transform.position - transform.TransformPoint(effort)) * 10f;
これで、レイが当たった位置を持てるようになりました。