Unity ECS学习笔记(3)IJobForEach

最近在学习unity的ecs框架,转载几篇写的比较好的文章帮助理解

原文日期 2019-12-5 避免误导未来使用正式版的开发者。

 

上一篇我们介绍了JobComponentSystem的基础用法,其实还有更多的用法,这次来介绍一下IJobForEach。

同样是用于筛选实体数据,执行一些逻辑操作,但是IJobForEach比起单纯地使用Entities.ForEach,在大部分情况下会有更优秀的性能。

1.IJobForEach

我们还是用之前的代码,但是,System类又要做一些改动。

这里提一下IComponentData,它就是一个空接口而已,作用只是表面自己是Component的身份,从而让System识别,非常纯粹的一个脚本。下面是这个案例的重点RotationSpeedSystem_IJobForEach:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

using Unity.Collections;

using Unity.Entities;

using Unity.Jobs;

using Unity.Mathematics;

using Unity.Transforms;

 

public class RotationSpeedSystem_ForEach : JobComponentSystem

{

    struct RotationSpeedJob : IJobForEach<Rotation, RotationSpeed_ForEach>

    {

        public float dt;

 

        public void Execute (ref Rotation rotation, [ReadOnly]ref RotationSpeed_ForEach rotationSpeed)

        {

            rotation.Value = math.mul(

                     math.normalize(rotation.Value),

                     quaternion.AxisAngle(math.up(), rotationSpeed.RadiansPerSecond * dt));

        }

    }

 

    protected override JobHandle OnUpdate (JobHandle inputDeps)

    {

        var job = new RotationSpeedJob() { dt = Time.DeltaTime };

        return job.Schedule(this, inputDeps);

    }

}

现在,OnUpdate里的逻辑都放到一个RotationSpeedJob里处理,然后通过调用这个Job的Schedule函数返回了一个JobHandle对象。和之前有点像,只不过是用一个称之为Job的东西把逻辑封装了。

RotationSpeedJob继承了IJobForEach接口,然后实现了Execute 函数。

Execute函数里做的事情和之前类似,修改实体的旋转值。

但是,这里有一点不一样,很重要的一点——Execute里没有使用Entities.ForEach了。

是的,每一个IJobForEach,只会处理一个实体的组件对象

并且,这些Job是可以并行处理的,这就是JobComponentSystem配合IJobForEach的优势——并行

我们来理一理:

a. JobComponentSystem的OnUpdate函数的主要逻辑移到了RotationSpeedJob中处理。

b. JobHandle对象需要通过IJobForEach来返回,实际上能返回JobHandle对象的不仅仅是IJobForEach这种接口,还有其他的,即,JobComponentSystem可以和若干种不同类型的Job配合。

c. IJobForEach接口需要实现Execute函数,函数参数指定了需要筛选的组件类型(可多个),以此来获得所需实体的组件对象,然后进行读写操作。指定的组件类型需要和接口声明的泛型对应,比如我们的接口声明的泛型是: IJobForEach<Rotation, RotationSpeed_ForEach>,和Execute函数的参数类型是对应的。

d. Execute函数只能对单个实体的组件(组件可以多个)进行操作。

e. IJobForEach,我们称之为Job,Job是可以并行执行的(多线程),因此能提升性能。

f. 请注意,Execute的参数可以带有ReadOnly特性,代表获取的这个类型的组件是只读的,不能进行写操作。

g. 如果某个Job对某个组件对象进行了写操作,则其他需要读取这个组件对象的Job无法并行执行,相当于锁住了。

关于JobSystem的知识,我现在还没有掌握,我会在后续的教程里和大家分享。

2.运行

好了,看看效果吧,除了System发生了改变,其他内容没变,大家修改了System类后,运行程序,结果是是一样的。

3.要注意的地方,重要!

利用IJobForEach时,系统会自动并行处理,但是,它只会按照块(Chunk)来并行处理。

什么是块(Chunk)?因为这是一个很重要的概念,我会在下一篇单独讲(重要,但理解起来很简单)。

虽然现在大家还没有块的概念,但是可以先注意一下。

如果我们的实体数量很少,筛选出来的实体刚好都在一个块里。

那么,IJobForEach其实是没有帮助的,因为它是按照块为单位进行并行处理的,只有一个块的话,也就不存在并行了。

大家看看下一篇关于块(Chunk)的解释,就能理解这段话的意思了。

 

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

 

下图出自同样不错的官方案例讲解:https://blog.csdn.net/qq_30137245/article/details/99049676

图解

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值