튜토리얼에서 배우는 카메라 구현 방법의 차이

공식 튜토리얼 를 통해 배운 내용을 앱풋하면서 비망록으로 남겨 갑니다.

이번은 각 튜토리얼의 카메라의 실장 방법에 대해 정리해 갑니다.

Roll a Ball (옥회전 게임)



플레이어로부터 일정 거리를 유지해 내려다 보는 형태로 추적하는 심플한 카메라 동작이 되어 있어,
회전이나 ​​줌 처리 등도 없기 때문에 스크립트도 간소한 것이 되고 있습니다.

CameraController.cs
public class CameraController : MonoBehaviour
{
    public GameObject player;   // 操作対象のボール

    private Vector3 offset;     // カメラからボールまでの距離、
                                // カメラは常にボールからoffset分の距離を保つことになる

    void Start ()
    {
        // ボールの初期位置からoffsetを初期化する
        offset = transform.position - player.transform.position;
    }

    void LateUpdate ()
    {
        // (移動後の)ボールの位置を元にカメラの位置を移動する
        transform.position = player.transform.position + offset;        
    }
}

Tanks! (대전형 탱크 게임)



한 화면에서 2대의 전차를 거쳐야 하기 때문에,
2대의 중간 지점을 중심으로 카메라가 이동해, 화면내에 표시가 낫지 않는 경우는 줌 아웃 하는 동작이 되고 있습니다.

카메라의 줌 처리에 대해서는 코드량도 적고 복잡한 계산은 하고 있지 않습니다만,
로컬 공간에 대한 이해가 필요하기 때문에 전제 지식이 없는 경우, 좀처럼 이해할 수 없을 가능성이 높습니다.
Tutorial의 동영상으로 도해로 설명되고 있기 때문에 자세한 것은 생략합니다만,
반복 확인하여 불명점을 씻어내는 것이 좋습니다.

좌표계로 막혔을 때는 스스로도 도해해 정리하는 것이 효과적입니다.


CameraControl.cs
using UnityEngine;

public class CameraControl : MonoBehaviour
{
    public float m_DampTime = 0.2f;                 // カメラが目標に到達するまでの時間
    public float m_ScreenEdgeBuffer = 4f;           // 戦車が画面端に貼り付かないようにするために設定する余地
    public float m_MinSize = 6.5f;                  // カメラが画面に寄り過ぎないようにするために設定する最小値
    [HideInInspector] public Transform[] m_Targets; // カメラにおさめる対象(戦車)を配列で格納する


    private Camera m_Camera;                        // カメラ
    private float m_ZoomSpeed;                      // カメラのズーム速度
    private Vector3 m_MoveVelocity;                 // カメラの移動速度
    private Vector3 m_DesiredPosition;              // カメラが向かっている位置


    private void Awake ()
    {
        m_Camera = GetComponentInChildren<Camera> ();
    }


    private void FixedUpdate ()
    {
        Move ();
        Zoom ();
    }


    private void Move ()
    {
        // 2点間の中央地点を求める
        FindAveragePosition ();

        // 目的座標にカメラリグを移動させる
        transform.position = Vector3.SmoothDamp(transform.position, m_DesiredPosition, ref m_MoveVelocity, m_DampTime);
    }


    private void FindAveragePosition ()
    {
        Vector3 averagePos = new Vector3 ();
        int numTargets = 0;

        // 残存している全ての戦車の情報を確認し、位置情報を加えていく
        for (int i = 0; i < m_Targets.Length; i++)
        {
            // プレイヤーが死亡している時は戦車が画面内に存在しないためスキップする
            if (!m_Targets[i].gameObject.activeSelf)
                continue;

            // ベクトル変数に戦車の位置情報を加える
            averagePos += m_Targets[i].position;
            numTargets++;
        }

        // 戦車が複数台残っている場合は、中央地点を求める
        if (numTargets > 0)
            averagePos /= numTargets;

        // 戦車やカメラはY座標を移動しないため安全装置として初期値0を維持させる
        averagePos.y = transform.position.y;

        // メンバ変数に目標地点を格納する
        m_DesiredPosition = averagePos;
    }


