[Unity ECS 入门]1.最简单的ECS程序

笨木头  2019-12-5 14:11   ECS入门   阅读(3,712)   19条评论

转载请注明,原文地址:http://www.benmutou.com/archives/2783
文章来源:笨木头与游戏开发

官方的第一个Demo是ForEach,演示了最基础的ECS游戏(旁白:等等,你管这叫做游戏?)

这一篇,我们抛开所有的理论知识,先让大家把一个最简单的ECS游戏唔,程序,跑起来。

1.安装Entities

首先,我们要安装Entities包和Hybrid Renderer包,这样才能支持ECS模式的开发。

打开Unity的Window->PackageManager菜单,搜一下Entities,记住,要把筛选条件改为All packages:



编写本系列教程时,我使用的Entities是0.3.0版本(预览版)。

安装完Entities后,接着安装Hybrid Renderer包,仍然是0.3.0。

注:在我写教程的时候,ECS相关的包只更新到0.2.0版本,后来更新到0.3.0版本,所以上面的截图版本号不准确。

2.概念(说好的抛开所有理论知识呢?)

ECS是什么?上一篇说过了:实体(Entity)、组件(Component)、系统(System)。

官方Demo的第一个例子是制作一个旋转的正方体,简单地展示了ECS的基本模式。

3.组件(Component

首先创建一个场景,然后新建一个结构体:

RotationSpeed_ForEach继承了IComponentData接口,这是ECS的组件接口。

4.系统(System

ECS的System是用于处理逻辑的,整个游戏中,可能会存在很多很多的System。

我们现在就来创建一个用于管理Cube旋转逻辑的System,创建一个新的类

继承了JobComponentSystem的类,就是System,看起来有点复杂(官方原本的Demo更复杂,我简化了),先别慌,照抄就是了。

5.创建实体

等等,为什么实体要放在最后?

因为实体有点特别,我们先创建一个Cube:


现在,把RotationSpeed_ForEach(组件)拖到Cube上:


唔,我还偷偷添加了一个【ConvertToEntity】组件,这个也是必须的。

这样的话,我们的Cube就会被自动转换为ECS的实体,并且这个实体拥有RotationSpeed_ForEach组件。

很神奇是不是?

将GameObject转换为ESC中的实体的方式不止一种,以后我们会慢慢讲到。

8.运行

不管任何原理,现在,运行程序,看看是不是有一个Cube在不断旋转。

好了,本篇到此结束,下一篇我们仍然使用同样的代码,然后把基础的概念给大家解释一下。

注意,本系列教程基于DOTS相关预览版的Package包,是预览版,不代表正式版的时候也适用。

转发本系列文章的朋友请注意,带上原文链接和原文日期,避免误导未来使用正式版的开发者。

19 评论

  1. RotationSpeed_ForEach拖不到cube上 can’t add script behaviour RotationSpeed_ForEach. The script needs to derive MonoBehaviour

    1. 这样的话,有两个问题需要确认一下:
      1. 你使用的Entities版本是0.3.0吗?
      2. RotationSpeed_ForEach是否添加了[GenerateAuthoringComponent]特性?

  2. Entities.ForEach((ref RotationSpeed_ForEach rotationSpeed, ref Rotation rotation) =>
    {
    var deltaTime = Time.DeltaTime;

    /* 旋转Cube,代码逻辑不用管,这里可以是其他任何逻辑 */
    rotation.Value = math.mul(math.normalize(rotation.Value),
    quaternion.AxisAngle(math.up(), rotationSpeed.RadiansPerSecond * deltaTime));
    });
    这里会报错哈,委托 未采用两个参数

    1. 我看了,估计你用的时候参数没有加ref?
      ForEach函数的参数是一个Action,这个Action对应了一个委托。

      ForEach函数实际上有很多个重载,其中一个是:
      public unsafe void ForEach (F_DD action) where T0 : struct, IComponentData where T1 : struct, IComponentData

      它的Action对应的委托是:
      public delegate void F_DD (ref T0 d0, ref T1 d1) where T0 : struct, IComponentData where T1 : struct, IComponentData;

      委托已经声明了要求带ref,并且其他委托里也不存在不带ref的声明,所以,如果不带ref,就会报你所说的那个错误了。

      1. 代码直接复制的,Rotation 不是Unity.Transforms.Rotation 吗,怎么会是struct或者IcomponentData呢

        1. Entities.ForEach((RotationSpeed_ForEach rotationSpeed, ref Rotation rotation) =>
          {
          var deltaTime = Time.DeltaTime;

          /* 旋转Cube,代码逻辑不用管,这里可以是其他任何逻辑 */
          rotation.Value = math.mul(math.normalize(rotation.Value),
          quaternion.AxisAngle(math.up(), rotationSpeed.RadiansPerSecond * deltaTime));
          });

          把第一个ref 去掉就可以

          1. Rotation也是继承了IComponentData接口的,这个可以直接在代码里点进去看到。
            至于你之前的那个问题,很奇怪,你进去ForEach函数看看?看看你现在调用的是哪一个ForEach。

            我文章中调用的是这个ForEach:
            public unsafe void ForEach (F_DD action) where T0 : struct, IComponentData where T1 : struct, IComponentData

    1. 不是的,后面还会提到其他创建ECS实体的方式,就我目前的学习来看,Unity的ECS提供了很多种选择,需要我们自己判断哪种方式在哪种场合更合适(也许未来会更加统一?)

发表评论

电子邮件地址不会被公开。 必填项已用*标注