ECS1.0 pre 解读

ECS1.0 pre 解读

  • 前言
  • 详细
    • 1.C# 作业系统 The C# Job system
    • 2.实体和组件 Entities and components
      • (1) 实体和组件 Entities and components
      • (2) 世界和实体管理器 Worlds and EntityManagers
      • (3) 原型和块 Archetypes and chunks
        • Archetypes
        • Chunks
      • (4) 查询 Queries
      • (5) IComponentData组件
        • 标记组件 Tag Component
      • (6) DynamicBuffer 组件 DynamicBuffer components
      • (7) 方面 Aspects
        • 创建aspect的实例 Creating instances of an aspect
    • 3.系统 Systems
      • (1) 系统组和系统更新顺序 System groups and system update order
      • (2) 创造世界和系统 Creating worlds and systems
      • (3) 系统状态 SystemState
      • (4) SystemAPI
    • 4.访问作业中的实体 Accessing entities in jobs
    • 5.实体命令缓冲区 Entity command buffers
    • 6.Transform组件和系统 Transform components and systems
    • 7.烘焙和实体场景 Baking and entity scenes
      • (1) 访问 Baker 中的数据 Accessing data in a Baker
      • (2) 加载和卸载实体场景 Loading and unloading entity scenes
    • 8.其他实体功能 Additional Entities features
  • 总结

前言

简单介绍一下需要了解的几个关键点

Unity官方文档: https://github.com/Unity-Technologies/EntityComponentSystemSamples

详细

1.C# 作业系统 The C# Job system

  • 非托管集合 Unmanaged Collections
  • C# 作业 C# Jobs
  • C# 作业依赖项 Job Dependencies
  • 作业安全检查 Job Safety Checks
  • 并行作业 Parallel Jobs

详情: https://github.com/Unity-Technologies/EntityComponentSystemSamples/blob/master/Docs/jobs.md

2.实体和组件 Entities and components

(1) 实体和组件 Entities and components

实体是游戏对象的轻量级、非托管替代品。实体在很多方面类似于 GameObjects 并且可以发挥相似的作用,但它们有关键的区别:

  • 与 GameObject 不同,实体不是托管对象,而只是一个唯一的标识符号。
  • 与实体关联的component通常是struct value
  • 单个实体只能具有任何给定类型的一个组件。例如,单个实体不能有两个类型为Foo的组件。(一个Entity上只能挂载一个名为Foo的组件)
  • 虽然实体组件类型可以被赋予方法,但通常不鼓励这样做。(在component中不建议设置除了GET/SET之外的Function)
  • 一个实体没有内置的父子概念。相反,标准Parent组件包含对另一个实体的引用,允许形成实体转换层次结构。(Entity的父子结构为引用)

实体组件类型是通过实现这些接口来定义的:

组件种类 描述
IComponentData 定义最常见、最基本的组件类型。
IBufferElementData 定义动态缓冲区(可增长数组)组件类型。
ISharedComponent 定义一个共享组件类型,其值可以被多个实体共享。
ICleanupComponent 定义清理组件类型,这有助于正确设置和拆卸资源。
ISharedComponent 定义一个共享组件类型,其值可以被多个实体共享。

使用IComponentData定义最常见、最基本的组件类型。
eg

  1. 作为Tag查找使用
/// 
/// 空组件称为“标记组件”
/// 
struct TankTag : IComponentData
{

}

  1. 作为组件挂载使用
using Unity.Entities;

/// 
/// 同样的方法对于炮弹,我们正在创建一个组件来识别实体。
/// 但这次它不是一个标记组件(空的),因为它包含数据: Speed字段。
/// 它不会立即被使用,但当我们实施议案时会变得有意义。
/// 
struct CannonBallComponent : IComponentData
{
    public float Speed; 
}

(2) 世界和实体管理器 Worlds and EntityManagers

World是实体的集合。一个实体的 ID 号只在它自己的世界中是唯一的,即在一个世界中具有特定 ID 的实体与在不同世界中具有相同 ID 的实体完全无关。

