笨木头  2019-12-05 14:30     ECS入门     阅读(5107)     评论(0)
转载请注明,原文地址: http://www.benmutou.com/archives/2834
文章来源:笨木头与游戏开发
经过前面九篇教程,想必大家对ECS已经有了初步的了解,也已经能够用ECS这种模式写点简单的游戏了。

比如,做一个不断旋转的物体。

又比如,做两个不断旋转的物体。

又再比如,做1000个不断旋转的物体。

 

按照这种思路,我们已经会做无数个游戏了。(旁白:像开水一样,滚!)

 

你看,旁白又激动了,我不过是开个玩笑而已。

实际上,这次我要给大家写一个更有意思的游戏——让一个物体在3秒后消失!(旁白:这不叫游戏!)

1.IJobForEachWithEntityIJobForEach

为了实现这个功能,我们顺便就引出了另外一种筛选实体的方式——IJobForEachWithEntity。

 

我们之前已经介绍过IJobForEach了([Unity ECS 入门]4.筛选实体数据的方式3——IJobForEach),这次的IJobForEachWithEntity和之前的差不多,只是有一个小区别。

 

IJobForEach只能筛选出实体的组件,即,只能对组件进行读写操作。

IJobForEachWithEntity不仅能筛选出组件,还能筛选出实体,即,可以对组件和实体进行操作。

 

由于我们这次的例子是要删除物体的,所以必须把实体对象也筛选出来,否则无法执行删除操作。

 

注意,IJobForEachWithEntity为什么要放在这个后面讲呢?因为它涉及到了前面的很多知识,如果大家没有弄懂前面的Job、EntityCommandBuffer等知识,建议重复多看几遍,然后再接着往下看。

2.组件

为了演示这个例子,我们还是要创建一个组件,简单起见,我们用最开始的方式:
using Unity.Entities;

[GenerateAuthoringComponent] public struct LifeTimeComponent : IComponentData { public float LifeTime; }
 

3.实体

我们新建一个Cube,然后把LifeTimeComponent组件和ConvertToEntity挂上去:

4.系统

重点来了,我们来看看System的代码:
using Unity.Entities;
using Unity.Jobs;

public class LifeTimeSystem : JobComponentSystem { EndSimulationEntityCommandBufferSystem m_EntityCommandBufferSystem;

protected override void OnCreate () { m_EntityCommandBufferSystem = World.GetOrCreateSystem<EndSimulationEntityCommandBufferSystem>(); }

struct LifeTimeJob : IJobForEachWithEntity<LifeTimeComponent> { public float DeltaTime; public EntityCommandBuffer.Concurrent CommandBuffer;

public void Execute (Entity entity, int index, ref LifeTimeComponent lifeTimeComponent) { lifeTimeComponent.LifeTime -= DeltaTime;

if (lifeTimeComponent.LifeTime < 0) { CommandBuffer.DestroyEntity(index, entity); } } }

protected override JobHandle OnUpdate (JobHandle inputDeps) { var commandBuffer = m_EntityCommandBufferSystem.CreateCommandBuffer().ToConcurrent();

var job = new LifeTimeJob { DeltaTime = Time.DeltaTime, CommandBuffer = commandBuffer, }.Schedule(this, inputDeps);

m_EntityCommandBufferSystem.AddJobHandleForProducer(job);

return job; } }
 

虽然代码看起来很复杂,实际上都是我们熟悉的东西,比如JobComponent和EntityCommandBufferSystem。

唯一要关注的就是LifeTimeJob这个结构体:



这次我们使用了IJobForEachWithEntity接口,其实和IJobForEach的用法基本一致,只不过,我们在Execute函数的参数里可以获得Entity对象。

 

于是,我们判断实体的LifeTimeComponent的LifeTime是否小于0,是的话,则销毁实体。

当然,我们是通过EntityCommandBuffer来销毁实体的,因为在Job里是不能直接销毁实体的(参考[Unity ECS入门]9.如何回到主线程搞事情——EntityCommandBufferSystem)。

 

好,大家运行一下,Cube会在3秒后消失。

 

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

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

0 条评论
发表评论
粤ICP备16043700号

本博客基于 BlazorAnt Design Blazor 开发