카테고리 없음

유니티 카메라 이동과 활용

akama 2024. 9. 18. 13:52

게임을 만들다 보면 스크립트를 적용하고 플레이를 하면 예상 밖의 결과를 보는 경우가 종종 있습니다. 캐릭터 이동을 적용해서 확인하면 움직이는 캐릭터를 당연히 카메라를 통해 계속 볼 것이라는 착각을 말하는 것입니다. 카메라 이동에 대해 명령어가 없다면 캐릭터가 카메라 프레임 밖을 벗어나서 사라지는 것은 당연한 결과입니다. 그럼 카메라도 이동시켜 보겠습니다. 아주 간단한 스크립트로 카메라가 플레이어 캐릭터를 중심에 두고 따라다니게 됩니다.

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

public class CameraFollow : MonoBehaviour
{
      public float cameraMoveSpeed = 5f;
      GameObject player;

    private void Start()
    {
        player = GameObject.FindGameObjectWithTag("Player");
    }

    void LateUpdate()
    {
        Vector3 dir = player.transform.position - transform.position;
        Vector3 moveVector = new Vector3(dir.x * cameraMoveSpeed * Time.deltaTime, dir.y * cameraMoveSpeed * Time.deltaTime, 0f);
        transform.Translate(moveVector);
    }
}

속도를 설정해주고, 게임오브젝트 변수(player)를 한 개 만들어 줍니다. 참고로 변수의 이름은 아무거나 써도 상관없습니다. 여기서는 그냥 player 쓴 것 뿐입니다. 변수는 일종의 빈 그릇이라고 비유하면 좋습니다. 빈 그릇을 만들었다면 그릇을 채워서 써먹어야겠죠? Start(시작함수)에서 player는 Player태그가 있는 게임오브젝트이니 이 태그가 있는 게임오브젝트를 찾고, 그 오브젝트가 바로  player라고 지정해 줍니다. 카메라의 이동 역시 방향 설정이 먼저입니다. Vector 변수를 생성하고 player.transform.position - transform.position 위치 차이를 방향으로 설정하고, 카메라 이동속도를 곱해서 Translate으로 이동시켜 줍니다. 이 스크립트는 카메라를 이동시켜줘야 하는 스크립트이기 때문에 main Camera에 이 스크립트를 추가시킵니다. 플레이를 해보면 캐릭터가 움직이는 대로 카메라가 따라다니게 됩니다.

만약 횡스크롤 게임인데 캐릭터가 움직이는 플랫폼 게임이라면 카메라뷰도 달라져야 할 수도 있습니다. 주로 달리는 플랫폼 게임 특성 상 진행 방향이 일정하기 때문에 앞에 있는 상황을 보면서 플레이어가 판단할 수 있도록 화면에 좀 더 많은 정보를 제공하는 것이 좋습니다. 낭떠러지나 아이템 등을 미리 보여주고 플레이어는 이를 보고 판단해서 플레이하도록 해야 하는데 이 때 캐릭터의 위치를 카메라의 중앙이 아닌 부분에 배치하여 플레이어가 좀 더 필요한 부분을 많이 보도록 할애해 주는 것이 좋습니다. 이런 방식의 카메라 이동은 위 스크립트에서 아주 살짝 변경하는 것으로 가능합니다.

void LateUpdate()
    {
        Vector3 dir = player.transform.position - transform.position;
        Vector3 moveVector = new Vector3((dir.x+5f) * cameraMoveSpeed * Time.deltaTime, dir.y * cameraMoveSpeed * Time.deltaTime, 0f);
        transform.Translate(moveVector);
    }

붉은색 표시된 부분이 변경된 부분인데 카메라의 중심 방향을 현재 player.transform.position 위치로부터 5f 플러스한 것이므로 카메라의 중심이 플레이어로부터 우측으로 갔고 상대적으로 캐릭터는 좌측으로 밀려 보이도록 합니다. 여기서 주의할 점은 '괄호'를 꼭 해주어야 합니다. 모든 프로그램은 수학의 기본 공식을 따릅니다. 더하기 빼기이기 때문에 괄호를 안 하면 cameraMoveSpeed와 먼저 곱연산이 되기 때문에 원하는 결과를 얻을 수 없으니 괄호처리를 통해 먼저 카메라의 위치를 변경해야 원하는 결과를 얻을 수 있습니다.

 

게임을 플레이하다 보면 벽을 만나거나 부딪힐 때가 있습니다. 이런 영역들은 게임 플레이의 경계부분으로 캐릭터가 갈 수 없는 곳이기 때문에 카메라 역시 경계지역에 들어서면 카메라의 이동을 제한시킬 필요가 생깁니다.

이럴 경우에는 이 스크립트를 이용해봅니다.

using UnityEngine;

