Navmesh의 생성은 던전의 생성이 끝난 후 이루어져야함.
DungeonManager에서 DungeonGenerate(), NavmeshGenerate()를 순차적으로 실행
-> 비정상적인 Navmesh 생성 (맵 전체가 Walkable) 아마도 타일맵이 모두 생성되기 전에 (Background만 생성된 상태) Navmesh가 생성된 듯 함.
코루틴으로 1초 뒤에 생성시킴
-> 내 컴퓨터에선 정상적으로 작동. 하지만 엄청 느린 기기에선 오류가 발생할 수 있기 때문에 좋은 방법은 아닌듯
코루틴으로 매 프레임 Navmesh 생성
-> 프레임이 미친듯이 떨어짐. 절대 써선 안되는 방법
DungeonGenerator에 IsDone이라는 bool 변수 추가 후, NavmeshGenerator의 코루틴에서 WaitWhile로 IsDone 검사
-> 이게 왜 됨? 설마 되나 하고 해봤는데 진짜 돼서 놀랐다.
private IEnumerator Generate()
{
// 던전 생성이 끝날 때까지 기다림
yield return new WaitWhile(() => !Main.Dungeon.DungeonGenerator.IsDone);
if (Surface2D.useGeometry == NavMeshCollectGeometry.PhysicsColliders)
yield return new WaitForFixedUpdate();
var op = Surface2D.BuildNavMeshAsync();
op.completed += op =>
{
_callback?.Invoke(op);
};
yield return null;
}
기존의 했던 방식은 왜 안되고, 3번의 방법은 왜 되는지 궁금해서 튜터님께 질문해봤다.
던전은 생성하는 코드는 비동기 방식이 아님에도, 순차적인 실행이 보장되지 않아서 오류가 발생했다.
코드는 위에서부터 순차적으로 실행되지만,
유니티에서 방대한 양의 오브젝트를 Instantiate, Load하는 등의 코드는 순차적인 실행을 보장할 수 없다.
엔진에 대한 이해도가 필요한 문제였던 것 같다.
내 생각엔 생성, 삭제, 로드와 같이 거대한 오버헤드가 발생할 수 있을 만한 메서드는 호출하면 엔진 단위에서 추가 작업을 하며 몇 프레임 뒤로 밀릴 수도 있는 것 같다.
즉, 내가 짠 스크립트에서는 엔진에게 예약같은 것만 걸어주는 것이고, 실제 그 처리는 엔진이 처리하는 느낌인 것 같다.
마침 어제 트러블슈팅에서 알게 된 Destroy() 메서드의 동작방식이 실제론 삭제를 하기 위한 예약만 걸어두는 것이고 실제 삭제는 다음 프레임의 렌더링 직전에 엔진이 따로 처리한다는 사실 덕에 오늘 있었던 트러블 슈팅의 이해에 조금이나마 도움이 된 것 같다.
아무튼, 유니티를 쓴다면 코드가 쓰여진 위에서부터 아래로 순차적으로 실행이 무조건 보장되지 않는 다는 것을 알게 됐다.