介紹完ECS的大致理念之後,我們接着單獨來了解下Entity,Component和System的概念以及使用,首先我們先從Entity開始入手。
Entity概念
我們來看下Entity的組成,代碼如下,只有Index和Version兩個字段。
public struct Entity
{
/// <summary>
/// The ID of an entity.
/// </summary>
public int Index;
public int Version;
}
我們可以理解爲Entity就是遊戲中不同的物體,其中只有一個ID,也就是Index用來進行區分。Entity中不存在任何數據和行爲,這些交給了Component和System去辦了。
在每個World中,會有一個EntityManager來管理該World下所有的Entity,EntityManager利用NativeArray來管理Entities並且紀錄了每個Entity和Component的關係。
World
我們可以將其理解成一種Manager,每一個World都擁有一個EntityManager和一系列的System,我們可以自由的創建World:
World newWorld = new World("NewWorld");
ECS中會有一個默認的World(DefaultWorld),可以通過 World.DefaultGameObjectInjectionWorld 來獲取它。系統自帶的System和我們自定義的System默認都會被添加進這個World。
創建Entity
創建一個Entity
前面我們說到Entity是由EntityManager來管理的,而EntityManager又存放與World之中,因此要創建Entity,我們先要獲得EntityManager,然後就可以利用其CreateEntity方法來創建我們的Entity了。
EntityManager entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
Entity entity = mEntityManager.CreateEntity();
若要爲Entity添加組件,也需要使用EntityManager來完成,例如添加一個用於存放座標信息的Translation Component並且賦值:
entityManager.AddComponentData(entity, new Translation(){Value = new float3(0, 0, 0)});
若要刪除Entity上的Component,自然是要用RemoveComponent方法了:
entityManager.RemoveComponent<Translation>(entity);
除此之外,我們也可以在創建的時候就指定好需要添加的組件,然後再利用 SetComponentData 賦值,例如:
Entity entity = entityManager.CreateEntity(typeof(Translation), typeof(OtherComponent), ...);
entityManager.SetComponentData(entity, new Translation(){Value = new float3(0, 0, 0)});
前面我們提到Component的不同組合被稱爲Archetype,因此我們也可實現聲明好Archetype,然後用其創建Entity,這樣生成的Entity就會帶有Archetype所代表的所有Component(其實和上面那種方法是等價的)。
EntityArchetype entityArchetype = entityManager.CreateArchetype(typeof(Translation), typeof(LocalToWorld), typeof(RenderMesh));
Entity entity = entityManager.CreateEntity(entityArchetype);
entityManager.SetComponentData(entity, new Translation(){Value = new float3(0, 0, 0)});
對於已存在的Entity,我們可以使用EntityManager.Instantiate方法來進行copy
Entity entity2 = entityManager.Instantiate(entity);
創建多個Entity
CreateEntity不僅可以創建一個Entity,也可以同時創建多個Entity,前提是要事先聲明好EntityArchetype,例如
NativeArray<Entity> entityArray = new NativeArray<Entity>(10, Allocator.Temp);
entityManager.CreateEntity(entityArchetype, entityArray);
entityArray.Dispose();
等價於
entityManager.CreateEntity(entityArchetype, 10, Allocator.Temp).Dispose();;
對於已存在的Entities我們可以進行整體copy,Entities中的數據都會被copy到新的Entities中。
NativeArray<Entity> copyEntityArray = new NativeArray<Entity>(10, Allocator.Temp);
entityManager.Instantiate(entityArray, copyEntityArray);
copyEntityArray.Dispose();
Instantiate也可將單個Entity進行多份copy
entityManager.Instantiate(entity, 10, Allocator.Temp);
銷燬Entity
entityManager.DestroyEntity(entity);