Unity ECS学习笔记(一)

ECS架构概述

ECS术语

实体Entity:像容器一样

组件数据Component Data:要存储在实体中的数据(不包括处理)

组件系统ComponentSystem:处理

组Group:组件系统运行所需的ComponentData列表

Unity官版ECS主要特征如下:

  • 数据和行为分离
  • 在通常的Unity开发中,我们会将Monobehavior组件挂载到一个Gameobjec上,而ECS中,则将设计为将组建附加到Entity上
  • 使用一个池子(pool)来存放所有的Entity
  • 可以给Entity设定分组(group)
  • 通过matcher来获取指定的Entity

ECS与Unity的GameObject /Component相比,有一个稍微接近的地方。如果完全粗略地说明,则它与以下项目匹配。

Entity=GameObject

ComponentData =Component的字段

ComponentSystem =Component的Update方法

Group = 无

 

环境

需要环境如下:

  • Unity 2018及以上,理论上2017的最后几个版本也可以,主要是要支持.net 4.6
  • 安装ECS包

步骤

  • 下载最新版Unity,建议官方下载
  • 开Unity,新建一个项目:
  • 进入Unity后,设置.net版本:依次点击File - BuildSetting - PlayerSetting - Other Setting - Scripting Runtime Version 设置为.NET 4.x Equivalent,会提示重启,点Restart重启Unity即可。
  • 打开项目目录(即创建项目的文件夹),找到Packages目录,并找到里面的manifest.json文件

  • 打开manifest.json文件,并将以下内容复制进去,并保存:
{

"dependencies": {

"com.unity.entities": "0.0.12-preview.5"

},

"registry": "https://packages.unity.com",

"testables": [

"com.unity.collections",

"com.unity.entities",

"com.unity.jobs"

]

}
  • 在此进入Unity的环境时,会进行下载ECS包和导入,导入完成后,我们会发现顶部菜单栏多了Jobs项,

  • 菜单栏打开Window - Packages Manager 也可以看到Entities已经安装:

 

  • 例一:
  • 接着我们来写个让cube旋转的测试样例:
  • 新建一个Rotator.cs脚本

代码如下:

using UnityEngine;

public class Rotator : MonoBehaviour {

    public int speed;
}
  • 没错,这个脚本继承自monobehavior,但是,他就只有一个字段,即,只有数据
  • 再新建一个类,叫RotateSystem.cs,这个类我们让它继承ECS
using Unity.Entities;

public class RotateSystem : ComponentSystem

{

}
  • ComponentSystem来自Unity.Entities命名空间,所以,在开头需要进行引用。
  • 创建一个结构体,作为容器来存储数据:
struct Components

{

    public Rotator rotator;

    public Transform transform;

}
  • Rotator就是上面创建的数据类,同时这里还存了一个transform,因为我们需要使用transform的实例方法
  • 因为继承了ComponnetSystem,所以这个类还需要实现基类的一个OnUpdate方法:
protected override void OnUpdate()

{

}
  • 这个方法同monobehavior一样,也是每帧调用。
  • 在这个方法中,我们遍历下场景的所有Entity,使用GetEntities接口进行遍历即可
foreach (var item in GetEntities<Components>())

{

}
  • 然后就是对遍历出来的子项做一些行为操作:
foreach (var item in GetEntities<Components>())

{

    item.transform.Rotate(0f, item.rotator.speed * Time.deltaTime, 0f);

}
  • 到这里,代码算是告一段落了,我们需要在Unity中进行一些操作设置
  • 在Unity界面下的Hierrarchy窗口下右键创建一个Cube,然后挂载Rotator.cs脚本
var deltaTime = Time.deltaTime;

foreach (var item in GetEntities<Components>())

{

    item.transform.Rotate(0f, item.rotator.speed * deltaTime , 0f);

}

 

  • 再给cube添加一个GameObjectEntity脚本(ECS系统内置脚本,不需要你自己写)
  • 现在点击运行,并给cube身上的rotator脚本设置speed的值,cube就可以转起来了。
  • 你可以多复制几十或者几百个测试下效率。
  • 当然,上面那个遍历脚本还可以优化一下,就是将Time.delaTime缓存一下,而不是放到循环里去,
  • 最后我们可以通过Windows->Debug->Entity Debugger来查看下信息

