Unityでカメラを追従させる方法:基本から応用まで

ゲーム開発

はじめに

Unityでキャラクターやオブジェクトを動かすとき、カメラがターゲットをうまく追従してくれると便利ですよね。 視点が見やすい位置を保ってくれると、ゲームの開発やデモシーンを作るうえで、ストレスなくプレイや確認を進められるのではないでしょうか。

ただし、単純にカメラを追従させるだけでも、制御が不安定になる場合があります。 いきなりスクリプトを組んでしまうと、カメラの揺れが激しくなったり、建物や障害物にめりこんでしまうこともあるかもしれません。 そこで、今回はUnityにおけるカメラ追従をテーマに、基本的な設定から実務に活かせるテクニックまで、段階的にお伝えしていきます。

この記事では、初心者でもわかりやすいように、シンプルなスクリプト例と一緒に注意点を解説します。 また、カメラをなめらかに動かすための関数や、さまざまなゲームジャンルでの具体的な使い方にも触れていきます。 最終的には、簡単なプロトタイプを組んでテストしながら、必要に応じて要件に合わせた調整ができるところまで理解を深めてみましょう。

それでは、まずはカメラ追従の基本概念から始めてみると良いかもしれません。

Unityにおけるカメラ追従の基本概念

Unityでは、カメラ自体もシーンに配置される一つのGameObjectです。 キャラクターや標的となるオブジェクトをカメラが追いかける場合、位置や向きをスクリプトで調整する必要があります。 この位置調整のしかたによっては、ゲーム体験が大きく変わることもありそうですね。

カメラ追従の方法は大きく分けていくつか存在します。 たとえば、ターゲットの座標に合わせてカメラを一定の距離を保ちながら追従させるシンプルな方法があります。 また、ターゲットの移動にあわせてカメラが自然にスムーズに遅れてついていくようにするには、LerpやSmoothDampなどの関数が活躍します。

さらに、カメラの追従と同時に障害物を考慮することも多いです。 壁がカメラとプレイヤーの間に入り込まないようにするには、RayやPhysics.Raycastを使う手がよく見られます。 まずは、これらのポイントをざっくり押さえたうえで、最初のシンプルな例から取り組んでみましょう。

シンプルなカメラ追従スクリプト

ゲーム開発の場面では、キャラクターの後ろからカメラがついてくるケースが多いですよね。 このとき、カメラの位置をターゲットの座標に対して固定的に調整してあげると、基本的な追従が可能になります。

カメラを固定オフセットで追従させる

まずは、カメラの位置をターゲットに対して固定オフセットを加えた状態で更新するスクリプトを見てみます。 ここではC#スクリプトを作成するときの一例をご紹介します。

using UnityEngine;

public class SimpleCameraFollow : MonoBehaviour
{
    public Transform target;
    public Vector3 offset = new Vector3(0f, 5f, -10f);

    void Update()
    {
        if (target == null)
        {
            return;
        }

        transform.position = target.position + offset;
    }
}

上の例は、ターゲットの位置 + オフセットという単純な計算でカメラ位置を決めています。 カメラにこのスクリプトをアタッチし、targetに追従させたいオブジェクトを設定すれば、基本的なカメラ追従が実現できるでしょう。

また、このようなシンプルな追従は、トップビューの2Dゲームや、平面的なマップであまり動きの激しくないゲームなどで役に立ちます。 ただし、動きの速いアクションゲームや3Dアドベンチャーゲームなどでは、このままだと視点の揺れが大きくて見づらいかもしれません。

UpdateではなくLateUpdateを使うケース

カメラの移動を行うタイミングとしては、LateUpdate()を使うことが推奨されるケースが多いです。 LateUpdate()は、すべての物体のUpdate()処理が終わった後に呼び出されるため、キャラクターが移動してからカメラを追従させる流れが自然につくれます。 次のように書き換えると、より安定したカメラ追従が行いやすくなりそうですね。

using UnityEngine;

public class SimpleCameraFollow : MonoBehaviour
{
    public Transform target;
    public Vector3 offset = new Vector3(0f, 5f, -10f);

    void LateUpdate()
    {
        if (target == null)
        {
            return;
        }

        transform.position = target.position + offset;
    }
}

ただし、どうしてもキャラクターの動きが激しい場合、単なるオフセット移動だと突然の方向転換で画面がちぐはぐになることがあります。 そこで、次に説明するようなスムージングを取り入れると見やすさが向上します。

