ECS官方案例7. SpawnAndRemove

29 篇文章 3 订阅
31 篇文章 2 订阅

官方案例解析7

开始之前的准备工作:

0下载Unity编辑器(2019.1.0f1 or 更新的版本),if(已经下载了)continue;
1下载官方案例,打开Git Shell输入:
git clone https://github.com/Unity-Technologies/EntityComponentSystemSamples.git --recurse
or 点击Unity官方ECS示例下载代码
if(已经下载了)continue;
2用Unity Hub打开官方的项目:ECSSamples
3在Assets目录下找到HelloCube/7. SpawnAndRemove,并打开SpawnAndRemove场景

7. SpawnAndRemove

上一个案例演示了如何使用实体来生成别的实体,那么有生成,自然就有移除,下面一起来一探究竟吧:

  • Main Camera ……主摄像机
  • Directional Light……光源
  • Spawner……旋转方块生成器

打开Spawner生成器的Inspector窗口,我们发现这个案例是建议在第六个之上的,因为它也是先将自身转化成实体,再生成别的实体。所以我们忽略相同之处,看不同的地方,也就是移除操作了。

  • 实体和案例六几乎一致,所以对应的Entity脚本SpawnerAuthoring_SpawnAndRemove就跳过了。
  • Component组件脚本Spawner_SpawnAndRemove也跳过,该脚本存储的数据和案例六几乎一致。
  • 实体生成实体的System和案例六一致,所以SpawnerSystem_SpawnAndRemove跳过。

因此移除操作就只能在LifeTimeSystem(生命周期系统)实现了,且看:

/// <summary>
/// 生命周期,这里属于Component
/// </summary>
public struct LifeTime : IComponentData
{
    public float Value;
}

/// <summary>
/// 这个系统负责场景中所有实体的生命周期
/// 也可以将其改装来负责特定实体的生命周期,添加刷选条件Filter即可
/// </summary>
public class LifeTimeSystem : JobComponentSystem
{
    /// <summary>
    /// 实体命令缓存系统--阻塞
    /// </summary>
    EntityCommandBufferSystem m_Barrier;

    /// <summary>
    /// 将阻塞缓存起来
    /// </summary>
    protected override void OnCreate()
    {
        m_Barrier = World.GetOrCreateSystem<EndSimulationEntityCommandBufferSystem>();
    }

    [BurstCompile]//Burst加速编译器
    struct LifeTimeJob : IJobForEachWithEntity<LifeTime>
    {
        public float DeltaTime;

        [WriteOnly]//只写
        public EntityCommandBuffer.Concurrent CommandBuffer;

        /// <summary>
        /// 每帧执行,如果寿命 < 0 则摧毁实体
        /// </summary>
        /// <param name="entity">实体</param>
        /// <param name="jobIndex">任务索引</param>
        /// <param name="lifeTime">寿命</param>
        public void Execute(Entity entity, int jobIndex, ref LifeTime lifeTime)
        {
            lifeTime.Value -= DeltaTime;

            if (lifeTime.Value < 0.0f)
            {
                CommandBuffer.DestroyEntity(jobIndex, entity);
            }
        }
    }

    // OnUpdate runs on the main thread.
    /// <summary>
    /// 在主线程上每帧运行OnUpdate
    /// </summary>
    /// <param name="inputDependencies">输入依赖</param>
    /// <returns>任务</returns>
    protected override JobHandle OnUpdate(JobHandle inputDependencies)
    {
        var commandBuffer = m_Barrier.CreateCommandBuffer().ToConcurrent();

        var job = new LifeTimeJob
        {
            DeltaTime = Time.deltaTime,
            CommandBuffer = commandBuffer,

        }.Schedule(this, inputDependencies);

        m_Barrier.AddJobHandleForProducer(job);

        return job;
    }
}

其实这里的写法和我们OOP的写法差不多的,只是我们写在Update里面而已,也没有利用到Jobs和Burst。
没有什么好讲的地方,寿命到了就摧毁实体,再简单不过了。
这里我们可以看到另外一个ECS的特性,那就是多组件,多系统同时协作。这和我们原来的开发模式差不多,把需要的脚本挂在对象上面执行,多个脚本之间不会互相干涉(如果解耦的话)
这里是彻底解耦了的,你在生命周期系统上的更改,对旋转系统并没有影响。如果实体摧毁了,那么对应的组件也不存在了,对应的系统自然也会停止工作。这些蝴蝶效应应该是自发的,因为没有多余的代码来做这个工作。