    private void Zoom ()
    {
        // 複数台の戦車が画面内におさまるためのカメラサイズを求め変更する
        float requiredSize = FindRequiredSize();
        m_Camera.orthographicSize = Mathf.SmoothDamp (m_Camera.orthographicSize, requiredSize, ref m_ZoomSpeed, m_DampTime);
    }


    private float FindRequiredSize ()
    {
        // カメラリグのローカル空間において、カメラの目標地点の座標を取得する
        Vector3 desiredLocalPos = transform.InverseTransformPoint(m_DesiredPosition);

        // カメラサイズの初期値
        float size = 0f;

        // 残存している全ての戦車の情報を確認し、位置情報を加えていく
        // 最も離れた場所にある戦車を含んでズームアウトすれば画面内におさまる
        for (int i = 0; i < m_Targets.Length; i++)
        {
            if (!m_Targets[i].gameObject.activeSelf)
                continue;

            // カメラリグのローカル空間における戦車の座標を取得する
            Vector3 targetLocalPos = transform.InverseTransformPoint(m_Targets[i].position);

            // カメラリグのローカル空間において、カメラ移動後の目標地点を原点として戦車の距離を求める
            Vector3 desiredPosToTarget = targetLocalPos - desiredLocalPos;

            // 現在のカメラサイズとカメラリグのローカル空間における戦車のY軸の距離を比較し大きい方を格納する
            size = Mathf.Max(size, Mathf.Abs(desiredPosToTarget.y));

            // 現在のカメラサイズとカメラリグのローカル空間における戦車のX軸の距離を比較し大きい方を格納する
            size = Mathf.Max(size, Mathf.Abs(desiredPosToTarget.x) / m_Camera.aspect);
        }

        // カメラの画面端に戦車が画面端に貼り付かないようにするため余地(遊び)を加える
        size += m_ScreenEdgeBuffer;

        // カメラが画面に寄り過ぎないようにするため、カメラサイズの最小値と比較し下回っていたら上書きする
        size = Mathf.Max (size, m_MinSize);

        return size;
    }

    // GameManagerクラスからゲーム開始時に呼び出される
    public void SetStartPositionAndSize ()
    {
        FindAveragePosition ();
        transform.position = m_DesiredPosition;
        m_Camera.orthographicSize = FindRequiredSize ();
    }
}

Survival Shooter (내려다보는 건 액션 게임)



Roll a Ball과 같이 플레이어로부터 일정 거리를 유지해 내려다 보는 형태로 추적하는 심플한 카메라입니다.
카메라 이동에 관해서는 LateUpdate() 대신 FixedUpdate()로 수행하고 있습니다.
Vector3.Lerp 함수를 사용하여 두 점 사이를 보완하고 서서히 카메라가 이동하도록 구현되었습니다.
(체감적으로 카메라가 조금 늦어 플레이어에게 추적한다)

CameraFollow.cs
public class CameraFollow : MonoBehaviour
{
    public Transform target;        // カメラの追尾対象(プレイヤー)の位置
    public float smoothing = 5f;    // カメラの追尾速度

    Vector3 offset;                 // カメラからtargetまでの距離、
                                    // カメラは常にプレイヤーからoffset分の距離を保つことになる

    void Start ()
    {
        // プレイヤーの初期位置からoffsetを初期化する
        offset = transform.position - target.position;
    }


    void FixedUpdate ()
    {
        // プレイヤーの位置から追尾後のカメラ位置を算出する
        Vector3 targetCamPos = target.position + offset;

        // プレイヤーの位置を元にカメラを移動させる
        transform.position = Vector3.Lerp (transform.position, targetCamPos, smoothing * Time.deltaTime);
    }
}


앞으로도 추가 예정입니다

좋은 웹페이지 즐겨찾기