一个World也拥有一组系统,它们是在主线程上运行的代码单元,通常每帧一次。一个世界的实体通常只能被该世界系统访问(以及这些系统安排的工作),但这不是强制限制。

世界中的实体通过世界的EntityManager.
EntityManager方法包括:

方法 描述
CreateEntity() 创建一个新实体。
Instantiate() 使用现有实体的所有组件的副本创建一个新实体。
DestroyEntity() 销毁现有实体。
AddComponent() 将类型 T 的组件添加到现有实体。
RemoveComponent() 从现有实体中移除类型 T 的组件。
HasComponent() 如果实体当前具有 T 类型的组件,则返回 true。
GetComponentData() 检索类型 T 的实体组件的值。
SetComponentData(T) 覆盖类型 T 的实体组件的值。

Tip : 以上所有方法,除了GetComponentDataSetComponentData,都是结构变化操作。

eg

/// 
/// 空组件称为“标记组件”
/// 
struct TankTag : IComponentData
{

}
using Unity.Burst;
using Unity.Entities;

[BurstCompile]
partial struct TurretShootingSystem : ISystem
{

    [BurstCompile]
    public void OnCreate(ref SystemState state)
    {

    }
	[BurstCompile]
    public void OnDestroy(ref SystemState state)
    {

    }
	[BurstCompile]
    public void OnUpdate(ref SystemState state)
    {
        //拿到当前世界的EntityManager
        EntityManager entityManager = state.EntityManager;
        //创建一个新实体
        Entity entity = entityManager.CreateEntity();
        //使用现有实体的所有组件的副本创建一个新实体
        Entity newEntity = entityManager.Instantiate(entity);
        //销毁现有实体
        entityManager.DestroyEntity(newEntity);
        //将类型 T 的组件添加到现有实体
        entityManager.AddComponent<TankTag>(entity);
        //从现有实体中移除类型 T 的组件
        entityManager.RemoveComponent<TankTag>(entity);
        //如果实体当前具有 T 类型的组件,则返回 true
        bool hasCom = entityManager.HasComponent<TankTag>(entity);
        //检索类型 T 的实体组件的值
        TankTag tankTag = entityManager.GetComponentData<TankTag>(entity);
        //覆盖类型 T 的实体组件的值
        entityManager.SetComponentData(entity,tankTag);
    }
}

(3) 原型和块 Archetypes and chunks

Archetypes

原型代表世界中组件类型的特定组合:世界中具有特定组件类型集的所有实体都存储在同一原型中。

  • 世界上所有具有组件类型A、B和C的实体都存储在一个原型中,
  • …只有组件类型A和B(但不是C)的实体一起存储在第二个原型中,
  • …并且具有组件类型B和D的实体存储在第三个原型中。
  • 实际上,添加或删除实体的组件会更改实体所属的原型,从而需要EntityManager实际将实体及其组件从其旧原型移动到新原型。

Tip : 过于频繁地在原型之间移动太多实体会增加大量成本。

原型是在EntityManager您创建和修改实体时创建的,因此您不必担心显式创建原型。即使所有实体都从原型中移除,原型也只有在其世界被摧毁时才会被摧毁。

Chunks

原型的实体存储在属于称为chunks的原型的 16KiB 内存块中。每个块最多存储 128 个实体(精确数量取决于原型组件类型的数量和大小)。

每种类型的实体 ID 和组件都存储在块内它们自己单独的数组中。
块的创建和销毁由EntityManager处理:

  • 只有当EntityManager一个实体被添加到一个已经存在的块都已满的​​原型时,才会创建一个新块。
  • EntityManager只有当块的最后一个实体被移除时,才会销毁该块。

任何块在EntityManager内添加、删除或移动实体的操作都称为结构更改。此类更改通常只应在主线程上进行,而不应在作业中进行。(可以使用 EntityCommandBuffer来解决此限制。)

(4) 查询 Queries

