こんにちは、ともくんのゲーム作り部屋にようこそ!
このページでは、
「カメラをプレイヤーに追従させたい!」
「プレイヤーが移動したらカメラも動かしたい!」
というお悩みの方に向けた内容となっています。
ゲームでよくあるカメラワークとして、プレイヤーの移動に合わせてカメラも移動させるといった処理があります。
例えば、FPSなどのゲームでは、プレイヤーの視点でゲームを進めていくことになるため、カメラをプレイヤーと一緒に動かす必要があります。
Unityでプレイヤーに対してカメラを自動で動かして追従させる場合、
といった方法で、カメラを追従させる処理を作っていきます。
そこで、このページでは、Unityでプレイヤーが移動した際に、カメラを追従させる方法についてまとめていきます。
なお、2Dゲームでのカメラの追従方法は以下のページでも解説していますので、そちらを参考にしてください。
プレイヤーの移動に合わせてカメラを追従させる
ここでは、以下の青色のオブジェクトをプレイヤーと見立てて、カメラを追従させていく処理を作っていきます。

プレイヤーの移動処理を作る
まずは、プレイヤーの移動処理を作っていきます。
プレイヤーの移動は、キーボードのWASDキーを使って操作できるようにしたいので、プレイヤーにRigidbodyとColliderのコンポーネントを紐づけて、以下のスクリプトをアタッチしておきます。
using UnityEngine;
public class PlayerController : MonoBehaviour
{
Rigidbody rb;
float force = 5.0f; // オブジェクトを動かす際の力
float speed_X; // オブジェクトのX軸における速度
float speed_Z; // オブジェクトのZ軸における速度
float maxSpeed = 4.0f; // オブジェクトの最大速度
Vector3 prePos; // 前フレームでのオブジェクトの座標位置
Quaternion target; // オブジェクトの回転量
void Start()
{
rb = GetComponent<Rigidbody>();
prePos = transform.position; // スタート地点の座標を代入
}
void Update()
{
// 現在の速度を取得
speed_X = Mathf.Abs(rb.linearVelocity.x); // X軸における線速度
speed_Z = Mathf.Abs(rb.linearVelocity.z); // Z軸における線速度
// キー操作による移動処理
if (speed_X < maxSpeed && speed_Z < maxSpeed) // 速度制限
{
if (Input.GetKey(KeyCode.W))
{
rb.AddForce(0, 0, force);
}
if (Input.GetKey(KeyCode.S))
{
rb.AddForce(0, 0, -force);
}
if (Input.GetKey(KeyCode.D))
{
rb.AddForce(force, 0, 0);
}
if (Input.GetKey(KeyCode.A))
{
rb.AddForce(-force, 0, 0);
}
}
// オブジェクトの回転処理
Vector3 direction = transform.position - prePos; // フレーム間での座標の差分
if (direction != Vector3.zero)
{
target = Quaternion.LookRotation(direction); // オブジェクトを回転させたい量
transform.rotation = Quaternion.RotateTowards(transform.rotation, target, 600f * Time.deltaTime); // 回転を加える処理
}
prePos = transform.position; // 現在の座標位置を代入しておく
}
}
移動処理は26行目から45行目のようにAddForceメソッドでそれぞれの方向に力を加えるようにしています。
また、プレイヤーのオブジェクトを移動している進行方向に向きを変えられるように、51行目で進行方向に対しての回転量をLookRotationメソッドで計算しておき、その値を52行目でRotateTowardsメソッドを使って少しずつ回転させるようにしています。
RotateTowardsを使わなくてもオブジェクトの向きは変えられますが、カメラを追従させる際に滑らかでならなくなってしまったので使っています。
これでゲームを実行してみると、

キー操作により、プレイヤーとなるオブジェクトが進行方向の向きに回転しながら移動することができています。
なお、移動させる際にオブジェクトが倒れないように、RigidbodyコンポーネントのFreeze PositionのY軸と、Freeze RotationのX軸とZ軸にチェックを入れています。

カメラを追従させる方法①:プレイヤーの子オブジェクトにする
プレイヤーの移動に合わせてカメラを追従させる方法として、最も簡単なのがカメラオブジェクトをプレイヤーの子オブジェクトにすることです。
オブジェクトで親子関係を作ると、子は親と相対関係になるため、親であるプレイヤーが動くと子のカメラも動くことになります。
子オブジェクトにする場合は、先にプレイヤーに対してどの角度や距離にカメラを設置したいか、表示したいカメラオブジェクトを選択して調整しておきます。

カメラ位置を調整できたら、ヒエラルキーウィンドウでマウスを使って、カメラオブジェクトをプレイヤーの子オブジェクトに入れてあげます。

そしてゲームを実行してみると、

プレイヤーが移動するとカメラも一緒に移動して、常にプレイヤーの後ろから撮影できているのが分かります。
このようにカメラを追従させたい場合は、その中心となるオブジェクトを親とした親子関係を作ることで、簡単に実装することができます。
ただし、例えば「プレイヤーの向きが変わってもカメラは回転させたくない」などのように、細かい調整を行いたい場合は、次に説明するスクリプトを使った追従処理の方がカスタマイズしやすくなります。
カメラを追従させる方法②:スクリプトで処理を加える
カメラをプレイヤーの子オブジェクトにしなくても、カメラにスクリプトをアタッチして処理を加えてあげることで、プレイヤーに追従させることができます。
ここでは、スクリプトを使って、
といった方法をそれぞれ説明していきます。
基本的な追従の仕方・仕組み
スクリプトでカメラをプレイヤーに追従させる場合、仕組みとしてはプレイヤーに対してカメラの座標の位置を一定にしてあげることになります。

