본문 바로가기
Unity

카메라 추적

by imagineer_jinny 2021. 7. 22.

Main Camera - Projection - Orthographic

 

Perspective: 소실점이 존재, 하얀색 실선이 뷰의 투영선인데 이 투영선이 한 점으로 모임

소실점이 존재해서 멀리 있는건 작게보이고 가까이 있는 건 크게 보임

 

Orthographic: 소실점이 존재하지 않음, 카메라의 모든 선들이 평행하게 들어옴

가까이 있는 물체나 멀리 있는 물체나 크기가 똑같이 보이고 2d 게임에서 사용하는 방법.

원근감이 없음. 3d 게임에서 Orthographic을 사용하면 원근감이 없어보여서 독특한 아트가 나옴.

 

카메라 위치 조정

 

카메라 스크립트 역할: 

자기자신의 위치를 원하는 위치로 갖다 붙여버림. 이렇게 되면 문제점이 카메라가 어떤 물체랑 딱 붙어있으면 그 물체가 안보임. 즉, 카메라를 어떤 오브젝트에 일정 거리를 벌려주면서 갖다 붙이고 싶다.

 

그걸 위해서 하이라키에 Rig이라는 빈 게임오브젝트를 만든다.

Rig은 배의 추 역할이라고 보면 되는데 카메라의 추(Rig)가 실제 오브젝트에 딱 붙어있고 카메라는 추에 질질 끌려다니는 것.

즉, 카메라 그 자체가 오브젝트에게 바로 붙는게 아니라 카메라는 Rig을 따라다니고 Rig이 실제 오브젝트를 졸졸 따라다님 

 

 

메인 카메라를 Rig의 자식으로 해주고 카메라의 트랜스폼 조정

 

Othographic 모드에서 size는 카메라가 담을 수 있는 게임 세상의 크기임. 

일단 여기서는 size를 5라고 설정.

 

사이즈 값을 늘리면 한번에 담을 수 있는 세상 크기는 커지되 하나하나의 크기는 작게보임

사이즈를 늘리면 줌 아웃이 되고 줄이면 줌 인이 됨.

사이즈 줄이면 한 프레임에 담는 세상 크기는 작아지지만 하나하나의 크기는 크게 보임

 

Rig에 CamFollow 스크립트 붙여주기

CamFollow 스크립트 역할은 원하는 오브젝트를 트래킹하는 동시에 줌인/아웃을 자동으로 하게 해줌

 

CamFollow는 세가지 상태로 두려고 함

1. 라운드를 대기하는 상태

2. 포탄 발사하기 대기하는 상태

3. 포탄을 실제로 발사해서 포탄을 추적하는 상태

 

- 타겟을 추적할 때 바로 추적이 되는게 아니라 지연시간을 줬으면 좋겠을 때

어떤 값이 있을 때 그 값으로 바로 가는게 아니라 중간에 부드럽게 꺾어서 시간을 들여서 값을 바꿔주는 함수를 사용.

 SmoothDamp 함수는 시간을 지정해주면 지정한 시간만큼 이동시킴

그렇게 하면 카메라가 목표물에 바로 붙는게 아니라 시간을 두고 스무스하게 붙음

 

SmoothDamp 역할은 현재 값이랑 원하는 값이 있을 때 현재값을 원하는 값으로 바로 박아 넣는게 아니라

지연시간을 둬서 부드럽게 이어주는 것

 

 

기본적으로 마지막 순간에 값이 얼마나 변경되었는지를 요구함

매 순간마다 값이 변경될 때 

a에서 b까지 값이 얼마나 변경되었는지 알아야지 b에서 c까지 스무스가 적용되는 컨셉

CamFollow.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CamFollow : MonoBehaviour
{
    public enum State
    {
        Idle,Ready,Tracking
    }

    //프로퍼티 사용
    private State state
    {
        set
        {
            switch(value)
            {
                case State.Idle:
                    targetZoomSize = roundReadyZoomSize;
                    break;
                case State.Ready:
                    targetZoomSize = readyShotZoomSize;
                    break;
                case State.Tracking:
                    targetZoomSize = trackingZoomSize;
                    break;
            }
        }
    }

    private Transform target; //추적할 대상

    //내 위치에서 내가 원하는 위치까지 도달하는 지연 시간
    public float smoothTime = 0.2f;

    //사용하려는 기능이 마지막 프레임의 어느 속도로 해당 위치에 이동하고 있는지 알고 있어야 
    //마지막 순간에 원하는 위치까지 얼마의 속도로 이동중이였는지 나타냄
    private Vector3 lastMovingVelocity;

    private Vector3 targetPosition;

    //줌인 줌아웃 구현
    //메인 카메라 가져오기
    private Camera cam;
    private float targetZoomSize=5f;

    //각각의 상태에 따라서 원하는 줌 사이즈 구현할 변수
    private const float roundReadyZoomSize = 14.5f;
    private const float readyShotZoomSize = 5f;
    private const float trackingZoomSize = 10f;

    private float lastZoomSpeed;



    void Awake()
    {
        //Rig안에 있는 자식으로 들어가서 카메라를 가져와야함
        //자식들을 다 뒤져서 원하는 컴포넌트를 가져와줌
        cam = GetComponentInChildren<Camera>();

        //여기에서 보기엔 변수지만 사실은 =을 통해서 들어온 값이
        //state 함수의 value 라는 키워드로 들어옴
        state = State.Idle;

    }

    //카메라가 타겟의 위치에 맞춰서 움직이는 친구
    private void Move()
    {
        targetPosition = target.transform.position;
        //처음 들어가는건 현재 값, 두번째 값은 가고싶은 값,세번째엔 마지막순간의 속도(변화량), 마지막 값은 지연시간
        //ref는 입력을 통해 들어간 값이 SmoothDamp라는 함수 내부에서 값이 변경되면 그걸 그대로 받아서 나온다는 얘기
        //SmoothDamp는 속도를 담을 임시 컨테이너 변수를 만들어놓고 (lastMovingVelocity) 
        //마지막 순간에 값을 부드럽게 꺾으면서 얼만큼의 값을 변경했는지를 매번 lastMovingVelocity에 갱신해서 넣음

        //ref 의미는 변수가 함수 내부에 들어갔을 때 변경된 값을 그대로 챙겨서 나온다는 의미
        Vector3 smoothPosition = Vector3.SmoothDamp(transform.position,targetPosition, ref lastMovingVelocity,smoothTime);

        transform.position = smoothPosition;
    }

    private void Zoom()
    {
        float smoothZoomSize = Mathf.SmoothDamp(cam.orthographicSize, targetZoomSize, ref lastZoomSpeed, smoothTime);
        cam.orthographicSize = smoothZoomSize;
    }

    //FixedUpdate vs Update
    //Update: 화면이 한번 갱신될때마다 실행
    //FixedUpdate: 무조건 정해진 간격 지킴
    //FixedUpdate의 시간 간격이 0.01초라고 지정이 되면 
    //무조건 0.01초 간격을 지켜서 실행됨
    //시간간격이 일정해서 정확한 트릭을 요구할때 사용됨
    private void FixedUpdate()
    {
        if(target!=null)
        {
            Move();
            Zoom();
        }
    }

    public void Reset()
    {
        state = State.Idle;
    }

    public void SetTarget(Transform newTarget, State newState)
    {
        target = newTarget;
        state = newState;
    }
}

 

댓글