一个EntityQuery有效地找到具有一组指定的组件类型的所有实体。例如,如果查询查找具有组件类型A和B的所有实体,则该查询将收集具有这两种组件类型的所有原型的块,而不管这些原型可能具有的任何其他组件类型。因此,这样的查询将匹配具有组件类型A和B的实体,但该查询也会匹配具有组件类型 A、B和C的实体。

与查询匹配的原型将被缓存,直到下一次将新原型添加到世界中。因为世界中现有的原型集往往会在程序生命周期的早期稳定下来,所以这种缓存往往会提高性能。

查询还可以指定要从匹配原型中排除的组件类型。例如,如果查询查找具有组件类型A和B但不具有组件类型C的所有实体,则该查询将匹配具有组件类型A和B的实体,但查询不会匹配具有组件类型A、B和C.

eg

using Unity.Burst;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;

/// 
/// 基于Isystem的非托管系统可以是突发编译,但这还不是默认值。
/// 因此,我们必须使用[BurstCompile]属性显式选择Burst编译。
/// 它必须被添加到结构和OnCreate/0nDestroy/0nUpdate函数上才能生效。
/// 
[BurstCompile]
partial struct TurretRotationSystem : ISystem
{
    //ISystem定义的每一个函数都必须实现,即使为空
    [BurstCompile]
    public void OnCreate(ref SystemState state)
    {

    }
    [BurstCompile]
    public void OnDestroy(ref SystemState state)
    {

    }
    [BurstCompile]
    public void OnUpdate(ref SystemState state)
    {
        //在2秒内绕Y旋转360度所需的旋转量。
        var rotation =quaternion.RotateY(SystemAPI.Time.DeltaTime*math.PI);
        //经典的C#foreach就是我们常说的方面提供了比直接访问组件数据更高级别的接口。“通用foreach”(IFE)。
        //将IFE与方面一起使用是编写主线程代码的一种强大而富有表现力的方式
        foreach (var transform in SystemAPI.Query<TransformAspect>().WithAll<TurretComponent>())
        {
            transform.RotateWorld(rotation);
        }
    }
}

(5) IComponentData组件

最常见的基本类型的组件类型定义为结构实现IComponentData
eg

public struct EnergyShield : IComponentData
{
    public int HitPoints;
    public int MaxHitPoints;
    public float RechargeDelay;
    public float RechargeRate;
}

结构应该是非托管的IComponentData,因此它不能包含任何托管字段类型。具体来说,允许的字段类型是:

  • Blittable types
  • bool
  • char
  • BlobAssetReference, 对 Blob 数据结构的引用
  • Collections.FixedString, 一个固定大小的字符缓冲区
  • Collections.FixedList
  • Fixed array (仅在不安全的上下文中允许)
  • 符合这些相同限制的结构类型(Struct types that conform to these same restrictions.)。

标记组件 Tag Component

没有字段的IComponentData结构称为标记组件。尽管标签组件不存储数据,但它们仍然可以像任何其他组件类型一样从实体中添加和删除,并且它们可用于标记实体以供查询。例如,如果我们表示怪物的所有实体都有一个Monster标签组件,则对Monster组件类型的查询将匹配所有怪物实体。
eg

public struct OnFire : IComponentData
{
    //空组件称为“标记组件”
	//标记组件不占用存储空间,但可以像任何其他组件一样对其//进行查询、添加和删除
}

(6) DynamicBuffer 组件 DynamicBuffer components

DynamicBuffer是一个组件类型,它是一个可调整大小的数组。要定义DynamicBuffer组件类型,请创建一个实现该IBufferElementData接口的结构。

示例

(7) 方面 Aspects

Aspects是实体组件子集上的类对象包装器。方面可用于简化查询和与组件相关的代码。TransformAspect例如,将标准变换组件(、LocalTransformParentTransform)组合在一起WorldTransform
示例

在查询中包含方面与包含由方面包装的组件相同,例如,包含TransformAspect标准变换矩阵组件的查询。

