자세히보기

공부 나눔 (Sharing Study)/Unity 와 C#

[Unity/C#] 카메라가 벽을 통과하지 못하게 만들기

윤스톤 2023. 1. 18. 18:53

이번 시간에는 플레이어를 따라다니는 카메라가
벽을 통과하지 못 하도록 만드는 방법을 배워보도록 하겠습니다 :)

 

1. 캐릭터와 공간 준비

바닥(Plane)과 플레이어(Capsule), 벽(Cube)을 만들어 배치하고,
플레이어는 움직일 수 있게 스크립팅을 해둔 상태입니다.

 

 

2. 카메라 배치

메인 카메라를 캐릭터를 따라다니는 3인칭 카메라를 만들기 위해
메인 카메라의 위치와 각도를 수정합니다.


카메라가 플레이어가 이동함에 맞춰 따라다니는 기능이 필요합니다.
이 기능을 메인 카메라에 바로 적용하면 카메라가 플레이어를 기준으로 회전할 수 없으므로
부모 오브젝트를 만들어 기능을 분리하도록 하겠습니다.
(카메라의 부모 : 플레이어 따라다니기 / 카메라 : 회전 및 벽 통과 불가)

 

3. 카메라의 부모는 플레이어 따라다니기

아래와 같이 스크립트를 만들어 코드를 작성하고,
카메라의 부모 오브젝트에 컴포넌트로 넣은 후, 플레이어 오브젝트를 할당합니다.

public class CameraPMove : MonoBehaviour
{
    public Transform player; // 플레이어

    Vector3 offset; // 플레이어와 카메라 사이의 거리와 방향

    void Start()
    {
        // 시작할 때 둘 사이의 거리와 방향 저장
        offset = transform.position - player.position;
    }

    void Update()
    {
        // 둘 사이의 거리와 방향을 유지하며 따라다니기
        transform.position = player.position + offset;
    }
}

CameraPMove.cs
0.00MB

(위 코드를 복사하시려면 이 스크립트를 다운받아주세요 - 우클릭 방지)

 

4. 카메라는 플레이어를 기준으로 회전하기

아래와 같이 스크립트를 만들어 코드를 작성하고,
카메라의 부모 오브젝트에 컴포넌트로 넣은 후, 플레이어 오브젝트를 할당합니다.

public class CameraMove : MonoBehaviour
{
    public Transform player;  // 플레이어

    public float rotateSpeed; // 회전 속도

    void Update()
    {
        // 좌클릭 드래그로 상하좌우 회전 (플레이어를 기준으로)
        if (Input.GetMouseButton(0))
        {
            float mouseX = Input.GetAxis("Mouse X");
            float mouseY = Input.GetAxis("Mouse Y");

            transform.RotateAround(player.position, transform.up, mouseX * rotateSpeed);
            transform.RotateAround(player.position, transform.right, -mouseY * rotateSpeed);
            transform.eulerAngles = new Vector3(transform.eulerAngles.x, transform.eulerAngles.y, 0);
        }
    }
}

(CameraMove 스크립트 파일은 아래에 있습니다 - 우클릭 방지)

플레이해보면 좌클릭 드래그 시,
카메라가 플레이어 주위를 회전하는 것을 볼 수 있습니다.

 

5. 카메라가 벽을 통과하지 못하게 제어하기

카메라에게 부여한 스크립트를 아래와 같이 수정합니다.

public class CameraMove : MonoBehaviour
{
    public Transform player;  // 플레이어

    public float rotateSpeed; // 회전 속도

    // 카메라가 통과하지 못할 오브젝트의 레이어
    public LayerMask cameraCollision;

    void Update()
    {
        // 좌클릭 드래그로 상하좌우 회전 (플레이어를 기준으로)
        if (Input.GetMouseButton(0))
        {
            float mouseX = Input.GetAxis("Mouse X");
            float mouseY = Input.GetAxis("Mouse Y");

            transform.RotateAround(player.position, transform.up, mouseX * rotateSpeed);
            transform.RotateAround(player.position, transform.right, -mouseY * rotateSpeed);
            transform.eulerAngles = new Vector3(transform.eulerAngles.x, transform.eulerAngles.y, 0);
        }


        // 플레이어에서부터 카메라까지의 방향 구하기
        Vector3 rayDir = transform.position - player.position;

        // 플레이어에서 카메라 방향으로 Ray 발사
        if (Physics.Raycast(player.position, rayDir, out RaycastHit hit, float.MaxValue, cameraCollision))
        {
            // 맞은 부위보다 더 안쪽으로 위치 이동
            transform.position = hit.point - rayDir.normalized;
        }
    }
}

CameraMove.cs
0.00MB

(위 코드를 복사하시려면 이 스크립트를 다운받아주세요 - 우클릭 방지)

더보기

[ 코드 설명 💬 ]

카메라가 벽을 통과하지 못하려면 벽이 있는지 파악해야 합니다.
카메라가 벽을 통과했다는 것은 플레이어와 카메라 사이에 벽이 존재한다는 것입니다.
즉, 플레이어와 카메라 사이의 오브젝트를 감지하기 위해 Ray를 발사해야 하는 상황입니다.

 

 

발사할 방향은 플레이어에서부터 카메라까지의 방향입니다.
카메라의 위치에서 플레이어의 위치를 빼 방향을 구합니다.

 

플레이어의 위치에서 시작하여 카메라를 향해 발사하며, 맞은 오브젝트는 hit 변수에 저장합니다.
이때, 발사하는 Ray의 길이는 최댓값으로 설정하고,
모든 오브젝트를 감지하지 않고 원하는 오브젝트만 감지하도록 LayerMask를 설정합니다.

 

hit.point는 Ray와 충돌한 위치입니다.
카메라가 이 위치로 이동하게 되면 벽 뒤로 넘어가지 못합니다.
하지만 충돌한 위치보다 플레이어와 조금 더 가까운 위치로 이동하는 것이 보기 좋기 때문에
아까 구해둔 플레이어부터 카메라까지의 방향을 정규화하여 덜 이동하도록 합니다. 

 

6. 통과되지 못할 오브젝트(벽)에 레이어 설정하기

특정 레이어를 가진 오브젝트만 Ray에 감지되도록 구현했으니
새로운 레이어를 만들고, 벽 오브젝트에게 부여합니다.

 

새로 만든 레이어들만 감지할 수 있도록 메인 카메라 오브젝트에 넣어 둔
CameraMove 컴포넌트에 레이어를 설정합니다.

 

 

7. 플레이해서 확인하기

벽 통과하지 못하게 만드는 기능이 없을 때는
아래와 같이 벽 뒤로 넘어가는 상황이 발생했습니다.


하지만 기능을 완성한 후에는 아래와 같이 벽을 통과하지 못하게 됩니다.

 


카메라가 벽을 통과하지 못하도록 만드는 방법이었습니다 :)
끝까지 읽어주셔서 감사합니다! 도움이 되셨다면 댓글+하트 해주세요 🥰

반응형