ECS入门 2.IJobEntityBatch
前言
此示例演示了一个基于作业的 ECS 系统,该系统可旋转一对多维数据集。此示例不是按实体迭代,而是按块进行迭代。(块是包含具有相同原型的实体的内存块,也就是说,它们都具有相同的组件集。
它显示了什么?
此示例演示了通过直接访问块来循环访问实体的另一种方法。 在某些情况下,这可以提供比实体更大的灵活性。
与前面的示例一样,RotationSpeedSystem_IJobEntityBatch使用存储在 RotationSpeed_IJobEntityBatch组件中的 数据 更新 对象的旋转。
此示例还演示如何编写自定义创作组件。 与使用“生成授权组件”属性生成一个相比,这可以提供更大的灵活性。
Systems 和 IJobEntityBatch
在此示例中,RotationSpeedSystem_IJobEntityBatch
中的作业现在使用 IJobEntityBatch 实现。
在使用 IJobEntityBatch 实现的作业中,ECS 框架将包含所需组件的每个内存块的原型转储实例传递给您的Execute()
函数。然后,您可以循环访问存储在该块中的组件数组。
请注意,您必须为 IJob 实体批处理作业执行更多的手动设置。这包括构造一个实体查询(EntityQuery
),用于标识系统操作的组件类型。您还必须将ArchetypeChunkComponentType
传递给作业,然后在作业中使用它来获取访问组件数组本身所需的本机数组实例。
使用IJobEntityBatch
的系统可以处理比Entities.ForEach
支持的更复杂的情况,同时保持最大的效率。IJobEntityBatch
提供对要处理的块、实体和组件的显式控制。您还可以以小于完整块的批次处理实体,这在某些情况下可能更有效,例如,当您具有计算成本高昂的算法和少量实体时。
从游戏对象转换为实体
ConvertToEntity
的MonoBehaviour在唤醒时将游戏对象及其子项转换为实体和 ECS 组件。目前,转换实体可以转换的一组内置 Unity 单行为包括Transform
和MeshRenderer
。您可以使用“Entity Debugger”(菜单:“Window”>“Analysis”>“Entity Debugger”)检查转换创建的 ECS 实体和组件。
您可以在自己的MonoBehaviour上实现“IConvertGameObjectEntity”接口,以提供转换函数,“ConvertToEntity”将用于将存储在MonoBehaviour中的数据转换为 ECS 组件。
在此示例中,RotationSpeedAuthoring_IJobEntityBatch
中MonoBehaviour使用 IConvertGame 对象在转换时将RotationSpeed_IJobEntityBatch
组件添加到实体。
项目
场景布置
创建两个Cube
其中一个作为父物体,并勾选Inspector
面板上的ConvertToEntity
代码编写
RotationSpeed_IJobEntityBatch.cs
using System;
using Unity.Entities;
// ReSharper disable once InconsistentNaming
// 在Editor显示出来
[Serializable]
public struct RotationSpeed_IJobEntityBatch : IComponentData
{
public float RadiansPerSecond;
}
RotationSpeedAuthoring_IJobEntityBatch.cs
using Unity.Entities;
using Unity.Mathematics;
using UnityEngine;
// ReSharper disable once InconsistentNaming
//添加快捷菜单
[AddComponentMenu("DOTS Samples/IJobEntityBatch/Rotation Speed")]
//通过声明版本号,ComponentSystem 可以确保资产管道的任何缓存数据都是使用活动代码准备的。如果任何转换系统或优化系统的版本号发生变化或添加了新的转换系统,则将重新转换场景。
//[ConverterVersion("joe", 1)]
//继承自IConvertGameObjectToEntity在 GameObject 转换期间,各种转换系统会处理它们识别的 MonoBehaviour 组件并将它们转换为基于 ECS 的组件。
//例如,其中一个 Unity.Transforms 转换系统检查 UnityEngine.Transform 组件并添加 ECS 组件(例如LocalToWorld)来替换它。
//您可以实施一个IConvertGameObjectToEntityMonoBehaviour 组件指定自定义转换步骤。
//转换的 GameObjects 数量和创建的实体数量之间通常不会存在一一对应的关系;
//GameObject 上的 MonoBehaviours 数量与添加到实体的 ECS 组件数量之间也不存在差异。
public class RotationSpeedAuthoring_IJobEntityBatch : MonoBehaviour, IConvertGameObjectToEntity
{
public float DegreesPerSecond = 360.0F;
// The MonoBehaviour data is converted to ComponentData on the entity.
// MonoBehaviour数据将转换为实体上的组件数据。
// We are specifically transforming from a good editor representation of the data (Represented in degrees)
// 我们专门从数据的良好编辑器表示(以度为单位表示)进行转换
// To a good runtime representation (Represented in radians)
// 到良好的运行时表示(以弧度表示)
public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
{
//新建一个RotationSpeed_IJobEntityBatch组件
var data = new RotationSpeed_IJobEntityBatch { RadiansPerSecond = math.radians(DegreesPerSecond) };
//添加组件
dstManager.AddComponentData(entity, data);
}
}
RotationSpeedSystem_IJobEntityBatch.cs
using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Jobs;
using Unity.Mathematics;
using Unity.Transforms;
// This system updates all entities in the scene with both a RotationSpeed_IJobChunk and Rotation component.
// 此系统使用RotationSpeed_IJobChunk和Rotation组件更新场景中的所有实体。
// ReSharper disable once InconsistentNaming
public partial class RotationSpeedSystem_IJobChunk : SystemBase
{
/// <summary>
/// 实体查询
/// </summary>
EntityQuery m_Query;
protected override void OnCreate()
{
// Cached access to a set of ComponentData based on a specific query
// 基于特定查询对一组组件数据的缓存访问
m_Query = GetEntityQuery(typeof(Rotation), ComponentType.ReadOnly<RotationSpeed_IJobEntityBatch>());
}
// Use the [BurstCompile] attribute to compile a job with Burst. You may see significant speed ups, so try it!
// 使用 [BurstCompile] 属性编译具有突发的作业。您可能会看到明显的加速,所以试试吧!
[BurstCompile]
struct RotationSpeedJob : IJobEntityBatch
{
public float DeltaTime;
public ComponentTypeHandle<Rotation> RotationTypeHandle;
[ReadOnly] public ComponentTypeHandle<RotationSpeed_IJobEntityBatch> RotationSpeedTypeHandle;
public void Execute(ArchetypeChunk batchInChunk, int batchIndex)
{
var chunkRotations = batchInChunk.GetNativeArray(RotationTypeHandle);
var chunkRotationSpeeds = batchInChunk.GetNativeArray(RotationSpeedTypeHandle);
for (var i = 0; i < batchInChunk.Count; i++)
{
var rotation = chunkRotations[i];
var rotationSpeed = chunkRotationSpeeds[i];
// Rotate something about its up vector at the speed given by RotationSpeed_IJobChunk.
chunkRotations[i] = new Rotation
{
Value = math.mul(math.normalize(rotation.Value),
quaternion.AxisAngle(math.up(), rotationSpeed.RadiansPerSecond * DeltaTime))
};
}
}
}
// OnUpdate runs on the main thread.
// OnUpdate 在主线程上运行。
protected override void OnUpdate()
{
// Explicitly declare:明确声明:
// - Read-Write access to Rotation - 对旋转的读写访问权限
// - Read-Only access to RotationSpeed_IJobChunk - 对RotationSpeed_IJobChunk的只读访问权限
var rotationType = GetComponentTypeHandle<Rotation>();
var rotationSpeedType = GetComponentTypeHandle<RotationSpeed_IJobEntityBatch>(true);
//新建一个Job
var job = new RotationSpeedJob()
{
RotationTypeHandle = rotationType,
RotationSpeedTypeHandle = rotationSpeedType,
DeltaTime = Time.DeltaTime
};
//并行Job
Dependency = job.ScheduleParallel(m_Query, Dependency);
}
}
添加并设置脚本
总结
GameObject自动转换为Entity
当MonoBehaviour
继承IConvertGameObjectToEntity
可以实现自定义挂载组件
BurstCompile多线程运算
使用[BurstCompile]
属性可将方法变更为多线程
创建一个Job
在System中调用