一个方面被定义为只读的部分结构实现IAspect。该结构可以包含以下类型的字段:

字段类型 描述
Entity 包装实体的实体 ID。
RefRW或者RefRO 对包装实体的 T 组件的引用。
EnabledRefRWEnabledRefRO 对包装实体的 T 组件的启用状态的引用。
EnabledRefRWEnabledRefRO $1
DynamicBuffer 包装实体的动态缓冲区 T 组件。
另一个Aspects类型 包含方面将包含 “embedded”Aspects 的所有字段。

eg

using Unity.Entities;

/// 
/// 而不是直接访问炮塔组件,我们正在创建一个方面。Aspects允许您为访问组件提供定制的API。
/// 
readonly partial struct TurretAspect : IAspect
{
    readonly RefRO<TurretComponent> m_Turret;

    //此引用提供了对炮塔组件的只读访问。
    //试图在只读引用上使用ValueRw (而不是ValueRo)是一个错误。
    public Entity CannonBallSpawn=>m_Turret.ValueRO.CannonBallSpawn;
    //注意ValueRO在下列属性中的使用。
    public Entity CannonBallPrefab=>m_Turret.ValueRO.CannonBallPrefab;
}

创建aspect的实例 Creating instances of an aspect

这些 EntityManager 方法创建方面的实例:

方法 描述
GetAspect 返回包装实体的类型 T 的一个Aspect。
GetAspectRO 返回包装实体的类型 T 的只读Aspect。如果您使用任何试图修改底层组件的方法或属性,只读Aspect将引发异常。

方面实例也可以通过SystemAPI.GetAspectRW检索SystemAPI.GetAspectRO或在IJobEntityorSystemAPI.Query循环中访问。

TIP : 在系统中,您应该通过 SystemAPI.GetAspectRWSystemAPI.GetAspectRO不是通过EntityManager方法获取方面实例。与EntityManager方法不同,方法向SystemAPI系统注册方面的底层组件类型,这是系统调度具有每个所需依赖性的作业所必需的。

3.系统 Systems

系统是属于世界并在主线程上运行的代码单元(通常每帧一次)。通常,一个系统只会访问它自己世界的实体,但这不是强制性的限制。
示例

系统被定义为实现ISystem接口的结构,它具有三个关键方法:

ISystemState方法 描述
OnUpdate() 通常每帧调用一次,但这取决于SystemGroup系统所属的系统。
OnCreate() 在第一次调用之前OnUpdate以及系统恢复运行时调用。
OnDestroy() 当系统被销毁时调用。

系统可以另外实现ISystemStartStop,它具有以下方法:

ISystemStartStop方法 描述
OnStartRunning() 在第一次调用 之前和系统属性从 更改为之后OnUpdate的任何时间调用。Enabled false true
OnStopRunning() 在系统属性从 更改为之前OnDestroy和之后调用。Enabled true false

(1) 系统组和系统更新顺序 System groups and system update order

一个世界的系统被组织成系统组。每个系统组都有一个有序的系统列表和其他系统组作为其子项,因此系统组形成一个层次结构,它决定了更新顺序。系统组定义为继承自的类ComponentSystemGroup
更新系统组时,该组通常会按其排序顺序更新其子项,但可以通过覆盖组的更新方法来覆盖此默认行为。

每次从组中添加或删除子项时,组的子项都会重新排序。

属性[UpdateBefore][UpdateAfter]用于确定组中子项之间的相对排序顺序。例如,如果 FooSystem具有属性UpdateBefore(typeof(BarSystem))],则将按排序顺序FooSystem放在前面的某个位置。BarSystem但是,如果FooSystemBarSystem不属于同一组,则该属性将被忽略。如果排序属性与另一个属性相矛盾,则会抛出异常。
eg