小结

这个案例结合了案例二和案例六,因此都列出来了。
案例二:

ECSScriptsInterface
EntityRotationSpeedAuthoring_IJobForEachIConvertGameObjectToEntity
ComponentRotationSpeed_IJobForEachIComponentData
SystemRotationSpeedSystem_IJobForEachJobComponentSystem

案例六:

ECSScriptsInterface1Interface2
EntitySpawnerAuthoring_FromEntityIConvertGameObjectToEntityIDeclareReferencedPrefabs
ComponentSpawner_FromEntityIComponentData
SystemSpawnerSystem_FromEntityJobComponentSystem

案例七:

ECS 1ScriptsInterface1Interface2
Entity 1SpawnerAuthoring_SpawnAndRemoveIConvertGameObjectToEntityIDeclareReferencedPrefabs
Component1Spawner_SpawnAndRemoveIComponentData
System 1SpawnerSystem_SpawnAndRemoveJobComponentSystem
ECS 2ScriptsInterface1Interface2
Entity 2RotationSpeedAuthoring_SpawnAndRemoveIConvertGameObjectToEntity
Component2RotationSpeed_SpawnAndRemoveIComponentData
System 2RotationSpeedSystem_SpawnAndRemoveJobComponentSystem
ECS 3ScriptsInterface1Interface2
Entity 3RotationSpeedAuthoring_SpawnAndRemoveIConvertGameObjectToEntity
Component3LifeTimeIComponentData
System 3LifeTimeSystemJobComponentSystem

案例七并没有复用之前的ECS,而是独立创建了,其实脚本是大同小异的。通过对比,我们发现不同的组件和系统,可以共用同一个实体,就像表格ECS2和ECS3中所列出来的一样,它们共用了一个实体。
因此我查询了官方文档,发现ECS中实体+组件+系统三者之间并非缺一不可的关系,我发现实体是可有可无的,组件和系统因为实体而存在,却并不依赖它。这就是解耦,需要却并不依赖。
而实体却依赖组件,否则实体的数据没地方传递给系统,所以对于实体来说组件是必须的。
至于系统,实体可以不需要系统,组件也可以不需要系统,系统也可以当它们不存在,系统是完全解耦的。

DOTS 逻辑图表

Remove流程大体如下:

Value
lifeTime
Execute
New
Schedule
AddJobHandleForProducer
AddJobHandleForProducer
CreateCommandBuffer
DestroyEntity
Entities
LifeTime
LifeTimeSystem
LifeTimeJob
CommandBuffer
OnUpdate
主线程
EntityCommandBufferSystem

这个图画得有点乱,稍微废话解释一下,Entities把寿命通过LifeTime传给LifeTimeSystem来控制的,在生命周期系统中OnUpdate会在主线程上每帧执行发布新的LifeTimeJob任务,该任务会排到主线程的Schedule表上等待执行,每次的任务都会执行这样的判定,如果实体的寿命到了,那么就会把摧毁实体的命令缓存到CommandBuffer中。
那么CommandBuffer什么时候摧毁实体呢?CommandBuffer会在OnUpdate中传给LifeTimeJob任务,该任务会交给主线程。
执行的时机实际上由EntityCommandBufferSystem来掌控,通过AddJobHandleForProducer,最终的任务由阻塞(EntityCommandBufferSystem)和主线程协调。
大概是这样!
Spawn流程大体如下:

DeclareReferencedPrefabs
Convert
ConvertGameObjectHierarchy
Execute
Instantiate
SetComponent
Spawner
Prefab
SpawnerEntity
PrefabEntity
CommandBuffer
Entities
DOTS

DOTS系统:

Data
Schedule
OnUpdate
Entities
Component
System
Burst
Jobs
ForEach
System Burst Jobs Entities 你好!任务交给你快速编译一下? 编译好了,任务交给你安排执行? 不好意思,你们的旋转已经排上日程了! 全体都有,集合,向右看齐,向前看,转起来! 我们不想转,我们要放假! 又转起来了! 为什么会说“又”? 旋转,跳跃 我闭着眼…… System Burst Jobs Entities

这一篇主要是多线程的地方要注意一下线程安全问题,其他的都是之前梳理过的。

更新计划