なめらかなカメラ追従(LerpやSmoothDampの活用)

カメラをターゲットに追従させるとき、移動をなめらかにすることで視点の揺れを抑えられます。 Unityでは、Vector3.LerpVector3.SmoothDampといった関数がよく使われています。

Lerpで補間する方法

Vector3.Lerpは、二つのベクトル間を指定した割合で線形補間するための関数です。 ターゲットの座標とカメラの現在座標を補間することで、急激な移動を抑えながらカメラの位置を移動できます。 典型的なコード例は次のとおりです。

using UnityEngine;

public class SmoothCameraFollow : MonoBehaviour
{
    public Transform target;
    public Vector3 offset = new Vector3(0f, 5f, -10f);
    public float smoothSpeed = 0.125f;

    void LateUpdate()
    {
        if (target == null)
        {
            return;
        }

        Vector3 desiredPosition = target.position + offset;
        Vector3 smoothedPosition = Vector3.Lerp(transform.position, desiredPosition, smoothSpeed);
        transform.position = smoothedPosition;
    }
}

ここでのsmoothSpeedは、カメラの移動スピードを調整するための値です。 数値が小さすぎるとカメラが追いつけない感じになり、大きすぎるとあまりスムーズさを感じられなくなるかもしれません。

SmoothDampでより自然な慣性を表現する

もうひとつの方法としてVector3.SmoothDampを使うと、カメラに自然な慣性や加速度を表現できます。 SmoothDampは「現在位置から目的位置に向けて、一定の減衰を伴いながら移動する」という動きをします。

using UnityEngine;

public class SmoothDampCameraFollow : MonoBehaviour
{
    public Transform target;
    public Vector3 offset = new Vector3(0f, 5f, -10f);
    public float smoothTime = 0.3f;
    private Vector3 velocity = Vector3.zero;

    void LateUpdate()
    {
        if (target == null)
        {
            return;
        }

        Vector3 desiredPosition = target.position + offset;
        Vector3 smoothedPosition = Vector3.SmoothDamp(
            transform.position,
            desiredPosition,
            ref velocity,
            smoothTime
        );
        transform.position = smoothedPosition;
    }
}

velocityという変数を引数に入れることで、慣性の情報を保持できるようになっています。 ゲーム中にプレイヤーが急加速・急停止を繰り返す場合でも、この方法なら比較的見やすい視点を確保できるでしょう。

カメラの向きをターゲットに合わせる

カメラの向きをターゲット方向に合わせる場合は、transform.LookAt(target)を使うと簡単に注視させることができます。 先ほどのスクリプトに1行追加すると、以下のようになります。

void LateUpdate()
{
    if (target == null)
    {
        return;
    }

    Vector3 desiredPosition = target.position + offset;
    Vector3 smoothedPosition = Vector3.Lerp(transform.position, desiredPosition, smoothSpeed);
    transform.position = smoothedPosition;

    transform.LookAt(target);
}

このとき、キャラクターの中心よりもやや上を狙うために、target.position + Vector3.up * 1.0fなどのように微調整する場合もあります。 これにより、キャラクターの頭上あたりをカメラが向くため、見下ろすアングルが自然に確保されるかもしれません。

実務で気をつけたいポイントと活用例

実務でカメラ追従を行うときは、単純に位置と向きを合わせるだけでは不十分なケースが多いです。 とくに、シーンに障害物が多い場合や、予期せずターゲットが画面外に消えるような状況が考えられますよね。

障害物をよける工夫

アクションゲームやアドベンチャーゲームでは、カメラとターゲットの間に壁やオブジェクトが入り込んで視点が遮られることがありえます。 そこで、Rayを飛ばして障害物との衝突を検知し、必要に応じてカメラの位置を調整する方法がよく用いられます。

たとえば、以下のようにRaycastを使い、衝突点との距離に応じてオフセットを短くしてしまう仕組みがあります。 このような処理をカメラの位置を更新する直前に書くと、プレイヤーが壁の近くへ行ったときも視界が確保されやすくなります。

RaycastHit hit;
Vector3 direction = desiredPosition - target.position;
if (Physics.Raycast(target.position, direction, out hit, direction.magnitude))
{
    desiredPosition = hit.point;
}