//示例系统。
//该系统将添加到称为MySystemGroup的系统组中。
//通过标记将ISystem方法通过标记使“入口点”爆发
//它们和结构本身具有burstCompile属性。
[BurstCompile]
[UpdateInGroup(typeof(MySystemGroup))]
public partial struct MySystem : ISystem
{
    // Called once when the system is created.
    [BurstCompile]
    public void OnCreate(ref SystemState state) { }
    [BurstCompile]
    public void OnDestroy(ref SystemState state) { }
    [BurstCompile]
    public void OnUpdate(ref SystemState state) { }
}

// 一个示例系统组。
public class MySystemGroup : ComponentSystemGroup
{
	//除非您需要,否则系统组是空的
    //覆盖update,ongreate或ondestroy。
}

(2) 创造世界和系统 Creating worlds and systems

默认情况下,自动引导过程会创建一个包含三个系统组的默认世界:

  • InitializationSystemGroupInitialization,它在Unity 播放器循环阶段结束时更新。
  • SimulationSystemGroupUpdate,它在Unity 播放器循环阶段结束时更新。
  • PresentationSystemGroupPreLateUpdate,它在Unity 播放器循环阶段结束时更新。

系统和系统组通常会添加到 SimulationSystemGroup中,但这可以通过使用[UpdateInGroup]属性标记它们来覆盖。例如,如果 FooSystem具有属性UpdateInGroup(typeof(InitializationSystemGroup))]FooSystem将被添加到InitializationSystemGroup而不是SimulationSystemGroup[DisableAutoCreation]自动引导不会实例化具有该属性的系统或系统组。

(3) 系统状态 SystemState

SystemState系统的OnUpdate(), OnCreate(), 和methods的参数OnDestroy()表示系统实例的状态,具有重要的方法和属性,包括:

方法或属性 描述
World 系统的世界。
EntityManager 系统世界的EntityManager
Dependency 用于JobHandle在系统之间传递作业依赖关系。
GetEntityQuery() 返回一个EntityQuery
GetComponentTypeHandle() 返回一个ComponentTypeHandle
GetComponentLookup() 返回一个ComponentLookup

TIP : 尽管可以直接从 获取实体查询、组件类型句柄和组件查找EntityManager,但系统通常只从 获取这些东西是合适的SystemState。通过SystemState,访问的组件类型将被系统跟踪,这对于Dependency属性在系统之间正确传递作业依赖性至关重要。查看有关访问实体的作业的更多信息。

eg

using Unity.Burst;
using Unity.Entities;

[BurstCompile]
partial struct TurretShootingSystem : ISystem
{
    [BurstCompile]
    public void OnCreate(ref SystemState state){}
    [BurstCompile]
    public void OnDestroy(ref SystemState state){}
    [BurstCompile]
    public void OnUpdate(ref SystemState state)
    {
        //拿到当前世界的EntityManager
        EntityManager entityManager = state.EntityManager;
    }
}

(4) SystemAPI

该类有许多静态便捷方法,涵盖了WorldEntityManagerSystemStateSystemAPI相同的大部分功能。

这些SystemAPI方法依赖于源生成器,因此它们只能在SystemIJobEntity(但不是IJobChunk)中工作。SystemAPI这些方法在两种上下文中产生相同的结果,因此SystemAPI通常更容易在这两种上下文之间复制粘贴。

TIP : 如果您对在哪里寻找关键实体功能感到困惑,一般规则是先检查SystemAPI。如果SystemAPI没有您要查找的内容,请在System中查找SystemState,如果您要查找的内容不存在,请在EntityManagerWorld中查找。

SystemAPI提供了一种特殊的Query()方法,通过源代码生成,帮助方便地创建一个foreach循环遍历匹配查询的实体和组件。

eg

using Unity.Burst;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;