Mon 12 Mon 19 Mon 26 1. ForEach 2. IJobForEach 3. IJobChunk 4. SubScene 5. SpawnFromMonoBehaviour 6. SpawnFromEntity 7. SpawnAndRemove 休息 修正更新计划 参加表哥婚礼 进阶:FixedTimestepWorkaround 进阶:BoidExample 进阶:SceneSwitcher 我是休息时间 资源整合 部署服务器 启动流程 登录流程 游戏主世界 待计划 待计划 待计划 待计划 待计划 我是休息时间 待计划 待计划 待计划 待计划 待计划 我是休息时间 读取Excel自动生成Entity 读取Excel自动生成Component 读取数据库自动生成Entity 读取数据库自动生成Component ESC LuaFrameWork Skynet DOTS 官方示例学习笔记 -----休息----- 基于ECS架构开发MMO学习笔记 LuaFrameWork学习笔记 -----休息----- 基于Skynet架构开发服务器学习笔记 制作代码自动生成工具 总结 基于Unity2019最新ECS架构开发MMO游戏笔记

作者的话

AltAlt

如果喜欢我的文章可以点赞支持一下,谢谢鼓励!如果有什么疑问可以给我留言,有错漏的地方请批评指证!
如果有技术难题需要讨论,可以加入开发者联盟:566189328(付费群)为您提供有限的技术支持,以及,心灵鸡汤!
当然,不需要技术支持也欢迎加入进来,随时可以请我喝咖啡、茶和果汁!( ̄┰ ̄*)

ECS系列目录

ECS官方示例1:ForEach

ECS官方案例2:IJobForEach

ECS官方案例3:IJobChunk

ECS官方案例4:SubScene

ECS官方案例5:SpawnFromMonoBehaviour

ECS官方案例6:SpawnFromEntity

ECS官方案例7:SpawnAndRemove

ECS进阶:FixedTimestepWorkaround

ECS进阶:Boids

ECS进阶:场景切换器

ECS进阶:MegaCity0

ECS进阶:MegaCity1

UnityMMO资源整合&服务器部署

UnityMMO选人流程

UnityMMO主世界

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
 一: 什么是ECS?       ECS是一种新的架构模式(当然是针对Unity本身来说),这是一个取代GameObject / Component 的模式。 其模式遵循组合优于继承原则,游戏内的每一个基本单元都是一个实体,每个实体又由一个或多个组件构成,每个组件仅仅包含代表其特性的数据(即在组件中没有任何方法)。系统便是来处理拥有一个或多个相同组件的实体集合的工具,其只拥有行为(即在系统中没有任何数据)。       ECS旨在比GameObject / MonoBehaviour更容易处理大量物体。ECS由于是面向数据的设计,所以很容易并行高速处理,以及与Unity开发的C#JobSystem/Burst Compiler一起工作,从而获取更高的项目运行性能。二:ECS总体发展历史       目前Unity公司由Mike Acton 大佬主持DOD(Data Oriented Design 面向数据设计)的全面改革与推进工作,目的是旨在进一步推进Unity系统本身与Unity项目的执行效率。    ECS总体发展:    A: 在Unity2018引入Entities之前,其实ECS框架早已经出现,但是ECS还是因为守望先锋采用了这个框架才被我们所熟知,后来Git上面出现了一个Entitas的插件可以直接用在Unity上面。Entitas-Unity(有多个语言的port版本,Entitas-Unity下统一称为Entitas) 是 Unity的一个ECS(Entity/Component/System)框架,是在github上面的一个开源项目。    B: 经过Unity公司的认可与改造,目前Unity2018.x 版本已经通过 Package Manager 提供了Unity版本的ECS插件,名称为:“Entities”。    C: Unity2019.x 版本,对“Entities”插件的API进行了进一步改造与完善,以更规范的API实现更加高效的与规范的编程模式。 三:ECS(一)轻松入门篇       本“ECS入门篇”旨在全面讲解ecs 的相关理论与简单Hello World 的编程模式,且通过Unity2018.x与Unity2019.x 两个不同API的编程模式,初步讲解ECS的编程规范与模式规范。        需要进一步学习ECS的小伙伴们,可以关注后续“ECS(二)小试牛刀”篇的进一步讲解。   《Unity ECS(二) 小试牛刀》https://edu.csdn.net/course/detail/27096 

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CloudHu1989

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值