官方案例HelloCube和Tank学习研究:
HelloCube:
通用部分:
使用Authoring根据Inspector的勾选添加为Entity添加不同Component。然后每个System会根据实体添加的Component运行不同的System逻辑。

1. MainThread
简单构造System
先看System接口定义:
cs
[RequireImplementors]
public interface ISystem
{
/// <summary>
/// Called when this system is created.
/// </summary>
/// <remarks>
/// Implement an `OnCreate` function to set up system resources when it is created.
///
/// `OnCreate` is invoked before the the first time <see cref="ISystemStartStop.OnStartRunning(ref SystemState)"/>
/// and <see cref="OnUpdate"/> are invoked.
/// </remarks>
/// <param name="state">The <see cref="SystemState"/> backing this system instance</param>
[RequiredMember]
void OnCreate(ref SystemState state) { }
/// <summary>
/// Called when this system is destroyed.
/// </summary>
/// <remarks>
/// Systems are destroyed when the application shuts down, the World is destroyed, or you
/// call <see cref="World.DestroySystem"/>. In the Unity Editor, system destruction occurs when you exit
/// Play Mode and when scripts are reloaded.
/// </remarks>
/// <param name="state">The <see cref="SystemState"/> backing this system instance</param>
[RequiredMember]
void OnDestroy(ref SystemState state) { }
/// <summary>
/// Implement `OnUpdate` to perform the major work of this system.
/// </summary>
/// <remarks>
/// <p>
/// By default, the system invokes `OnUpdate` once every frame on the main thread.
/// To skip OnUpdate if all of the system's [EntityQueries] are empty, use the
/// [RequireMatchingQueriesForUpdateAttribute]. To limit when OnUpdate is invoked, you can
/// specify components that must exist, or queries that match specific Entities. To do
/// this, call <see cref="SystemState.RequireForUpdate{T}"/> or
/// <see cref="SystemState.RequireForUpdate(EntityQuery)"/>
/// in the system's OnCreate method. For more information, see <see cref="SystemState.ShouldRunSystem"/>.
/// </p>
/// <p>
/// You can instantiate and schedule an <see cref="IJobChunk"/> instance; you can use the
/// [C# Job System] or you can perform work on the main thread. If you call <see cref="EntityManager"/> methods
/// that perform structural changes on the main thread, be sure to arrange the system order to minimize the
/// performance impact of the resulting [sync points].
/// </p>
///
/// [sync points]: xref:concepts-structural-changes
/// [C# Job System]: https://docs.unity3d.com/Manual/JobSystem.html
/// [EntityQueries]: xref:Unity.Entities.EntityQuery
/// [RequireMatchingQueriesForUpdateAttribute]: xref:Unity.Entities.RequireMatchingQueriesForUpdateAttribute
/// </remarks>
/// <param name="state">The <see cref="SystemState"/> backing this system instance</param>
[RequiredMember]
void OnUpdate(ref SystemState state) { }
}
有3处接口
OnCreate里可以添加是否让System在OnUpdate里运行
类似:

当至少有一个Entity包含ExecuteIJobEntity组件。会激活Update
OnDestory就是在System被销毁时运行
OnUpdate里实现了简单的旋转。
这里Query是查询当前符合要求Component的实体。
RW是即可读又可写,RO是只可读,在system里不可改变其属性

2. IJobEntity
该案例是把System里执行的逻辑换成Job,这样程序的运行可以利用多核在不用非在主线程里运行。这样会提升CPU的使用率

这个Job实现的Schedule可以实现在代码里顺序执行。
比如增加下列代码测试,就可以发现物体上下移动了


3. Aspects
上述的读取数据还得根据情况写RW,RO。
Unity提供了一个接口如图:

不需要去传入值,且函数名可以自定义

在使用时直接查询就可以正确去找到对应拥有Component组件的实体进行遍历。这个比较方便
需要注意是必须用
readonly partial进行修饰。
可以看到Unity自己扩展定义后的内容

