前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >UE5的Control Flows

UE5的Control Flows

作者头像
quabqi
发布2023-02-02 15:53:17
7550
发布2023-02-02 15:53:17
举报
文章被收录于专栏:Dissecting UnrealDissecting Unreal

在Gameplay开发过程中,常常会碰到一些流程非常复杂,由很多个子逻辑复合而成的业务,就比如最常见的客户端登录流程,可能要分这几步:要先走账号授权,访问平台SDK的API,等待回调取得对应token,再和游戏服务器建立连接,连接后将获取到的用户id和token发给游戏服务器,等待服务器校验成功后返回给客户端才算成功登录。中间会有好几个子步骤,每个步骤都可能是异步的回调。虽然流程看起来很线性,但当我们在实现时,会发现事情没这么简单。每一步都需要根据上一步的结果来决定下一步怎么做,过程中连接失败了怎么办,鉴权失败了怎么办,超时了怎么办?中间有非常多的异常逻辑要处理,最终的业务看似线性但实际是一个网。而且整个过程可能会因为策划需求变更,平台SDK更新,服务器重构等各种原因进行多次变更,每次修改流程,就要把业务的这张“网”重新编织一遍,“网”上的某个链路出现问题,就会导致整个系统出现瘫痪,无穷无尽的开发工作量就是这样出现的。经验丰富的开发者在写这些业务时,可能会考虑使用状态机,把这张网梳理成多个状态,在重构时只要调整状态机之间的关系即可,但业务在不符合状态机的运行模式时,强行套用可能会让业务变得更加抽象,当业务规模庞大时不但不能减轻业务开发人员的重构负担,反而会加重理解成本。

ControlFlows是UE5新增的一个插件,针对上述这种流程式的业务模型,封装了一套通用的类状态机但更简化的流程控制框架。就拿上述登录流程来说,如果使用ControlFlows这个插件来实现,可以让整个流程简化成几个子业务函数和一个整体的流程配置,当需要修改流程时不用改每一步的子业务函数,只修改对应的流程配置即可。插件本身的实现对引擎的新功能没有依赖,所以理论上手动移植到UE4上应该也会比较容易。

ControlFlow的使用

Lyra工程中的启动登录流程使用了ControlFlow,就以Lyra中的示例作为说明:

上图可以看到,首先创建一个ControlFlow的对象,然后调用QueueStep添加流程。整个登录流程分为了4步:

  1. 等待初始化
  2. 显示PressStart按钮
  3. 尝试加入请求的Session
  4. 显示主界面

每一步QueueStep后面都有一个函数作为参数。我们先看某一步的内部代码

可以看到内部,在业务执行完的时候,需要ContinueFlow,或者CancelFlow。这样就可以让多个步骤的Flow依次执行下去,或者中途结束。

其实这就是ControlFlows框架的全部了,就是这么简单。你可能会疑惑,使用ControlFlows和自己直接写一堆子业务的函数,并在每个子业务的回调函数内部调用下一个子业务有什么区别?其实本质是一样的,但使用ControlFlows有一个好处,就是当业务流程发生改变,但每一个子业务没有变化时,不用修改子业务本身,只需要修改下面这几行,可能简单调整一下顺序就搞定了。不用深入到每个子业务的回调中去调整下一个业务是什么,因为子业务内部启动下一个子业务的代码永远是ContinueFlow这个函数。

再说回QueueStep。看源码可以得知,QueueStep是一个模板函数,可以根据不同的参数特化成不同的实现,本质上类似Delegate的模式。这里直接看注释最清楚

可以看到QueueStep会根据参数情况,来决定调用QueueFunction,QueueWait,QueueControlFlow,QueueControlFlowBranch等函数,所以业务只需要使用一个QueueStep即可。

这里可以看到除了支持简单的任务外,还支持分支QueueBranch和循环QueueLoop。这两种模式都要求先提供一个判断函数来决定执行哪个分支或者循环是否结束,就像写if条件判断或者while循环一样,看源码内部有支持多线程的打算,但是没有实现,所以目前来说还只是单线程模式,和delegate一样,回调支持绑定UObject,所以建议只在GameThread上使用。

如下是分支的写法,创建两个分支,1和2,返回值就是决定执行哪个分支,这里写死了2,实际可以根据业务情况动态决定执行哪个branch

循环写法也类似,这里就不详细说明了。

有时候会遇到没法在QueueStep提供的函数内部决定是否ContinueFlow,或者无法在内部使用lambda回调。Lyra的做法是将参数SubFlow保存下来,在真正的回调结束后,用保存的SubFlow智能指针继续ContinueFlow

ControlFlow的创建,获取,销毁

可以看到默认要求填入OwningObject,这里支持两种对象,一种是UObject,一种是继承了SharedFromThis的智能指针。因为ControlFlow内部大量的Delegate,这样可以让ControlFlow在关联的对象生命周期内安全的运行。

每次执行ControlFlow不需要重新创建,直接复用原有的即可,只要FlowId相同。上面可以看到也支持FindOrCreate接口,FindOrCreate创建的Flow是Persistent的。而重复创建相同FlowId内部会报错,如果Flow创建时是Persistent的,即使Flow已经执行完成重复创建也会报错,这是需要注意的。

内部有4个全局的静态容器,保存了整个进程内所有的Flows,内部也会通过Ticker在游戏的每一帧检查执行完的Flow并删除。

ControlFlow本身也支持绑定一个FTrackedActivity,可以实时监控当前状态,也可以用于进度条展示等功能。比如我们在做资源加载时如果使用了ControlFlow,就可以额外使用FTrackedActivity来为当前UI提供相关的展示文字。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-01-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ControlFlow的使用
  • ControlFlow的创建,获取,销毁
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档