내일배움캠프/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 환경에서는 제데로 작동하지 않는 모습을 볼 수 있었습니다.

 

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