只有你足够强,别人才会和你讲道理。
文章: 280
浏览: 2,949,604
  • 博主:笨木头
  • 关注:Unity、Net Core、Blazor
  • 邮箱:musicvs@163.com
笨木头  2019-12-05 14:11     ECS入门     阅读(19006)     评论(31)
转载请注明,原文地址: 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

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

using Unity.Entities;

[GenerateAuthoringComponent]
public struct RotationSpeed_ForEach : IComponentData
{
    public float RadiansPerSecond;
}

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

 

4.系统(System

ECS的System是用于处理逻辑的,整个游戏中,可能会存在很多很多的System。 我们现在就来创建一个用于管理Cube旋转逻辑的System,创建一个新的类

using Unity.Entities;
using Unity.Jobs;
using Unity.Mathematics;
using Unity.Transforms;

// This system updates all entities in the scene with both a RotationSpeed_ForEach and Rotation component.

public class RotationSpeedSystem_ForEach : ComponentSystem
{
    protected override void OnUpdate ()
    {
        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));
        });
    }
}

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

5.创建实体

等等,为什么实体要放在最后? 因为实体有点特别,我们先创建一个Cube:

 

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

唔,我还偷偷添加了一个【ConvertToEntity】组件,这个也是必须的。 这样的话,我们的Cube就会被自动转换为ECS的实体,并且这个实体拥有RotationSpeed_ForEach组件。 很神奇是不是? 将GameObject转换为ESC中的实体的方式不止一种,以后我们会慢慢讲到。

8.运行

不管任何原理,现在,运行程序,看看是不是有一个Cube在不断旋转。 好了,本篇到此结束,下一篇我们仍然使用同样的代码,然后把基础的概念给大家解释一下。

 

注意,本系列教程基于DOTS相关预览版的Package包,是预览版,不代表正式版的时候也适用。 转发本系列文章的朋友请注意,带上原文链接和原文日期,避免误导未来使用正式版的开发者。

31 条评论
  • wx 2021-05-11 17:37:09

    我的是2020.3.7f1,ECS版本也是0.3.0的,照抄一遍你的代码一运行cube就自动消失了,控制台也没有报错,有点懵
    0回复
    • wx 2021-05-12 13:06:26

      解决了,我把unity官方的例子down下来重新写了一遍就好了,可能是unity版本不一致导致的吧。
      0回复
      • Hank 2021-10-14 22:05:39

        我也遇到了相似情况,还是得使用Unity官方例子吗
        0回复
      • hank 2021-10-15 13:48:18

        我找到问题所在了,cube自动消失是因为hybrid render没有更新到最新版本
        0回复
        • lxw 2021-12-14 17:16:21

          是怎么解决的呀
          0回复
          • lanslot 2022-03-25 23:44:16

            必须要用的渲染管线,URP或者HDRP都可以。内置渲染器一运行就会隐藏。
            0回复
  • 鱼头 2020-12-02 23:14:37

    你的网站好像被劫持了。第一次用谷歌浏览器从百度入口进你网站会跳到欺诈网站。我用公司电脑跟家里电脑第一次都重现了,再试就没有了。不知道是在那一层被劫持了
    0回复
    • 博主 笨木头 2020-12-03 08:13:50

      不会吧,这么吓人。我拿云服务器的浏览器访问我的博客,没有跳转。。。要是真的,那就麻烦了,真不知道怎么整
      0回复
      • 鱼头 2020-12-05 19:13:31

        我看了下历史记录网址是travelbandplane12.live 不过现在已经连不上了。
        大致内容是告诉你你是谷歌浏览器的幸运用户,让你回答几个浏览器使用的问题,然后告诉你你获得了购买特价iPhone的权利,最后跳转到了假的苹果网站购买页。(我居然操作了一遍)
        网站假的1B,来你网站的人估计不会上当的。
        0回复
        • 博主 笨木头 2020-12-07 13:53:12

          好的,谢谢告知,起码我能留个心眼了
          0回复
  • 棒棒糖 2020-07-04 14:36:29

    我的package manager 里没有Entities,怎么办
    0回复
    • 博主 笨木头 2020-07-04 16:27:52

      Advanced里的选项看看,有个开启是否显示preview包的选项,看看是不是没开?
      0回复
  • 啄木猫 2020-05-20 11:56:00

    ECS新手来啄木头了
    0回复
    • 博主 笨木头 2020-05-20 12:45:56

      教程用的Etities版本有点老了(尴尬),可能就是“仅供参考”
      0回复
  • fairy 2020-01-03 15:11:13

    为啥我的2018 Entities只到了0.0.24 没有0.2或0.3
    0回复
    • 博主 笨木头 2020-01-06 07:42:18

      我猜测是2018不支持新版本的Entities
      0回复
      • aladdin 2020-01-20 10:23:54

        木头胸用的是哪个版本的Unity
        0回复
        • 博主 笨木头 2020-01-20 10:47:41

          我用的是2020的,2019应该也是可以的,最好的办法是看看官方demo项目是哪个版本
          0回复
  • ls 2019-12-25 18:56:49

    RotationSpeed_ForEach拖不到cube上 can't add script behaviour RotationSpeed_ForEach. The script needs to derive MonoBehaviour
    0回复
    • 博主 笨木头 2019-12-26 08:18:21

      这样的话,有两个问题需要确认一下:
      1. 你使用的Entities版本是0.3.0吗?
      2. RotationSpeed_ForEach是否添加了[GenerateAuthoringComponent]特性?
      0回复
      • ls 2019-12-26 09:14:05

        好像是0.2.0,更新版本里面没有3.0
        0回复
        • 博主 笨木头 2019-12-26 14:04:40

          0.2.0也没问题的,所以,[GenerateAuthoringComponent]特性你也添加了吗?添加了应该没问题才对
          0回复
          • ls 2019-12-26 15:08:19

            没有这个特性,不过已经解决了 感谢
            0回复
  • 3493000 2019-12-16 15:33:08

    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));
    });
    这里会报错哈,委托 未采用两个参数
    0回复
    • 博主 笨木头 2019-12-16 19:17:01

      好的,我明天看看,现在代码不在身边
      0回复
    • 博主 笨木头 2019-12-17 08:10:26

      我看了,估计你用的时候参数没有加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,就会报你所说的那个错误了。
      0回复
      • 3493000 2019-12-17 09:20:42

        代码直接复制的,Rotation 不是Unity.Transforms.Rotation 吗,怎么会是struct或者IcomponentData呢
        0回复
        • 3493000 2019-12-17 11:12:39

          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 去掉就可以
          0回复
          • 博主 笨木头 2019-12-17 15:12:15

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

            我文章中调用的是这个ForEach:
            public unsafe void ForEach (F_DD action) where T0 : struct, IComponentData where T1 : struct, IComponentData
            0回复
  • sneaking 2019-12-13 20:02:44

    用ConvertToEntity把GameObject转换成Entity是纯的ECS实体创建方式吗?
    0回复
    • 博主 笨木头 2019-12-16 08:26:02

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

本博客基于 BlazorAnt Design Blazor 开发