FPSコントローラーのカメラが指定したオブジェクトの方へ向きかけたら、自動でそのオブジェクトが正面に見えるようにカメラを回転してみます。
まずターゲットのCubeにタグとコライダーを付けました。
プレイヤーのスクリプトでは、自動で注視するかどうかを切り替えるメソッドを作ります。
// FirstPersonController
bool autoLook; // 自動で注視するかどうか
Vector3 autoLookTarget; // 注視するものの位置
[SerializeField] AudioClip[] audios;
public void PrepareAutoLook(Transform target)
{
if (target.gameObject.tag == "Target")
{
autoLook = true;
autoLookTarget = target.position;
}
}
引数にターゲットのオブジェクトのTransformを入れます。今回はキー入力でこのメソッドを呼んでテストしました。
そして、Update()で上の変数がtrueのときに、ターゲットに向けてレイを投げます。
// Update()
// 状態0
if (state == 0)
{
// ...
if (autoLook)
{
RaycastHit hitTarget;
// レイキャストがヒット
if (Physics.Raycast(m_Camera.transform.position, autoLookTarget - m_Camera.transform.position, out hitTarget, 10f,~(1 << 9)))
{
if (hitTarget.collider.tag == "Target")
{
Vector3 dir = autoLookTarget - m_Camera.transform.position;
float dot = Vector3.Dot(m_Camera.transform.forward, Vector3.Normalize(dir));
if (dot >= 0.6f)
{
state = 5;
Warp(transform.position, Quaternion.FromToRotation(m_Camera.transform.forward, dir) * m_Camera.transform.rotation, true);
}
}
}
}
}
// 状態1
else if (state == 1)
{
// ...
}
// 状態2
else if (state == 2)
{
//...
レイキャストでは、距離を短めにして、プレイヤーの体にレイが当たらないようにマスクを設定しています。ヒットしたコライダーのタグからターゲットを判別して内積を計算します。
プレイヤーがターゲットの方を向いているときはプレイヤーの状態を変えてレイを飛ばすのをやめて、自動で回転させるメソッドを呼びます。このメソッドは一人称視点でロッカーの中に入って隠れるときに使ったのと同じです。
回転値は、プレイヤーのカメラの視線がターゲットに向くときの回転値と今の回転値を合わせたものです。
Quaternion.FromToRotation(m_Camera.transform.forward, dir) * m_Camera.transform.rotation
ワープが終わったら、移動と回転をロックして音を鳴らし、ロックを解除するメソッドを2秒後に呼びます。
// ワープが終わったら
if (autoLook)
{
autoLook = false;
canMove = false; // 動けなくする
LockCamera = true; // 回転をロック
m_AudioSource.clip = audios[0];
m_AudioSource.Play();
Invoke("EndAutoLook",2f); // 2秒後に呼ぶ
}
// ロックを解除する
void EndAutoLook()
{
LockCamera = false; // 回転のロック解除
canMove = true; // 動けるようにする
state = 0; // 状態を戻す
}
この移動・回転のロックやプレイヤーの状態などは、FirstPersonControllerに元々無く、新しく加えたものです。
移動・回転は、プレイヤーにしばらくターゲットを注視させたいのでロックしています。プレイヤーの状態は、自動で回転するメソッドが呼ばれた後に、一旦レイを飛ばすのをやめることさえできれば必要無いと思います。
これでカメラを自動で回転させてオブジェクトの方を向かせることができました。