상황
ECS로 심리스 오픈월드를 구현하고싶다. 자연스럽게 지역과 지역을 넘나드려면 로딩 속도가 생명이다. 게임 데이터에는 여러가지가 있겠지만 NavMesh만 우선 생각해보자.
게임 속에는 공중유닛, 수영할 수 있는 유닛, 지상유닛 등으로 나뉘어져 각각 NavMesh가 필요하다.
NavMesh는 굉장히 간략하게 보자면 폴리곤의 집합과 인접 데이터의 모음이라 할 수 있으며 이 데이터들의 길이는 제각각이다. 그럼 이걸 어떻게 구현할 것인가?
DynamicBuffer?
public struct NavPolygonElement : IBufferElementData
{
public int StartVertexIndex;
public int VertexCount;
public int NeighborStart; // 인접 인덱스 버퍼에서의 시작 위치
}
ECS에서 가변배열하면 DynamicBuffer를 떠올릴 수 있다. 그리고 실제로 DynamicBuffer로 Navmesh를 구현할 수 있다. 유닛마다 NavMesh데이터를 한 벌씩 가지는 건 말이 안되니, 맵 데이터에서 한번 DynamicBuffer로 데이터를 변환하고 유닛마다 NavMesh의 id를 통해 접근할 수 있을 것이다.
근데 이건 사실 좋지 않다. 우선 지역 데이터(Subscene)을 저장장치에서 메모리로 올린다. 이후 SubScene 파일에서 읽어온 데이터 스트림을 ECS 메모리 구조에 맞게 재구성 해야한다. 이 과정에서 ECS메모리 영역에 새로 힙을 할당하고 데이터를 복사하는 과정이 포함된다. 이러 다음 지역을 로드할 때 시간이 더 걸릴 뿐더러, 맵이 로드/해제 될 때 메모리 파편화가 생길 여지가 있다.
또한 DynamicBuffer는 특정 엔티티에 귀속된 가변 데이터다. 따라서 기본적으로 Safety Check가 수행된다.
BlobAsset
public struct NavPolygonBlob
{
public BlobArray<float3> Vertices;
public BlobArray<int> NeighborIndices;
}
사실 필요한 데이터는 이미 Subscene이 bake될 때 다 마련됐다. 이걸 그대로 쓰면 안 될까? 라는 의문이 든다. 그렇다 Subscene이 로드될 때 그 데이터를 그대로 쓰는 게 BlobAsset이다.
BlobAsset은 불변(Immutable)의 바이너리 데이터 덩어리이다. SubScene이 로드될 때, 유니티는 이 데이터를 ECS의 메모리 영역에 복사하지 않고 그냥 디스크에 저장된 바이너리 상태 그대로 Native Memory 영역에 로드한다. 그리고 이것에 대한 참조 포인터를 넘겨주면 끝이다.
public struct NavMeshInstance : IComponentData
{
public BlobAssetReference<NavMeshBlob> BlobRef;
}
public void Execute(in NavMeshInstance instance)
{
ref var mesh = ref instance.BlobRef.Value;
var firstVertex = mesh.Vertices[0];
}
BlobAsset은 DynamicBuffer와 달리 Safety Check가 필요 없다.
정확한 사용법은 AI한테 물어보자.
'게임엔진 > ECS(Unity)' 카테고리의 다른 글
| ECS에서 Behavior Tree 구현하기 (ft. xNode) (0) | 2026.02.08 |
|---|---|
| ECB + sortKey (0) | 2025.11.30 |
| Entities - 컴포넌트 구조 (0) | 2023.02.25 |