/// 
/// 基于Isystem的非托管系统可以是突发编译,但这还不是默认值。
/// 因此,我们必须使用[BurstCompile]属性显式选择Burst编译。
/// 它必须被添加到结构和OnCreate/0nDestroy/0nUpdate函数上才能生效。
/// 
[BurstCompile]
partial struct TurretRotationSystem : ISystem
{
    //ISystem定义的每一个函数都必须实现,即使为空
    [BurstCompile]
    public void OnCreate(ref SystemState state){}
    [BurstCompile]
    public void OnDestroy(ref SystemState state){}
    [BurstCompile]
    public void OnUpdate(ref SystemState state)
    {
        //在2秒内绕Y旋转360度所需的旋转量。
        var rotation =quaternion.RotateY(SystemAPI.Time.DeltaTime*math.PI);
        //经典的C#foreach就是我们常说的方面提供了比直接访问组件数据更高级别的接口。“通用foreach”(IFE)。
        //将IFE与方面一起使用是编写主线程代码的一种强大而富有表现力的方式
        foreach (var transform in SystemAPI.Query<TransformAspect>().WithAll<TurretComponent>())
        {
            transform.RotateWorld(rotation);
        }
    }
}

4.访问作业中的实体 Accessing entities in jobs

您可以使用C# Job System将实体数据的处理卸载到工作线程。Entities 包有两个接口用于定义访问实体的作业:

  • IJobChunk, 其Execute()方法为匹配查询的每个单独块调用一次。
  • IJobEntity,它的Execute()方法为匹配查询的每个实体实体调用一次。

虽然IJobEntity通常更方便编写和使用,但IJobChunk提供更精确的控制。在大多数情况下,它们的性能对于同等工作是相同的。

这个可以与下面一章一起看

5.实体命令缓冲区 Entity command buffers

上面解释比较繁琐,看下面的讲的比较清晰
ECS的简单入门(五):Entity Command Buffer

6.Transform组件和系统 Transform components and systems

LocalTransform组件表示实体的转换

TIP : 虽然您可以安全地读取实体的Child缓冲区组件,但您不应该直接修改它。仅通过设置实体的Parent组件来修改转换层次结构。

每一帧,LocalToWorldSystem计算每个实体的世界空间变换(从LocalTransform实体的组件及其祖先)并将其分配给实体的LocalToWorld组件。
系统Entity.Graphics读取LocalToWorld组件但不读取任何其他转换组件,因此LocalToWorld是实体需要呈现的唯一转换组件。

TransformAspect为使用实体的转换组件提供了一个方便的抽象。

eg

using Unity.Burst;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;

/// 
/// 基于Isystem的非托管系统可以是突发编译,但这还不是默认值。
/// 因此,我们必须使用[BurstCompile]属性显式选择Burst编译。
/// 它必须被添加到结构和OnCreate/0nDestroy/0nUpdate函数上才能生效。
/// 
[BurstCompile]
partial struct TurretRotationSystem : ISystem
{
    //ISystem定义的每一个函数都必须实现,即使为空
    [BurstCompile]
    public void OnCreate(ref SystemState state){ }
    [BurstCompile]
    public void OnDestroy(ref SystemState state){ }
    [BurstCompile]
    public void OnUpdate(ref SystemState state)
    {
        //在2秒内绕Y旋转360度所需的旋转量。
        var rotation =quaternion.RotateY(SystemAPI.Time.DeltaTime*math.PI);
        //经典的C#foreach就是我们常说的方面提供了比直接访问组件数据更高级别的接口。“通用foreach”(IFE)。
        //将IFE与方面一起使用是编写主线程代码的一种强大而富有表现力的方式
        foreach (var transform in SystemAPI.Query<TransformAspect>().WithAll<TurretComponent>())
        {
            transform.RotateWorld(rotation);
        }
    }
}

7.烘焙和实体场景 Baking and entity scenes

烘焙是一个构建时过程,它使用面包师和烘焙系统将子场景转换为实体场景:

  • 子场景是 Unity 场景资产,通过SubScene MonoBehaviour 嵌入到另一个场景中。
  • 实体场景是一组序列化的实体和组件,可以在运行时加载。
  • Baker是一个扩展类Baker,其中 TMonoBehaviour。带有 BakerMonoBehaviour称为创作组件。
  • 烘焙系统是标有[WorldSystemFilter(WorldSystemFilterFlags.BakingSystem)]属性的普通系统。(烘焙系统是完全可选的,通常只有高级用例才需要。)