ただし、このロジックを入れすぎるとカメラが急に近づく現象が起こるかもしれません。 そのため、壁にめりこまないようにするだけでなく、プレイヤーと壁との距離も考慮したうえで微調整したほうがよいでしょう。

カメラが壁をすり抜けてしまうトラブルは意外によくあります。障害物検知のロジックを組むときには、見た目の自然さと物理衝突の両方を気にかけると安心です。

カメラのX軸・Y軸回転を分けて制御する

ゲームによっては、カメラの回転をマウスやコントローラで操作しながらターゲットを追従させる仕組みもほしくなるかもしれません。 この場合、X軸回転(左右の回転)とY軸回転(上下の回転)を分けて管理すると混乱を減らせます。

  1. カメラオブジェクトを親子構造で分ける(例:Y軸回転用オブジェクトと、X軸回転用のカメラ)。
  2. 水平回転はY軸回転用オブジェクトに適用し、上下の視点操作は子のカメラ側で調整する。

こうした構成にしておくと、ターゲットを見失わない程度にマニュアル回転を加えつつ、基本的な位置追従を維持できるはずです。 TPSやFPSのゲームでは一般的なアプローチですね。

複数のカメラを切り替える

実務では、シーン内に複数のカメラを用意して状況に応じて切り替える手法もよく使われます。 プレイヤー操作用のカメラとイベントシーン用のカメラを分けておけば、特定のカットシーンを演出しやすいですよね。 このとき、追従用カメラと固定カメラの両方をシーン内に用意して、スクリプトで有効・無効を切り替えて制御する場合があります。

特に、ゲームジャンルによってはトップビューやサイドビュー、TPS視点、FPS視点などを切り替えることがあるでしょう。 その際、カメラごとに異なる追従スクリプトをアタッチしておくと、シームレスな視点変更が狙いやすくなるはずです。

実務レベルのカメラシステム

より大規模なプロジェクトでは、Cinemachineを使う方法も考えられます。 CinemachineはUnity公式のパッケージとして提供されており、高度なカメラ挙動をコードを書かずに実現しやすいのが特徴です。 カメラのブレンドや制御をカスタマイズできる機能が豊富なので、実務でも活用が広がっているようです。

ただし、Cinemachineの仕組みは奥が深いので、最初は今回紹介したようなシンプルなスクリプトを理解しておくと、挙動の本質に触れられるでしょう。 状況に応じてスクリプトの挙動を調整できる力が身につけば、Cinemachineの活用でもつまづきにくくなるかもしれません。

カメラ追従が効果的な具体的シーン例

  • 3Dアクションゲーム:主人公の後方から追従させ、マップの状況を見渡しやすくする
  • レースゲーム:車体を後方から追いかけるカメラワークで、スピード感を演出する
  • アクションRPG:ボス戦などで被写体が激しく移動しても、常にキャラクターを中心に捉えられる
  • 教育用シミュレーター:実演しているキャラクターの動作をプレイヤーが見やすいようにする

このように、カメラ追従は多くの場面で利用されています。 ただし、どのような距離感やどんな回転の制御が最適かは、ゲームのタイプや開発の意図によって異なるでしょう。 そのため、少しずつパラメータを調整しながら、実際のプレイフィールを確認するのが大事です。

まとめ

ここまで、Unityでのカメラ追従に関する基本から応用例までを幅広く見てきました。 シンプルにターゲットの座標を追従させる方法だけでなく、LerpやSmoothDampを用いてなめらかに移動させるテクニックもありましたよね。

また、障害物が入る場合のRaycastや、Cinemachineの活用といった実務での工夫についても触れました。 ゲームやアプリケーションの種類によって、どこまでカメラ挙動を作りこむかは変わってくるかもしれませんが、まずは今回の基本的な方法を押さえておけば、土台は固まるのではないでしょうか。

皆さんのプロジェクトでもカメラ追従を実装するときに、この記事で紹介したスクリプトや工夫を活かしてみてください。 パラメータを色々といじりながら、自分のゲームのスタイルに合ったカメラ挙動を探っていけると楽しそうですね。

最後までお読みいただき、ありがとうございました。

Unityをマスターしよう

この記事で学んだUnityの知識をさらに伸ばしませんか?
Udemyには、現場ですぐ使えるスキルを身につけられる実践的な講座が揃っています。