Unity: Ray로 obstacle(장애물)을 피해보자

이재형·2024년 7월 9일
0
post-thumbnail
post-custom-banner

Unity 공부

Ray로 obstacle(장애물)을 피해보자

문제 발생: 플레이어를 rigidbody로 추격할 때 장애물을 통과 못하는 문제가 발생함

문제 진행: 플레이어 방향으로 가게만 되어있지 장애물에 대해서 처리를 하지 못한 문제였음

문제 해결: 플레이어를 추격할 때 Ray를 발사하여 장애물을 확인하고 방향을 변경하게 하여 문제를 해결하였음

1. 이동할 방향에 대한 변수 생성 및 초기화

// 플레이어 추격 관련
private bool chase = false;
private float trackingTime = 0.0f;
private Vector3 direction; // 추격 방향
private Vector3 leftDirection; // 왼쪽 추격 방향
private Vector3 rightDirection; // 오른쪽 추격 방향
private Vector3 leftRot = new Vector3(0, 0, 45f);
private Vector3 rightRot = new Vector3(0, 0, -45f);
private Vector3 leftTurnRot = new Vector3(0, 0, 65f);
private Vector3 rightTurnRot = new Vector3(0, 0, -65f);

private Vector2 size = new Vector2(2f, 2);

private IEnumerator RayPlayer()
{
    while (true)
    {
        if (chase)
        {
            direction = target.position - transform.position;
        }
        else
        {
            direction = startPos - transform.position;
        }

추격하는지 여부에 따라서 추격 처음 위치로 돌아가던가 플레이어를 쫓아가게 초기화를 해준다.


2. 쫓아가는 방향에 장애물 여부를 판단하기 위한 각도 처리

leftDirection = Quaternion.Euler(leftRot) * direction;
rightDirection = Quaternion.Euler(rightRot) * direction;

RaycastHit2D hitDirection = Physics2D.Raycast(transform.position, direction, circleCollider2D.radius, LayerMask.GetMask("Wall"));
Debug.DrawRay(transform.position, direction.normalized * circleCollider2D.radius, Color.red, 0.1f);
Debug.DrawRay(transform.position, leftDirection.normalized * circleCollider2D.radius, Color.blue, 0.1f);
Debug.DrawRay(transform.position, rightDirection.normalized * circleCollider2D.radius, Color.blue, 0.1f);

발사한 Ray 사진

Ray를 발사하여 벽의 Layer인 Wall을 추가하고 DrawRay로 Ray를 사거리만큼 나타내서 확인


3. OverlapBox를 이용하여 벽 근접시에도 확인 후 방향 변경

Ray를 발사해서 끝인데 왜 OverlapBox를 사용하는가?

Enemy가 Wall오브젝트의 끝에 다가가고 플레이어를 다시 추격할 때 벽과 Enemy가 겹쳐서 낑기는 문제가 발생하여 처리를 하였음

Collider2D hit = Physics2D.OverlapBox(transform.position, size, 0, LayerMask.GetMask("Wall"));
if (hitDirection.collider != null || hit?.gameObject != null)
{
    RaycastHit2D hitLeftDir = Physics2D.Raycast(transform.position, leftDirection, circleCollider2D.radius, LayerMask.GetMask("Wall"));
    RaycastHit2D hitRightDir = Physics2D.Raycast(transform.position, rightDirection, circleCollider2D.radius, LayerMask.GetMask("Wall"));
    if (hitLeftDir.collider == null)
    {
        Movement(Quaternion.Euler(leftTurnRot) * direction);
    }
    else if (hitRightDir.collider == null)
    {
        Movement(Quaternion.Euler(rightTurnRot) * direction);
    }
}

DrawWireCube로 OverlapBox 사진

Ray를 발사하고 벽이거나 overlapBox에 충돌한 오브젝트가 있을 때 좌우 Ray를 또 발사하여 벽이 있는지 확인을 하고 벽이 존재하지 않으면 선택한 방향으로 이동을 하는 코드이다.

4. 추격을 하지 않을 때는 다시 돌아가고 잦은 Ray발사를 줄이기 위해 딜레이

else
{
    Movement(direction);
}

yield return new WaitForSeconds(0.02f);

void메서드가 아닌 코루틴으로 시작하여서 Ray가 계속 생성되는 문제를 해결하고자 하였다. new WaitForSeconds는 GC(가비지 컬렉터)가 일어나므로 후에 캐싱을 해야겠다.


정리

배운 내용

1. 잦은 Ray가 발생하는 문제가 있을 수 있으므로 코루틴을 이용하여 딜레이를 부여하여 진행했는데 더 효율적인 방법이 있을지에 대해 생각을 해야겠음

해결 못한 문제

1. 생각을 해보니 yield return new WaitForSeconds(0.02f);는 GC를 일으키기 때문에 캐싱을 이용해서 처리해야겠다.

문제점

1. 없음

profile
한국사람
post-custom-banner

0개의 댓글