首页 > 编程语言 >Unity DOTS系列之Aspect核心机制分析

Unity DOTS系列之Aspect核心机制分析

时间:2023-10-27 14:56:03浏览次数:34  
标签:DOTS Entity Unity 引用 Aspect 组件 entity MyAspect

  最近DOTS发布了正式的版本, 我们来分享一下DOTS里面Aspect机制,方便大家上手学习掌握Unity DOTS开发。

Aspect 机制概述

当我们使用ECS开发的时候,编写某个功能可能需要某个entity的一些组件,如果我们一个个组件的查询出来,可能参数会写很长。如果我们编写某个功能的时候,需要entity的一些组件的引用,我们如何高效的来获得呢?Unity DOTS引入了Aspect机制。

Aspect是一个特殊的数据结构,可以把它理解为是entity中一些组件的引用Wrapper”包装盒”,把entity中的一些组件的引用包含在一起。方便在System中通过这个Aspect来获取entity当中的组件的引用,高效方便的访问entity中的一些组件数据。定义一个Aspect, 需要继承自Iaspect Interface, Aspect里面的成员可以包含以下的内容:

Entity类型的引用;

RefRW<T> 与RefRO<T>组件数据的引用;

EnabledRefRW与EnabledRefRO的Enable Component组件数据的引用;

DynamicBuffer<T> 类型数据buffer;

shared component 类型的组件的引用;

      其它的Aspect类型;

 

Aspect定义与使用

定义一个Aspect,需要定义一个readonly的partial结构体并继承自接口类IAspect。

using Unity.Entities;

readonly partial struct MyAspect : IAspect

{

// Your Aspect code 

}

结构体里面的字段可以使用上面字段所规定的类型, 我们还可以把某个字段通过attribute设置为[Optional]。这样这个字段在entity里面就不是必须的,如果某个entity类没有这个可选字段,也能生成对应的Aspect。如果想要DynamicBuffer字段为只读,可以定义attibute [ReadOnly]。RefRO修饰的组件是只读的,RefRW修饰的组件可读写。

在System中我们要基于定义好的Aspect类型来操作entity中的组件数据,我们可以为Entity生成一个Aspect对象。通过API:SystemAPI.GetAspect<TASpect>来获取entity对应的Aspect对象。

// Throws if the entity is missing any of // the required components of MyAspect. MyAspect asp = SystemAPI.GetAspect<MyAspect>(myEntity);

如果这个entity类型无法生成对应的Aspect,那么asp就会返回null。当我们在System中需要迭代所有Entity的某种Aspect,可以使用API:

SystemAPI.Query。参考代码如下:

#region aspect-example

    struct CannonBall : IComponentData

    {

        public float3 Speed;

    }

 

    // Aspects must be declared as a readonly partial struct

    readonly partial struct CannonBallAspect : IAspect

    {

        // An Entity field in an Aspect gives access to the Entity itself.

        // This is required for registering commands in an EntityCommandBuffer for example.

        public readonly Entity Self;

 

        // Aspects can contain other aspects.

 

        // A RefRW field provides read write access to a component. If the aspect is taken as an "in"

        // parameter, the field behaves as if it was a RefRO and throws exceptions on write attempts.

        readonly RefRW<LocalTransform> Transform;

        readonly RefRW<CannonBall> CannonBall;

 

        // Properties like this aren't mandatory. The Transform field can be public instead.

        // But they improve readability by avoiding chains of "aspect.aspect.aspect.component.value.value".

        public float3 Position

        {

            get => Transform.ValueRO.Position;

            set => Transform.ValueRW.Position = value;

        }

 

        public float3 Speed

        {

            get => CannonBall.ValueRO.Speed;

            set => CannonBall.ValueRW.Speed = value;

        }

    }

#endregion

    #region aspect-iterate

    public partial struct MySystem : ISystem

    {

        public void OnUpdate(ref SystemState state)

        {

            foreach (var cannonball in SystemAPI.Query<CannonBallAspect>())

            {

                // use cannonball aspect here

            }

        }

    }

    #endregion

上面代码中定义了一个struct CannonBall 的ComponentData, 定义了一个CannonBallAspect,包含了entity本身引用,以及所需要的其它组件的引用(字段里面还可以基于get/set)。System中通过查询当前World里面所有含有CannonBallAspect对象的entity,然后统一处理它们。

Aspect的代码自动生成

不同类型的Entity可能有同一个类型的Aspect,那么Unity DOTS如何来处理呢?例如Entity类型A与Entity类型B,都有Aspect所定义的组件与引用,那么系统如何把A类型的Entity与B类型的Entity都生成它对应的Aspcet对象呢?那么这个时候就需要通过扫描所有的代码,来自动生成相关的代码自动生成对应的伪代码如下:

MyAspect  CreateAspectWithEntityA(entity实例) {

     Var myAspect = new MyAspect();

把A类entity实例对应的ArchType的ComponentData块的引用,生成一个MyAspect实例。

    Return myAspect;

}

MyAspect  CreateAspectWithEntityB(entity实例) {

     Var myAspect = new MyAspect();

把B类entity实例对应的ArchType的ComponentData块的引用,生成一个MyAspect实例。

    Return myAspect;

}

entity是否具有某种Aspcet类型的Aspect,也会被快速的生成出来,这样再查询的时候都可以提升查询的速度。具体可以参考相关源码。

标签:DOTS,Entity,Unity,引用,Aspect,组件,entity,MyAspect
From: https://www.cnblogs.com/rainy1unity/p/17792368.html

相关文章

  • 循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(6) -- 窗口控
    在我们窗口新增、编辑状态下的时候,我们往往会根据是否修改过的痕迹-也就是脏数据状态进行跟踪,如果用户发生了数据修改,我们在用户退出窗口的时候,提供用户是否丢弃修改还是继续编辑,这样在一些重要录入时的时候,可以避免用户不小心关掉窗口,导致窗口的数据要重新录入的尴尬场景。本篇随......
  • 循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(4) -- 实现Da
    在我们设计软件的很多地方,都看到需要对表格数据进行导入和导出的操作,主要是方便客户进行快速的数据处理和分享的功能,本篇随笔介绍基于WPF实现DataGrid数据的导入和导出操作。1、系统界面设计在我们实现数据的导入导出功能之前,我们在主界面需要提供给客户相关的操作按钮,如下界面所示......
  • 循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(5) -- 树列表
    在我们展示一些参考信息的时候,有所会用树形列表来展示结构信息,如对于有父子关系的多层级部门机构,以及一些常用如字典大类节点,也都可以利用树形列表的方式进行展示,本篇随笔介绍基于WPF的方式,使用TreeView来洗实现结构信息的展示,以及对它的菜单进行的设置、过滤查询等功能的实现逻辑......
  • Unity ECS内存分配器原理详解
    ECS为什么会高效,性能好,Entity的内存布局与分配就是非常重要的部分,今天我们一起来分析一下UnityECS架构里面如何来做高效的内存分配器。这种思路也可以给我们做内存分配提供很好的一个思路。1:ECS 里面基本的一些概念UnityECS框架里面有几个重要的概念:Entity,ComponentD......
  • Unity RVO动态避障技术方案介绍
    我们在开发游戏的时候经常会遇到这样的问题,当我们寻路的时候,其它人也在寻路,如何避免不从其它人的位置穿过。这个叫做动态避障,目前主流的解决方案就是RVO。本节我们来介绍一些Unity实现RVO的相关资料,后续在详细的讲解ROV算法的原理。先給大家介绍一个RVO2Library的项目,这个项......
  • Unity从AssetBundle中加载特效显示不全的问题
    环境:Unity2021.3.25f1 最近做的项目中经常会出现通过Bundle加载的ParticleSystem显示不全的问题,查阅Unity官方的文档是这样说明的:Meshesmustberead/writeenabledtoworkonthe ParticleSystem.IfyouassignthemintheEditor,Unityhandlesthisforyou.Bu......
  • Unity anchoredPosition转localPosition
    参考https://zhuanlan.zhihu.com/p/119442308在已经有结果的情况下,先捋一下unity对相关字段的注释就能得出很多公式(rectMinPos表示左下角在父节点坐标系中的位置,其他以"Pos"结尾的字段同理)pivot:ThenormalizedpositioninthisRectTransformthatitrotatesaround.......
  • Unity Addressable资源管理方案实战详解
    Unity推出了全新的Addressable的资源管理方案, 全网一夜间觉得不用Addressable感觉自己的资源管理方案会低一个档次,本节我们将详细的分析Addressable资源管理系统。本节主要从以下3个点来进行分析:(1) Addressable的本质是什么?AssetsBundle是否过时了?(2) Assetsbundle使用实......
  • 在使用 Unity 2022 打包安卓项目时,遇到 gradle 无法访问或下载超级慢最终超时出错的问
    一般表现是打包最后一步会等待超长时间,最后报错,错误信息:PickedupJAVA_TOOL_OPTIONS:-Dfile.encoding=UTF-8FAILURE:Buildfailedwithanexception.*Whatwentwrong:Aproblemoccurredconfiguringrootproject'Gradle'.>Couldnotresolveallartifactsfor......
  • Unity Shader入门
    ShaderLab首先我们创建一个URP工程,然后复制这个地址里的shader。Unity中的shader以ShaderLab的格式编写。下面是上面地址复制的ShaderObject//ShaderLab代码以Shader声明开始。这个路径决定了Material面板中UnityShader的名字和位置。Shader.Find也会使用这个路径Shader"......