public class CameraFollow : MonoBehaviour
{
    public Transform player;
    public Vector2 minBounds;
    public Vector2 maxBounds;
    public float smoothSpeed = 0.15f;
    public Vector3 offset;

    void LateUpdate()
    {
            Vector3 controlledPosition = player.position + offset;
            Vector3 clampedPosition = new Vector3(
            Mathf.Clamp(controlledPosition.x, minBounds.x, maxBounds.x),
            Mathf.Clamp(controlledPosition.y, minBounds.y, maxBounds.y),
            controlledPosition.z);

            Vector3 smoothedPosition = Vector3.Lerp(transform.position, clampedPosition, smoothSpeed);
            transform.position = smoothedPosition;
    }
}

offset은 public Vector3 변수입니다. inspector를 통해 변경 가능하며, 카메라가 플레이어로부터 어느 위치에 배치되는지를 설정해 줍니다. 0이라면 카메라는 카메라와 플레이어의 위치가 같아지므로 캐릭터를 중앙 보고 따라다니게 됩니다. 이동의 제한은 Mathf.Clamp를 통해 제한하게 됩니다. Mathf.Clamp(대상, 대상의 최소값, 대상의 최대값) 형식을 통해서 대상이 최소값과 최대값을 넘어서지 못 하도록 합니다. 즉 Vector3를 선언한 후에 카메라의 x축과 y축의 이동을 제한하기 위해서 controlledPosition.x와 controlledPosition.y를 대상으로 하여 각각 최소값(min)와 최대값(max)을 지정해서 카메라의 영역제한을 지정합니다. 카메라가 영역 밖을 나가면 카메라의 위치 좌표와 clampedPosition 위치 좌표간 사이 선형을 통해 움직입니다. 이 명령을 통해서 카메라는 clampedPosition 좌표 영역 내에서 부드럽게 움직이면서 캐릭터를 따라다니게 됩니다.

이 게임은 snake game과 유사한 방식이라고 앞서 언급한 적이 있습니다. 즉 게임오버 판정은 꼬리에 부딪히거나 벽에 부딪히는 것인데 여기서는 snake가 아닌 robot이기 때문에 벽 충돌만 생각하겠습니다. 플레이어 캐릭터 robot이 벽에 부딪칠 때 어떤 효과를 주고 싶다는 생각을 합니다. 첫번째가 충돌 이미지 발생 또는 파티클(particle)이고, 두번째가 카메라 흔들기 입니다. 카메라 부분을 다루고 있기 때문에 카메라 흔들기를 한 번 알아보겠습니다. 원래 이 파트는 게임을 개발하면서 추가하게 되는 것인데 기획 단계에서 이런 아이디어를 생각해 놓았다면 카메라 스크립트를 만들 때 만들어 놓고 추후에 적용 및 테스트를 해보아도 됩니다.

카메라를 흔들어 주는 스크립트

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

public class ShakeCamera : MonoBehaviour
{
    public float shakeAmount = 1.0f;
    public float shakeTime = 1f;
    public Vector3 player;

    public void Shaking(Vector3 v)
    {
        player = new Vector3(v.x, v.y, v.z - 5);
        StartCoroutine(Shake(shakeAmount, shakeTime));
    }

    IEnumerator Shake (float shakeAmounts, float shakeTimes)
    {
        float timer = 0f;
        while (timer <= shakeTimes)
        {
            Camera.main.transform.position = (Vector3)UnityEngine.Random.insideUnitCircle * shakeAmount + player;
            timer += Time.deltaTime;
            yield return null;
        }
        Camera.main.transform.position = player;
    }
}

이 스크립트를 캐릭터 게임 오브젝트에 붙입니다. 아마 붙여 놓아도 카메라 흔들기 이벤트는 발생하지 않을 것입니다. Shaking 함수가 있어도 이벤트가 없기 때문입니다. 벽에 부딪치는 이벤트 발생 시 Shaking 함수를 호출하여 카메라를 흔들도록 해야 합니다. 아직 벽 오브젝트가 없기 때문에 이를 테스트 하는 간단한 방법은 버튼을 한 개 만들고 Shaking함수를 on click 즉 버튼 클릭 시 호출하는 것입니다. 그러면 버튼을 누를 때마다 카메라가 흔들리는 것을 보실 수 있습니다. 너무 크게 흔들린다면 shakeAmount와 shakeTime을 조정해 주면서 알맞게 설정하면 됩니다.

위 스크립트는 유니티 엔진에 탑재된 기능을 사용한 것이며 shakeTime 동안 반복적이면서도 랜덤위치 지정을 명령해서 마치 카메라가 흔들리는 것처럼 보이도록 한 것입니다.

이 기능은 추후 타일맵에서 벽 오브젝트를 만든 후에 연계 및 활용될 것입니다.

다음에는 캐릭터에 움직일 때 간단한 표정을 표현하는 애니메이션을 적용해 보겠습니다.