본문 바로가기
스파르타 내배캠

스파르타 내배캠 Unity 3기 26일차

by LemongO 2024. 1. 29.

허리가 활처럼...!

 

 

 

팀 과제도 이제 사실상 하루만 남겨놨다...

이번엔 나의 과한 욕심이 낳은 업보 같은 느낌을 많이 받는데

"괜히 픽셀을 직접 찍었나?" 라는 생각이 많이 든다.
생각보다 픽셀 찍기는 많은 시간을 잡아먹기 때문에

캠프의 취지와는 완전히 상반되는 작업에 시간을 투자한 셈이 되어서 영~ 기분이 찜찜하다.

 


재귀 호출과 StackOverflow

 

이번 팀과제를 하면서 몬스터 부분을 담당했다.

 

그리고 몬스터의 일종인 장애물(Obstacle) 이라는 특수한 시스템을 추가했는데 여기서 문제가 생겼다.

 

  • 맨 아래부터 쌓여야하는데 공중에 떠있는 장애물
  • 동시에 파괴될 때, StackOverflow 발생

 

아래층이 비면 안 돼!

 

얜 또 뭐야?!

 

일단 기본적인 Obstacle 로직이 자신이 파괴가 될 때, 자신의 윗 칸 블럭을 검사하는 방식이다.

Rigidbody2D가 없으며 Collider2D 만 있고, Transform 이동을 외부에서 호출해서 해준다.

 

    private void CheckMyUpPosition()
    {
        Vector2 startRay = transform.position + Vector3.up;
        RaycastHit2D hit = Physics2D.Raycast(startRay, Vector2.up, 0.5f);
        Debug.DrawRay(startRay, Vector2.up * 0.5f, Color.red);

        if (hit && hit.collider.CompareTag("Ground"))
            hit.transform.GetComponent<Obstacle>().CheckMyUpPosition();

        if (!_isBroken)
            MoveDown();
    }    

    private void MoveDown() => transform.position += Vector3.down;

 

Obstacle 클래스의 일부이다.

CheckMyUpPosition 함수는 자신이 파괴가 됐을 때, 호출되는 함수이다.

 

  1. 자신의 한 칸 위 기준으로 up방향 0.5f 거리만큼 레이를 쏜다.
  2. 진행방향에 오브젝트가 있고, 그 오브젝트가 Ground 태그를 가지고 있으면 Obstacle로 간주,
    (현재 기획상 예외는 없다.) 재귀 호출로 해당 오브젝트에서 다시 한 칸 위를 검사.
  3. 없을 때 까지 반복 후, 맨 끝에 녀석부터 한 칸 아래로 내려옴.

 

와! 복잡해!

 

처음엔 ray의 길이로 인해 이중 검사를 의심했지만 사실 그건 아닐것이다.

그 이유는 진행 방향에 처음으로 걸리는 녀석이 바로 반환되며, 만약 이중 검사를 하더라도 이상한 결과가 나올 뿐

스택오버플로우가 일어날 일은 없다.

 

그렇다면 무엇이 문제일까?

 

프레임 단위로 실행을 시켜보았지만 전혀 문제를 찾지 못했다.

 

그러고 타이밍을 맞춰서 정지를 눌렀더니 다음과같은 현상을 발견했다.

 

...?!

 

사진만 봐선 잘 모르겠다. 사실 내가 생각하는게 맞는지도 잘 모르겠다. 하지만 이거 아니면 내 얕은 지식으론

이해가 안 되는 부분이다.

 

 

 

앞서 체크 하는 함수가 재귀호출이라고 말했다.

그리고 재귀호출이 정상 작동하기 위해선, 한 번의 파괴가 일어날 때 정상 작동을 한다.

하지만 지금과 같이 동시다발적이라면???

 

누가 먼저 실행돼도 아무도 모르는 상황이 돼버리면서 다음과 같은 일이 일어난듯 하다.

 

  1. 먼저 파괴, 검사, 이동을 끝마친 A 박스가 위 칸 B 박스를 자신의 위치로 이동시킴.
  2. B박스가 A박스에 의해 이동이 일어남과 동시에 이동된 위치에서 Ray를 쏨.
  3. 그러나 B박스의 Collider는 이전 위치에 남아있음.
  4. 재귀 호출로 자기 자신의 Transform 으로부터 재검사가 이루어짐.
  5. Collider는 여전히 이전 위치에 있으므로 현재 B의 Transform 으로부터 다시 재검사가 이루어짐.
  6. 무한반복.

 

음! 역시 복잡하군

 

 

한 마디로 실행 순서가 꼬이고 Collider가 Transform과 같이 이동되지 않아서 생긴 문제이지 않을까 싶다.

 

이렇게 추측하는 이유는 혼자 작업할 때,

이상하게 Object의 위치와 Collider의 위치가 항상 같지 않고

Collider가 뒤늦게 따라오는 현상을 자주 봤기 때문이다.

 

물론! 내 생각이 틀린걸지도 모른다.

 

그래서 이걸 어찌한담...

 

하는 수 없이 원래 안 하려고 했던 RigidBody2D를 넣어 X,Z 축 Freeze를 한 뒤,

재귀 호출 함수를 빼고 장애물 파괴 후 별다른 조치를 안 하는걸로 바꿧다.

 

즉, 위에 쓴 코드를 그냥 통으로 삭제했다.

 

결과

 

왜 이게 더 좋아보일까...