4. Prefabs
cs
public partial struct SpawnSystem : ISystem
{
uint updateCounter;
[BurstCompile]
public void OnCreate(ref SystemState state)
{
// This call makes the system not update unless at least one entity in the world exists that has the Spawner component.
state.RequireForUpdate<Spawner>();
state.RequireForUpdate<ExecutePrefabs>();
}
[BurstCompile]
public void OnUpdate(ref SystemState state)
{
// Create a query that matches all entities having a RotationSpeed component.
// (The query is cached in source generation, so this does not incur a cost of recreating it every update.)
var spinningCubesQuery = SystemAPI.QueryBuilder().WithAll<RotationSpeed>().Build();
// Only spawn cubes when no cubes currently exist.
if (spinningCubesQuery.IsEmpty)
{
var prefab = SystemAPI.GetSingleton<Spawner>().Prefab;
// Instantiating an entity creates copy entities with the same component types and values.
var instances = state.EntityManager.Instantiate(prefab, 500, Allocator.Temp);
// Unlike new Random(), CreateFromIndex() hashes the random seed
// so that similar seeds don't produce similar results.
var random = Random.CreateFromIndex(updateCounter++);
foreach (var entity in instances)
{
// Update the entity's LocalTransform component with the new position.
var transform = SystemAPI.GetComponentRW<LocalTransform>(entity);
transform.ValueRW.Position = (random.NextFloat3() - new float3(0.5f, 0, 0.5f)) * 20;
}
}
}
}
拿到对象实例,这里是Dots需要用结构体,所以跟Unity之前的GameObject生成有所区别
var prefab = SystemAPI.GetSingleton<Spawner>().Prefab;
这里是生成实例的DOTS版本
var instances = state.EntityManager.Instantiate(prefab, 500, Allocator.Temp);
cs
public partial struct FallAndDestroySystem : ISystem
{
[BurstCompile]
public void OnCreate(ref SystemState state)
{
state.RequireForUpdate<ExecutePrefabs>();
}
[BurstCompile]
public void OnUpdate(ref SystemState state)
{
// rotation
float deltaTime = SystemAPI.Time.DeltaTime;
foreach (var (transform, speed) in
SystemAPI.Query<RefRW<LocalTransform>, RefRO<RotationSpeed>>())
{
// ValueRW and ValueRO both return a ref to the actual component value.
// The difference is that ValueRW does a safety check for read-write access while
// ValueRO does a safety check for read-only access.
transform.ValueRW = transform.ValueRO.RotateY(
speed.ValueRO.RadiansPerSecond * deltaTime);
}
// An EntityCommandBuffer created from EntityCommandBufferSystem.Singleton will be
// played back and disposed by the EntityCommandBufferSystem when it next updates.
var ecbSingleton = SystemAPI.GetSingleton<BeginSimulationEntityCommandBufferSystem.Singleton>();
var ecb = ecbSingleton.CreateCommandBuffer(state.WorldUnmanaged);
// Downward vector
var movement = new float3(0, -SystemAPI.Time.DeltaTime * 5f, 0);
// WithAll() includes RotationSpeed in the query, but
// the RotationSpeed component values will not be accessed.
// WithEntityAccess() includes the Entity ID as the last element of the tuple.
foreach (var (transform, entity) in
SystemAPI.Query<RefRW<LocalTransform>>()
.WithAll<RotationSpeed>()
.WithEntityAccess())
{
transform.ValueRW.Position += movement;
if (transform.ValueRO.Position.y < 0)
{
// Making a structural change would invalidate the query we are iterating through,
// so instead we record a command to destroy the entity later.
ecb.DestroyEntity(entity);
}
}
}
}
Dots版本的删除实体:
var ecbSingleton = SystemAPI.GetSingleton<BeginSimulationEntityCommandBufferSystem.Singleton>();
var ecb = ecbSingleton.CreateCommandBuffer(state.WorldUnmanaged);
ecb.DestroyEntity(entity);
BeginSimulationEntityCommandBufferSystem.Singleton:我的理解就是全部关闭实例Manager
EntityCommandBuffer:是每个实体管理的控制器,类似GameObjectManager。所有的创建销毁实体都是通过他来控制。