对不起。我吹牛逼的!!!
思路还是可以的,而且也实现出来了。不看损失!
整理一下最近做的工作,也是分享一下思路。
一 节点编辑器的起因
最近公司策划脑拍了一个万能事件编辑器,由策划配置副本的流程,程序进行组件的开发,这样的一套系统,想象很完美,但是对于程序来说有点难。
开始的时候不知道如何下手,因为要和现在游戏系统做兼容,并且还要有普适性,真他妈的烦,但是也得硬着头皮往下做。看了前一个项目失败的代码,逻辑复杂,开发难度大,理解困难,而且无法融合,在看了2天之后果断的放弃了,果然失败是有失败的道理,没有现成的可以用,那只能自己造轮子了。
组件式的开发我首先想到了ECS的模式,也就是unity那套开发模式,但是整个系统搭建和现有系统的融合有点问题,不好融合,模块之间的交互很成问题。果断放弃。
客户端丢过来了behavic的文档 ,腾讯的行为树,主要还是是用来做游戏AI,可以导出C++ 和C# 代码,真好,看了2天的文档,发现我们定制xml节点的问题比较麻烦,需要去定制,客户端觉得成本有点高,也是果断放弃。
二 设计要点
2.1 概念
下面分享下开发的这套节点编辑器是如何满足策划需求的,核心思想的图如下:
2.1.1、Context 管理着运行时数据,代表着一个副本
2.1.2、frameParamMap 是和外部系统沟通的桥梁,外部系统可以获取map,然后将数据放进去,流程管理器可以读取其中的参数,if节点,client节点使用。
2.1.3、runNodeList 当前帧需要运行的节点,会在下一帧执行
2.2 配置方式
配置文件
<?xml version="1.0" encoding="utf-8"?><ins><insId> 1001</insId><desc> 测试</desc><nodes><node><nodeId>1</nodeId><nodeType>begin</nodeType><nextNode>2</nextNode></node><node><nodeId>2</nodeId><nodeType>if</nodeType><leftOp>2</leftOp><op>2</op><rightOp>2</rightOp><nextNode>3</nextNode></node><node><nodeId>3</nodeId><nodeType>end</nodeType></node></nodes></ins>
2.3 伪代码
公司的代码无法拿出来,只能回忆一些核心代码了
2.3.1 节点类型定义
NodeType{// 开始节点BEGIN("begin",BeginCfg.class),// 结束节点END("end",BeginCfg.class),.....// xml中的节点名字private final String xmlNodeStr;// xml 配置的解析类private final Class<? extends AbsNodeCfg>}
2.3.2 配置对象:对xml 解析之后的对象,nodeMap 缓存所有的节点
NodeTree{// 所有的节点 node Id 和 配置对应Map<Long,AbsNodeCfg> nodeMap;// 开始节点BeginCfg beginCfg;// 结束节点EndCfg endCfg;}
2.3.3 抽象的配置解析类:所有xml节点解析类的父类
AbsNodeCfg<T extends AbsNode<?>> {// 节点idlong nodeId// 节点类型NodeType nodeType// 节点结束之后,流程的下面节点List<Long> nextNodeList// 节点描述String desc// 生成当前节点对应的执行节点public abstract T getRunNode(AbsContext context);}
配置节点类型 nodeType nodeId ,nextNode
AndCfg:逻辑 "且" ,子节点 subNode
BeginCfg:开始节点,全局唯一,可以开启多条线
ClientCfg:客户端节点 除去服务器关注的节点统一作为客户端节点,需要客户端做确认,子节点 confirmCount 确认次数
DelayCfg :延时节点 控制流程的执行时间,延时时间最少一帧,子节点 delayMs,subNode
EndCfg :结束节点 全局唯一,不需要nextNode,可以多个输入,在所有输入节点都到达的时候流程完成,Set<Long> prevNodeSet
IfCfg :条件节点 ,判断作用,leftOp,op rightOp
OrCfg 逻辑节点或, 子节点只能是If节点,子节点 subNode
RangeCfg:区域循环节点,单链,会对子节点进行循环,达到配置次数后进入nextNode,count subNode
其他的节点都为具体的业务节点。
2.3.4 抽象的执行节点:
AbsNode<T extends AbsNodeCfg>{ // 当前的节点的配置 T nodeCfg // 执行上下文 AbsContext context }
节点类型
AndNode 逻辑"且" ,子节点只能是If节点
BeginNode 开始节点,全局唯一,可以开启多条线
ClientNode 客户端节点 除去服务器关注的节点统一作为客户端节点,需要客户端做确认
DelayNode 延时节点 控制流程的执行时间,延时时间最少一帧
EndNode 结束节点 全局唯一,不需要nextNode,可以多个输入,在所有输入节点都到达的时候流程完成
IfNode 条件节点 ,判断作用,
OrNode 逻辑节点或, 子节点只能是If节点
RangeNode 区域循环节点,单链,会对子节点进行循环,达到配置次数后进入nextNode。
2.3.5 执行上下文:管理当前副本的所有数据,和其他模块交互的树
AbsContext 上下文管理器
runNodeList 运行中节点
NodeTree解析出的xml 节点配置
frameParamMap 和外部系统交换的map
isEnd 是否流程结束,如果设置ture 可以强制结束流程
ownerList 客户端的玩家id(主要做流程确认和发送消息通知)
delNodeList 每帧运行完成之后需要删除的节点,主要是完成的节点
2.3.6 InsMgr 副本管理器
服务器启动的时候
loadConfig() 加载服务器的xml配置
startSchedule 启动定时器
管理的数据
InsMgr{ // 所有的副本数据 Map<Long,InsContext> contextMap ; /** * 定时线程 */ private void startSchedule(){ ins_scheduler.scheduleAtFixRate(()->instance.update(),1000,100.TimeUnit.MILLISECONDS) } }
2.3.7 客户端和服务器的的通信消息
NodeStart 节点开始的时候通知客户端 proto: insId 副本id nodeId 节点id NodeEnd 节点结束的时候通知客户端 proto: insId 副本id nodeId 节点id FlowEnd 整个流程结束的时候通知客户端 proto: insId 副本id
2.3.8 其他
流程的缺省的超时时间,暂时设定为30分钟
节点的缺省超时时间,暂时设定为10分钟
异常的处理,暂时处理为流程异常则直接进入流程
三 总结
节点编辑器只是做了初版,流程通了,但是还没有真正的实践,整个的开发思路很简单,对节点进行编辑,客户端的节点客户端创建,比如播放特效,或者等待玩家操作等
服务端的节点服务端创建,单独的组件可以让策划选择,流程不需要重复开发,交互方便。
原文链接:https://blog.51cto.com/u_15064655/2887541
原创文章,作者:优速盾-小U,如若转载,请注明出处:https://www.cdnb.net/bbs/archives/6929