実際に、カメラオブジェクトに対して以下のスクリプトをアタッチしてみます。
using UnityEngine;
public class CameraController : MonoBehaviour
{
public GameObject player; // プレイヤーのオブジェクト
void LateUpdate() // Updateよりも後で処理される
{
transform.position = player.transform.position + new Vector3(0, 3, -10); // プレイヤーの座標から少しずらした場所にカメラを設置
}
}
5行目でプレイヤーの変数をpublic修飾子を付けて宣言しておきます。
宣言しただけでは中身がまだ無いので、カメラオブジェクトを選択してインスペクターウィンドウからこの変数にプレイヤーオブジェクトを指定しておきます。

次に、9行目でtransform.positionを使って、カメラ座標の位置をプレイヤー座標の位置から、少しずらしたところに設定するように記述しています。
プレイヤーの座標に「new Vector3(0, 3, -10)」と足してあげることで、プレイヤーからY軸に「+3」、Z軸に「-10」の位置に、常にカメラを配置する状態を作ることができます。
また、カメラの移動処理は、プレイヤーの移動処理が行われた後に実施される必要があるため、7行目でUpdateメソッドよりも遅く処理されるLateUpdateメソッドの中に処理を記述しています。
これで実際にゲームを実行してみると、

カメラとプレイヤーの位置が常に一定になり、プレイヤーの移動に合わせてカメラを追従させることができるようになりました。
少し遅らせて滑らかに追従させる
先ほどは、プレイヤーが移動すると同時にカメラを移動させるという処理を作りましたが、カメラの移動をゆっくりにしてあげることで、画面の移動を滑らかにして追従させることができます。
using UnityEngine;
public class CameraController : MonoBehaviour
{
public GameObject player;
Vector3 velocity = Vector3.zero; // 速度を初期化している
void LateUpdate()
{
transform.position = Vector3.SmoothDamp(transform.position, player.transform.position + new Vector3(0, 3, -10), ref velocity, 0.3f); // カメラを少し遅れて移動させる処理
}
}
10行目でカメラの座標位置をSmoothDampメソッドで指定しています。
このSmoothDampメソッドとは、現在の場所から別の場所に移動する際に、秒数を指定することで、その時間をかけて移動する処理を行ってくれるVector構造体などで定義されているメソッドで、フレーム毎に経過時間における座標を返してくれます。
SmoothDampを記述する際は、引数にそれぞれの値を設定していくことになります。
Vector3.SmoothDamp(Vector3 current, Vector3 target,ref Vector3 currentVelocity, float smoothTime);
- current:現在の座標の位置
- target:移動させたい座標の位置
- currentVelocity:現在の速度を取得する変数(参照渡し)
- smoothTime:到達するまでのおおよその時間(秒数)
ここでは、カメラを現在の座標位置から、プレイヤーの座標のY軸に「+3」、Z軸に「-10」した場所に、おおよそ0.3秒で移動させるように記述しています。
また、現在の速度を取得する変数でvelocityを指定していますが、この変数はSmoothDamp内での計算で使われており、「ref」を使った参照渡しとなるため、初期値をVector3.zeroで代入しておき「ref」を付けて指定しています。
これでもう一度ゲームを実行してみると、

先ほどと同様にプレイヤーを追従しますが、プレイヤーよりもカメラの移動が少し遅れていて、画面の移動が滑らかになっているのが分かります。
プレイヤーの後ろからカメラを追従させる
これまでは、プレイヤーが前を向いていようが後ろを向いていようが、カメラの方向は常に一定方向でした。
今度は、カメラを子オブジェクトに入れた時と同じく、カメラの向きも回転させて、常にプレイヤーの後ろからカメラを追従させる処理を作ってみます。

以下のように、カメラのスクリプトを修正してみます。
using UnityEngine;
public class CameraController : MonoBehaviour
{
public GameObject player;
void LateUpdate()
{
transform.position = player.transform.position + new Vector3(0, 3, 0) + player.transform.forward * -10; // プレイヤーの後ろ側にカメラを設置
transform.rotation = player.transform.rotation; // プレイヤーと向きとカメラの向きを一緒にする
}
}
9行目でカメラの座標位置を変更する処理を行っています。
カメラの座標位置は、プレイヤーの座標に対して、Y軸の場所はこれまでと同様に「+3」してあげて、X軸とZ軸の値は「transform.forward」でオブジェクトの向きを取得して、そこから「-10」ずらすようにしています。
このtransform.forwardとは、オブジェクトを基準とした軸で正面方向(Z軸)に対してのベクトル(0, 0, 1)を取得することができる変数で、これに「-10」をかけることで、オブジェクトの後ろ側にずれた場所に常にカメラを配置することができます。

また、10行目でカメラの向きをプレイヤーの向きに置き換えてあげることで、カメラをプレイヤーと同じ角度で回転させる処理を行っています。
これでゲームを実行してみると、

プレイヤーの向きが変わると、それに合わせてカメラの向きも変わりながら、追従しているのが分かります。
まとめ
このページでは、Unityでカメラをプレイヤーの移動に合わせて追従させる方法をまとめていきましたが、いかがでしたでしょうか?
カメラを特定のオブジェクトに追従させる場合は、子オブジェクトに入れてしまうのが最も簡単な方法になります。
ただし、オブジェクトが回転するとカメラも自動的に回転することになるので、この回転を防ぐ場合はスクリプトを使って記述する必要があります。
また、カメラを追従させるのと組み合わせて、マウスを使った視点移動の処理を加えることで、よりFPSなどのゲームに近づくので、以下のページも参考にしてみてください。
最後までお読みいただきまして、ありがとうございました!
コメント