// Creates an entity that contains a cleanup component.
Entity e = EntityManger.CreateEntity(
typeof(Translation), typeof(Rotation), typeof(ExampleCleanup));
// Attempts to destroy the entity but, because the entity has a cleanup component, Unity doesn't actually destroy the entity. Instead, Unity just removes the Translation and Rotation components.
EntityManager.DestroyEntity(e);
// The entity still exists so this demonstrates that you can still use the entity normally.
EntityManager.AddComponent<Translation>(e);
// Removes all the components from the entity. This destroys the entity.
EntityManager.DestroyEntity(e, new ComponentTypes(typeof(ExampleCleanup), typeof(Translation)));
// Demonstrates that the entity no longer exists. entityExists is false.
bool entityExists = EntityManager.Exists(e);
清除组件是非托管组件,并且具有与非托管组件相同的所有限制。
创建清理组件
要创建清理组件,请创建一个继承自 ICleanupComponentData 的结构。
以下代码示例显示了一个空的清理组件:
public struct ExampleCleanupComponent : ICleanupComponentData
{
}
public void DynamicBufferExample(Entity e)
{
// Acquires a dynamic buffer of type MyElement.
DynamicBuffer<MyElement> myBuff = EntityManager.GetBuffer<MyElement>(e);
// This structural change invalidates the previously acquired DynamicBuffer.
EntityManager.CreateEntity();
// A safety check will throw an exception on any read or write actions on the buffer.
var x = myBuff[0];
// Reacquires the dynamic buffer after the above structural changes.
myBuff = EntityManager.GetBuffer<MyElement>(e);
var y = myBuff[0];
}
[InternalBufferCapacity(16)]
public struct ExampleBufferComponent : IBufferElementData
{
public int Value;
}```
与其他组件一样,您可以向实体添加动态缓冲区组件。但是,您使用 DynamicBuffer<ExampleBufferComponent> 表示动态缓冲区组件,并使用特定于动态缓冲区组件的 EntityManager API(例如 EntityManager.GetBuffer<T>)与它们进行交互。例如:
```csharp
public void GetDynamicBufferComponentExample(Entity e)
{
DynamicBuffer<MyElement> myDynamicBuffer = EntityManager.GetBuffer<MyElement>(e);
}
访问块中的动态缓冲区
要访问块中的所有动态缓冲区,请使用 ArchetypeChunk.GetBufferAccessor 方法。这需要一个 BufferTypeHandle 并返回一个 BufferAccessor。如果您索引 BufferAccessor,它会返回块的类型为 T 的缓冲区:
以下代码示例显示了如何访问块中某种类型的每个动态缓冲区。
[InternalBufferCapacity(16)]
public struct ExampleBufferComponent : IBufferElementData
{
public int Value;
}
public partial class ExampleSystem : SystemBase
{
protected override void OnUpdate()
{
var query = EntityManager.CreateEntityQuery(typeof(ExampleBufferComponent));
NativeArray<ArchetypeChunk> chunks = query.ToArchetypeChunkArray(Allocator.Temp);
for (int i = 0; i < chunks.Length; i++)
{
UpdateChunk(chunks[i]);
}
chunks.Dispose();
}
private void UpdateChunk(ArchetypeChunk chunk)
{
// Get a BufferTypeHandle representing dynamic buffer type ExampleBufferComponent from SystemBase.
BufferTypeHandle<ExampleBufferComponent> myElementHandle = GetBufferTypeHandle<ExampleBufferComponent>();
// Get a BufferAccessor from the chunk.
BufferAccessor<ExampleBufferComponent> buffers = chunk.GetBufferAccessor(myElementHandle);
// Iterate through all ExampleBufferComponent buffers of each entity in the chunk.
for (int i = 0, chunkEntityCount = chunk.Count; i < chunkEntityCount; i++)
{
DynamicBuffer<ExampleBufferComponent> buffer = buffers[i];
// Iterate through all elements of the buffer.
for (int j = 0; j < buffer.Length; j++)
{
// ...
}
}
}
}
private void Example(Entity e, Entity otherEntity)
{
EntityCommandBuffer ecb = new EntityCommandBuffer(Allocator.TempJob);
// Record a command to remove the MyElement dynamic buffer from an entity.
ecb.RemoveComponent<MyElement>(e);
// Record a command to add a MyElement dynamic buffer to an existing entity.
// The data of the returned DynamicBuffer is stored in the EntityCommandBuffer,
// so changes to the returned buffer are also recorded changes.
DynamicBuffer<MyElement> myBuff = ecb.AddBuffer<MyElement>(e);
// After playback, the entity will have a MyElement buffer with
// Length 20 and these recorded values.
myBuff.Length = 20;
myBuff[0] = new MyElement { Value = 5 };
myBuff[3] = new MyElement { Value = -9 };
// SetBuffer is like AddBuffer, but safety checks will throw an exception at playback if
// the entity doesn't already have a MyElement buffer.
DynamicBuffer<MyElement> otherBuf = ecb.SetBuffer<MyElement>(otherEntity);
// Records a MyElement value to append to the buffer. Throws an exception at
// playback if the entity doesn't already have a MyElement buffer.
ecb.AppendToBuffer<MyElement>(otherEntity, new MyElement { Value = 12 });
}
您可以重新解释 DynamicBuffer<T> 以获得另一个 DynamicBuffer<U>,其中 T 和 U 具有相同的大小。如果您想将组件的动态缓冲区重新解释为组件所附加的实体的动态缓冲区,这将很有用。这种重新解释为相同的内存设置了别名,因此更改一个索引 i 处的值会更改另一个索引 i 处的值。
以下代码示例显示了如何解释动态缓冲区。它假设存在一个名为 MyElement 的动态缓冲区,并包含一个名为 Value 的 int 字段。
public class ExampleSystem : SystemBase
{
private void ReinterpretEntitysChunk(Entity e)
{
DynamicBuffer<MyElement> myBuff = EntityManager.GetBuffer<MyElement>(e);
// Valid as long as each MyElement struct is four bytes.
DynamicBuffer<int> intBuffer = myBuff.Reinterpret<int>();
intBuffer[2] = 6; // same effect as: myBuff[2] = new MyElement { Value = 6 };
// The MyElement value has the same four bytes as int value 6.
MyElement myElement = myBuff[2];
Debug.Log(myElement.Value); // 6
}
}
private void ChunkComponentExample(Entity e)
{
// Adds ExampleChunkComp to the passed in entity's chunk.
EntityManager.AddChunkComponent<ExampleChunkComp>(e);
// Finds all chunks with an ExampleComponent and an ExampleChunkComponent.
// To distinguish chunk components from a regular IComponentData, You must
// specify the chunk component with ComponentType.ChunkComponent.
EntityQuery query = GetEntityQuery(typeof(ExampleComponent), ComponentType.ChunkComponent<ExampleChunkComp>());
NativeArray<ArchetypeChunk> chunks = query.ToArchetypeChunkArray(Allocator.Temp);
// Sets the ExampleChunkComp value of the first chunk.
EntityManager.SetChunkComponentData<ExampleChunkComp>(chunks[0], new ExampleChunkComp { Value = 6 });
// Gets the ExampleChunkComp value of the first chunk.
ExampleChunkComp exampleChunkComp = EntityManager.GetChunkComponentData<ExampleChunkComp>(chunks[0]);
Debug.Log(exampleChunkComp.Value) // 6
}
private void ChunkComponentExample(Entity e)
{
// Sets the ExampleChunkComp value of the entity's chunk.
EntityManager.SetChunkComponentData<MyChunkComp>(e, new MyChunkComp { Value = 6 });
// Sets the ExampleChunkComp value of the entity's chunk.
MyChunkComp myChunkComp = EntityManager.GetChunkComponentData<MyChunkComp>(e);
Debug.Log(myChunkComp.Value) // 6
}
struct MyJob : IJobChunk
{
public ComponentTypeHandle<ExampleChunkComponent> ExampleChunkCompHandle;
public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex)
{
// Get the chunk's MyChunkComp.
ExampleChunkComponent myChunkComp = chunk.GetChunkComponentData(ExampleChunkCompHandle);
// Set the chunk's MyChunkComp.
chunk.SetChunkComponentData(ExampleChunkCompHandle, new ExampleChunkComponent { Value = 7 });
}
}
IsComponentEnabled(Entity e):如果实体 e 具有组件 T 并且它已启用,则返回 true。如果实体 e 有组件 T,但它被禁用,则返回 false。断言实体 e 是否没有组件 T,或者 T 是否未实现 IEnableableComponent。
SetComponentEnabled(Entity e, bool enable):如果实体 e 有组件 T,则根据 enable 的值启用或禁用它。断言实体 e 是否没有组件 T,或者 T 是否未实现 IEnableableComponent。 例如:
// ... in a SystemBase OnUpdate()
Entity e = this.EntityManager.CreateEntity(typeof(Health));
ComponentLookup<Health> healthLookup = this.GetComponentLookup<>();
// true
bool b = healthLookup.IsComponentEnabled(e);
// disable the Health component of the entity
healthLookup.SetComponentEnabled(e, false);
// though disabled, the component can still be read and modified
Health h = healthLookup(e);
您可以使用 ComponentLookup.SetComponentEnabled(Entity,bool) 从工作线程安全地启用或禁用实体,因为不需要进行结构更改。该作业必须具有对组件 T 的写访问权。您应该避免启用或禁用另一个线程可能在运行中处理的实体上的组件,因为这通常会导致竞争条件。
查询启用组件
禁用组件 T 的实体匹配查询,就好像它根本没有组件 T 一样。例如,如果实体 E 具有组件 T1(启用)、T2(禁用)和 T3(禁用):
public struct Health : IComponentData, IEnableableComponent
{
public float Value;
}
// ... in a SystemBase OnUpdate()
Entity e1 = this.EntityManager.CreateEntity(typeof(Health), typeof(Translation));
Entity e2 = this.EntityManager.CreateEntity(typeof(Health), typeof(Translation));
// true (components begin life enabled)
bool b = this.EntityManager.IsComponentEnabled<Health>(e1);
// disable the Health component on the first entity
this.EntityManager.SetComponentEnabled<Health>(e1, false);
EntityQuery query = new EntityQueryBuilder(Allocator.Temp).WithAll<Health, Translation>().Build(this);
// the returned array does not include the first entity
var entities = query.ToEntityArray(Allocator.Temp);
// the returned array does not include the Health of the first entity
var healths = query.ToComponentDataArray<Health>(Allocator.Temp);
// the returned array does not include the Translation of the first entity
var translations = query.ToComponentDataArray<Translation>(Allocator.Temp);
// This query matches components whether they're enabled or disabled
var queryIgnoredEnableable = new EntityQueryBuilder(Allocator.Temp).WithAll<Health, Translation>().WithOptions(EntityQueryOptions.IgnoreComponentEnabledState).Build(this);
// the returned array includes the Translations of both entities
var translationsAll = queryIgnoreEnableable.ToComponentDataArray<Translation>(Allocator.Temp);