내일배움캠프/TIL

내일배움캠프 16일차 TIL - 2D 충돌감지

서보훈 2024. 10. 7. 20:06

문제상황

 

2D 프로젝트중, Collider를 통해 벽을 만들고, 이동을 구현할경우 벽에 부딪치면 이러한 상황이 발생합니다.

동영상 서비스가 종료되어 해당 콘텐츠를 재생할 수 없습니다.

 

시도해본것

Character Contoller 컴포넌트를 사용하여 움직임을 구현할경우, 벽을 인식하지 못하는 상황이 발생합니다.

 

동영상 서비스가 종료되어 해당 콘텐츠를 재생할 수 없습니다.

private Move()
{
    characterContoller.Move(_input.move * moveSpeed * Time.deltaTime);
}

해결 방법

레이캐스팅을 응용하여 벽을 감지하고, 벽이 감지되면 해당 방향의 벡터를 0으로 만들어 움직이지 않도록 추가로 구현할 필요가 있습니다.

//이 오브젝트의 콜라이더
private BoxCollider2D _collider;

//감지된 콜라이더가 저장될 배열
private RaycastHit2D[] wallHitsX = new RaycastHit2D[5];
private RaycastHit2D[] wallHitsY = new RaycastHit2D[5];

//감지될 오브젝트의 레이어
[SerializeField]
private ContactFilter2D contactFilter;

//감지범위
private float detectionRange = 0.2f;

//벽 체크
private bool isWallX = false;
private bool isWallY = false;

//플레이어가 움직이는 속도
private float moveSpeed = 10f;

private void Move()
{
    //이동 입력이 없을때는 작동하지 않음
    if (_input.move == Vector2.zero)
    {
        return;
    }

    //실제 움직임을 처리할 변수
    Vector2 realMove = _input.move;

    //벽 확인
    isWallX = _collider.Cast(new Vector2(realMove.x, 0), contactFilter, wallHitsX, detectionRange) > 0;
    isWallY = _collider.Cast(new Vector2(0, realMove.y), contactFilter, wallHitsY, detectionRange) > 0;

    //X축 이동중 벽에 걸릴경우
    if (isWallX)
    {
        realMove.x = 0;
    }

    //Y축 이동중 벽에 걸릴경우
    if (isWallY)
    {
        realMove.y = 0;
    }

    //이동 처리
    transform.Translate(realMove * moveSpeed * Time.deltaTime);
}

 

상하좌우로 움직이면서 위가 막혀있을경우 좌, 우 이동이 막히지 않도록 상하, 좌우 로 나눠서 벽을 감지합니다.

감지된 객체의 수를 반환하는 Collider.Cast() 함수의 매개변수는

(감지할 방향(Vector3), 감지할레이어, 감지 내용이 저장될 배열, 감지 범위(float)) 입니다.

//벽 확인
isWallX = _collider.Cast(new Vector2(realMove.x, 0), contactFilter, wallHitsX, detectionRange) > 0;
isWallY = _collider.Cast(new Vector2(0, realMove.y), contactFilter, wallHitsY, detectionRange) > 0;

즉, 이 내용은 위를 누르고있을경우 좌, 우를 당담하는 부분은 0, 0 을 받아서 감지를 하지 않고,

위 아래를 당담하는 부분은 (0 , 1, 0) 을 받아서 자신 콜라이더의 위를 확인하고, 감지되는 다른 콜라이더가 있으면 배열에 저장합니다.

 

이후 저장된 배열의 크기가 0보다 크면 => 하나라도 감지된 객체가 있으면 해당 방향의 벡터를 0으로 만들어서 움직이지 않도록 합니다.

//X축 이동중 벽에 걸릴경우
if (isWallX)
{
    realMove.x = 0;
}

//Y축 이동중 벽에 걸릴경우
if (isWallY)
{
    realMove.y = 0;
}

 

따라서 조작하는 물체는 이러한 움직임을 보입니다.

 

동영상 서비스가 종료되어 해당 콘텐츠를 재생할 수 없습니다.

 

알게된점

사실 이전에 배운내용이였습니다.

다만, 원래 캐릭터 컨트롤러가 이와 같이 작동하기 때문에 캐릭터 컨트롤러를 사용하려고 했으나, 캐릭터 컨트롤러는 3D 환경에서 주로 사용되는 컴포넌트이기 때문에 2D 환경에서는 제데로 작동하지 않는 모습을 볼 수 있었습니다.

 

따라서 이 내용을 떠올리고, 사용하게 되었습니다.