糖尿病康复,内容丰富有趣,生活中的好帮手!
糖尿病康复 > 设计一个简易的引导任务框架(2) | 4.23粉丝赠书

设计一个简易的引导任务框架(2) | 4.23粉丝赠书

时间:2020-04-24 09:56:06

相关推荐

设计一个简易的引导任务框架(2) | 4.23粉丝赠书

今天是4.23世界读书日,公众号向支持的小伙伴们送出下面3本技术图书(三选一)!

参与方式:

本文点赞留言,必须超过20字,以及你想要的图书名字参与活动

积赞最多的前3名读者,将会获得赠书,三选一

活动截止时间:-4-24 20:00明天晚上8点

请获奖读者,通过公众号后台发送截图和您的快递联系方式领取赠书,24小时未来领取的视为放弃。

设计一个简易的引导任务框架

前文导读

上一篇分析了如何定位节点,如何显示节点遮罩,以及节点事件的确认,原理和方法是有了但要将整个逻辑链条串连起来,还需要下一翻功夫。

编写了一个简单的引导任务框架,想仅通过 JSON 配置的方式,完成上述步骤、任务的执行,实现一个配置式、可编程的引导框架,期望的是让非程序人员经过简单的学习,也能实现引导内容的制作,我们先看一个任务配置案例:

module.exports={name:'进入商店',debug:true,steps:[{desc:'点击主界面主页按钮',command:{cmd:'locator',args:'Home>main_btns>btn_home'},delayTime:1,},{desc:'点击主界面设置按钮',command:{cmd:'finger',args:'Home>main_btns>btn_setting'},},]};

下面是按此配置执行的效果:

引导框架—串联异步引导步骤

前面讲过,一个引导步骤中节点定位函数 godGuide.find() 是通过回调函数异步返回目标节点,用户对目标节点的点击确定也是异步的,因此任务中的每一个 step 都是异步的,为了方便对流程的异步控制,在这里使用了 async 这个三方库,如果你不习惯也可以更换为你熟悉的异步编程方式。

首先,我们看看任务配置中的 steps 异步串行处理:

run(){//串行处理steps数组中的每一项目元素async.eachSeries(this._task.steps,(step,cb)=>{//_processStep是一个异步函数,通过回调通知step处理完毕this._processStep(step,cb);},()=>{//this._task.steps中所有步骤处理完成,关闭引导this._task=null;//引导结束,隐藏遮罩、手指节点this._mask.node.active=false;if(this._finger){this._finger.active=false;}});}

async.eachSeries 是将 steps 数组中的元素依次迭代处理,具体的步骤处理我们封装在 引导类的 this._processStep 成员函数中,当 steps 数组中所有步骤执行完毕,async.eachSeries 最后一个回调函数被触发,退出引导状态。

引导步骤—步骤生命周期回调与步骤指令

上面是控制的是引导整体流程,我们再深入到 this._processStep 函数:

_processStep(step,callback){async.series({//步骤开始stepStart:(cb)=>{step.onStart?step.onStart(this,cb):cb();},//步骤指令stepCommand:(cb)=>{this.scheduleOnce(()=>{this._processStepCommand(step,()=>{cb();});},step.delayTime||0);},//步骤结束stepEnd:(cb)=>{step.onEnd?step.onEnd.call(this,cb):cb();}},callback);},

1. 步骤生命周期回调

async.series 帮助我们串行执行多个异步函数,这里为 step 设计了 onStart、onEnd 两个生命周期回调,分别在上面 stepStart 和 stepEnd 中执行,我们可以在这两个函数中做一些初始化、条件检查等异步等待操作,例如:

在 onStart 中等待玩家等级达到多少级,或某个事件发生;

在 onEnd 中等待服务器返回某个消息、操作后等待某个动画的完成,可以通过监听事件进行确认。

下面代码是模拟道具购买的引导实现,可以具体了解到 onStart、onEnd 的使用方法

{...steps:[{desc:'10级提示购买道具',//步骤开始onStart(callback){letobj={};//监听玩家等级变化cc.director.on('player-lv-up',(player)=>{//到达10级,显示商店界面if(player.lv>=10){cc.director.emit('show-shop');//移除事件监听cc.director.targetOff(obj);//执行回调,执行步骤指令callback();}},obj);},//步骤指令,定位商店界面中的购买按钮command:{cmd:'finger',args:'Shop>btnBuy'},//当玩家点击购买按钮,进入onEnd事件回调onEnd(callback){//使用网络代理模块,监听指定网络事件NetProxy.once('message-buy-item',(msg)=>{//事件发生,执行callback回调步骤结束callback();});}}]}

如果游戏比较简单 onStart 和 onEnd 不是必须的,通过 step 上 delayTime 属性可以做简单的延时控制,同样你也可以将游戏中增加事件、网络消息的广播编写成 step 配置中的 command 指令,以降低配置的复杂度。

2. 步骤指令

使用 step 指令,可以让步骤配置简化,特别是 UI 的点击引导。

步骤的异步处理过程中this._processStepCommand是关键,因为经常刚一进入某个场景时,可能需要定位的节点还未准备好(未创建或在动画运动过程中),我们又不想每个步骤都去写 onStart,因此步骤上提供了一个 delayTime 的属性,以延迟 step 指令的执行。

这里实现了两个指令:locatorfinger,他们的本质都是异步执行的函数 this._processStepCommand 中在对指令函数的调用,看下面代码:

letgodCommand=require('GodCommand');...//处理步骤中的指令_processStepCommand(cb){letcmd=godCommand[mand.cmd];if(cmd){this.log(`执行步骤【${step.desc}】指令:${mand.cmd}`);cmd(this,step,()=>{this.log(`步骤【${step.desc}】指令:${mand.cmd}执行完毕`);cb();});}else{cc.error(`执行步骤【${step.desc}】指令:${mand.cmd}不存在!`);}}

这里将指令函数编写在了名为 GodCommand.js 文件中,向指令函数传入当前引导对象step 配置对象,下面看定位指令的实现:

letGodCommand={//定位节点locator(godGuide,step,callback){//取出指令参数let{args}=mand;//调用引导类提供的定位节点godGuide.find(args,(node)=>{//设置目标节点,用于遮罩显示和点击放行godGuide._targetNode=node;//点击确认node.once(cc.Node.EventType.TOUCH_END,()=>{cc.log('节点被点击');//调用callback任务完成callback();});});},}

可以看出这里又是一系列的回调:

从 step 中获取参数,调用 godGuide.find 定位节点;

目标节点定位成功,使用 node.once 注册临时触摸监听;

当目标节点触摸事件发生,执行 locator 输入的 callback 回调,指令完成。

需要注意,任务完成时一定要执行 callback,不然无法继续流程。有了该指令函数,就可以在任务配置文件中使用了,使用方式:

{desc:'点击主界面主页按钮',command:{cmd:'locator',args:'Home>main_btns>btn_home'},delayTime:1,}

mand 中的 args 参数,由指令函数自行解释。

指令设计—实现手指动画指令

我们可以根据自己游戏的业务需求设计步骤指令,上一小节只是实现了节点的定位,并没有手指动画,在前面的基础上,我们为节点定位增加一个手指动画。

在 GodGuide 预制体上增加了一个手指预制体的属性,你可以根据自己的美术风格任意更换手指提示的表现,看下图:

手指预制体编辑界面:注意 GodFinger 预制体,锚点设置在了手指指尖位置。

手指动画提示可能比遮罩还常用,因此将手指动画的调用封装在了 GodGruid 组件代码中,提供了一个 fingerToNode 的函数,代码如下:

fingerToNode(node,cb){//手指节点不存在,直接回调if(!this._finger){cb();}this._finger.active=true;//转换节点位置letp=node.parent.convertToWorldSpaceAR(node.position)p=this.node.convertToNodeSpaceAR(p);//move动作letduration=p.sub(this._finger.position).mag()/cc.winSize.height;letmoveTo=cc.moveTo(duration,p);letcallFunc=cc.callFunc(()=>{cb();//完成回调})letsequnce=cc.sequence(moveTo,callFunc);this._finger.runAction(sequnce);}

手指动画很简单,就是一个 moveTo 的动作,需要注意的是节点坐标转换和动作完成回调,下面是 finger 指令的实现:

letGodCommand={//定位节点locator(godGuide,step,callback){...},//定位节点,显示一个手指动画finger(godGuide,step,callback){let{args}=mand;//定位节点godGuide.find(args,(node)=>{godGuide._targetNode=node;//手指动画godGuide.fingerToNode(node,()=>{//点击确认node.once(cc.Node.EventType.TOUCH_END,()=>{cc.log('节点被点击');//任务完成callback();});});});}};

其实没什么东西,就在前面 locator 函数的基础上增加了 godGuide.fingerToNode 的调用。

指令设计—文本提示

在引导流程中,更为常规的做法是手指动画+提示文本,读者可以思考一下如何设计一个text的指令。

我们以测试驱动的方式,先给出引导配置:

{...steps:[{desc:'文本提示'command:{cmd:'text',args:['欢迎来到xxx游戏',10001,10002]};},{desc:'点击主界面主页按钮',command:{cmd:'locator',args:'Home>main_btns>btn_home'},},]}

... ...

text 指令的参数是一个数组,可接受两种类型:

文本字符串:直接显示即可

语言配置 ID:有些游戏支持多国语言,在此直接配置语言 ID

同样,我们使用异步控制串行逐一输出 args 中的文本,当玩家点击屏幕时输出下一条文本,这里就不在帖出代码了。

小结

Step指令都是可扩展、可编程的, 在实际的项目中,我们可能需要根据具体业务需求,设计出更多的指令,方便引导任务的配置,例如:ScrollView 列表滑动指令、节点关闭指令、玩家等级变化指令、玩家过关指令等等,指令的设计主要是对事件的监听和异步流程的控制 。

下一次,我们再给大家介绍,关于自动化的实现。

GodGuide 框架已经上架 Cocos Store,而且最近开发者们又来上新了一大堆好玩、有趣、有价值的内容,点击【阅读原文】来看看吧!

4.23粉丝福利,快来参与吧!

参与方式:

本文点赞留言,必须超过20字,以及你想要的图书名字参与活动

积赞最多的前3名读者,将会获得赠书,三选一

活动截止时间:-4-24 20:00明天晚上8点

请获奖读者,通过公众号后台发送截图和您的快递联系方式领取赠书,24小时未来领取的视为放弃。

如果觉得《设计一个简易的引导任务框架(2) | 4.23粉丝赠书》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。