例二:

创建一个Cube作为Player,点击Add Component添加GameObjectEntity脚本,然后编写InputComponent脚本,编写代码并添加的Cube上。

代码就这么简单,ECS中Component是数据容器,仅包含与Entity相关的值字段。

using UnityEngine;

public class InputComponent : MonoBehaviour {

    public float Horizontal;
    public float Vertical;
}

接下来编写移动的System,我们新建一个MovementSystem,用来做对移动行为的控制System

using Unity.Entities;

public class MovementSystem : ComponentSystem {

	private struct Components
    {
        public Transform Transform;
        public InputComponent InputComponent;
    }


	protected override void OnUpdate ()
    {
        var deltaTime = Time.deltaTime;
        var speed = 10.0f;

        //遍历所有的所有包含结构体中组件的Entity
       foreach(var e in GetEntities<Components>())
        {
            var vector = new Vector3(e.InputComponent.Horizontal, 0, e.InputComponent.Vertical);
            e.Transform.Translate(vector * deltaTime * speed);
        }
    }
}

然后是InputSystem,代码如下:

using Unity.Entities;

public class InputSystem : ComponentSystem
{
	private struct Data
    {
        //结构体长度,即数据数量
        public readonly int Length;
        //获取所有包含InputComponent的数组
        public ComponentArray<InputComponent> InputComponents;
    }

    //Unity会自动注入满足此字段的对象
        [Inject] Data data;

    protected override void OnUpdate()
    {
        var horizontal = Input.GetAxis("Horizontal");
        var vertical = Input.GetAxis("Vertical");

        for (int i = 0; i < data.Length; i++)
        {
            data.InputComponents[i].Horizontal = horizontal;
            data.InputComponents[i].Vertical = vertical;
        }
    }
}

我们可以通过Entity Debuger来查看下信息,可以看到InputComponent下成功找到Entity 0这个对象了,说明我们的注入是成功的。

按下上下左右按键,我们的方块成功移动起来了,可以看到使用ECS,我们Entity对象上仅仅只有包含数据的Component,而我们无需关心其他System是如何运作的,每个System只关心自己本身的实现就行了。

 

 

 

 

 

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Unity ECS(Entity Component System)是Unity引擎的一种编程范式,它是一种数据驱动的编程模型,它将游戏对象(Entity)分解为数据和行为两个部分,其中数据由组件(Component)来表示,行为则由系统(System)来实现。相对于传统的面向对象编程模型,ECS提供了更高效、更灵活的编程方式,可以有效地提高游戏的性能和扩展性。 下面是我学习Unity ECS时的笔记: ## Entity Entity是ECS中最基本的概念,它表示游戏对象。每个Entity由一个唯一的ID来标识,可以通过EntityManager来创建、销毁、查询和管理Entity。 ## Component Component是Entity的数据部分,用来描述Entity的属性和状态。每个Component包含一些数据成员和一些方法,用来操作这些数据成员。Component是以结构体(struct)的形式定义的,通常只包含数据成员,不包含方法。 ## System System是Entity的行为部分,用来实现游戏逻辑和操作Component。System可以访问和操作EntityManager和Component,但不能直接访问Entity。每个System包含一个或多个Component,表示它所处理的数据类型。System是以类(class)的形式定义的,通常包含一个Update方法,用来实现游戏逻辑。 ## Job Job是一种轻量级的线程,用于并行执行System中的任务。Job可以访问和操作Component,但不能直接访问Entity和EntityManager。Job通常是以结构体(struct)的形式定义的,不包含方法。 ## Archetype Archetype是Entity的集合,包含一组具有相同Component类型的Entity。Archetype可以用来优化数据的访问和处理,可以在不同的System之间共享。 ## Chunk Chunk是Archetype中的数据块,包含一组连续的Entity和它们的Component数据。Chunk可以用来优化内存的分配和访问,可以在Job中进行并行处理。 ## Buffer Buffer是一种Component类型,用来存储可变长度的数据,例如数组或列表。Buffer可以在System和Job中进行修改和访问。 以上是我学习Unity ECS时的笔记,希望对你有所帮助。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值