烘焙子场景通过几个主要步骤完成:

  1. 对于子场景的每个游戏对象,都会创建一个对应的实体。
  2. 执行子场景中每个创作组件的 Baker。每个 Baker 都可以读取创作组件并将组件添加到相应的实体中。
  3. 烘焙系统执行。每个系统都可以以任何方式读取和修改烘焙的实体:设置组件、添加组件、删除组件、创建额外的实体或销毁实体。烘焙系统不应访问子场景的原始游戏对象。

简单来说就是在Sub Scene中的物体会自动转为Entity,并触发Break脚本
eg
ECS1.0 pre 解读_第1张图片

using Unity.Entities;
using UnityEngine;

public class CannonBallAuthoring : MonoBehaviour
{

}

class CannonBallBaker : Baker<CannonBallAuthoring>
{
    public override void Bake(CannonBallAuthoring authoring)
    {
        //默认情况下,组件是零初始化的。
        //所以在本例中,CannonBallComponent中的Speed字段将是float3.zero。
        AddComponent<CannonBallComponent>();
    }
}

(1) 访问 Baker 中的数据 Accessing data in a Baker

增量烘焙需要 Baker’s 跟踪他们读取的所有数据。Baker 创作组件的字段会自动跟踪,但 Baker 读取的其他数据必须通过 Baker 方法添加到其依赖项列表中:

Baker 方法 描述
GetComponent() 访问子场景中任何游戏对象的任何组件。
DependsOn() 跟踪此 Baker 的资产。
GetEntity() 返回在子场景中烘焙或从预制件烘焙的实体的 ID。(实体尚未完全烘焙,因此您不应尝试读取或修改实体的组件。)

(2) 加载和卸载实体场景 Loading and unloading entity scenes

出于流式传输的目的,场景的实体被分成由索引号标识的部分。实体属于哪个部分由其SceneSection共享组件指定。默认情况下,实体属于第 0 部分,但这可以通过SceneSection在烘焙过程中进行设置来更改。

TIP : 在烘焙过程中,子场景中的实体只能引用相同部分或部分 0 的其他实体(这是一种特殊情况,因为部分 0 总是在其他部分之前加载,并且只有在场景本身被卸载时才被卸载)。

当一个场景被加载时,它由一个实体表示,该实体具有关于场景的元数据,并且它的每个部分也由一个实体表示。通过操纵其实体的RequestSceneLoaded组件来加载和卸载单个部分:当该组件更改时, 会做出响应SceneSectionStreamingSystem
SceneSystemGroup包含用于加载和卸载实体场景的SceneSystem静态方法:

SceneSystem 方法 描述
LoadSceneAsync() 开始加载场景。返回表示加载场景的实体。
LoadPrefabAsync() 开始加载预制件。返回引用加载预制件的实体。
UnloadScene() 销毁已加载场景的所有实体。
IsSceneLoaded() 如果加载了场景,则返回 true。
IsSectionLoaded() 如果加载了一个部分,则返回 true。
GetSceneGUID() 返回表示场景资产的 GUID(由其文件路径指定)。
GetScenePath() 返回场景资产的路径(由其 GUID 指定)。
GetSceneEntity() 返回表示场景的实体(由其 GUID 指定)。

TIP : Entity scenesection loading始终是异步的,无法保证请求后多久加载完数据。在大多数情况下,代码应该检查是否存在从场景加载的特定数据,而不是检查场景本身的加载状态。这种方法避免了将代码绑定到特定场景:如果数据被移动到不同的场景、从网络下载或程序生成,代码仍然可以不加修改地工作。

8.其他实体功能 Additional Entities features

总结

慢慢补充

你可能感兴趣的:(ECS,Unity,unity,c#,游戏引擎,ECS,DOTS)