作了两年的Nodejs全栈开发,不知道为何跑来作游戏呢(大概是厦门nodejs很差找工做吧)。用的是网易的pomelo的游戏框架。现接手了一个棋牌游戏:二十一点,不懂的规则的能够自行百度。javascript
接手了平台其余相关游戏的代码,流程控制相互交错,不易理解、难以维护。(多是刚作游戏的缘由,若是大家有什么更简单的流程控制方法,欢迎分享)。我下意识的就想到了Generator函数的特性,感受用着这里很是方便(之前一直以为这是个异步流程控制中过分性质的方法,而且须要配合co才能自动执行,因此基本没实际用过,koa不算...)java
一、易于理解、便于开发、容易维护(看到Generator函数犹如看到了流程图)
二、开发思路清晰(每一个阶段(函数)只须要关注本身的业务逻辑,完成直接下一步,而不用管下一步要作什么操做)
三、不存在会忘记清除定时器的问题node
一、Generator函数执行后会生成一个Iterator。(注意不要加new)(简单说就是个有next方法的对象,执行一次返回一个值)
二、每次next的调用,执行yield后面的语句并返回该语句执行的结果
三、每次只执行一个yield,后面的语句不会再执行、只有在执行下次next函数时才执行。(能够利用这点作定时器的清理工做,并且能够说基本不会忘记)
四、yield* 能够将后面的变量(可迭代的变量,字符串、数组等)中的值一个一个的返回。执行一次返回其中的一个值数组
class EsydProcess { constructor(room) { /** * ...其余变量 */ this.flow = this.flowGenerator(); } *['flowGenerator']() { yield this.betStage(); // 下注 this.betStageTimer && clearTimeout(this.betStageTimer);// 下注阶段完成后直接清除定时器。彻底不用担忧定时器没有被清理的状况 yield this.assignStage(); // 分牌 if (this.esydCard.getCardPoint(this.bankerCards[0]) === 1) { yield this.ensureStage(); // 保险 this.ensureStageTimer && clearTimeout(this.ensureStageTimer); if (this.esydCard.getCardType(this.bankerCards) !== CardTypes.BLACK_JACK) { yield* this.operateStage(); // 操做 } } else { yield* this.operateStage(); // 操做 } yield this.settleStage(); // 结算 } *['operateStage']() { // 通知进入玩家操做阶段 this.noticeChangeStage(esydConsts.gameStage.OPERATE_STAGE); let players = this.players; for (let uid in players) { let player = players[uid]; // 操做第一副牌 yield this.changeOperatingPlayer(player); player.getCurCardInfo().isStop = true; this.operateTimer && clearTimeout(this.operateTimer); if (player.isSperated) { // 若是有一副牌,操做第二副牌 player.curCardsIndex = 1; yield this.changeOperatingPlayer(player); player.getCurCardInfo().isStop = true; this.operateTimer && clearTimeout(this.operateTimer); } } yield this.bankerOperate(); // 庄家操做 } // 转到下个阶段 nextStage() { process.nextTick(() => { this.flow.next(); }); } // 开始游戏 start(seats) { /** * ... * */ // 第一次next,直接进入下注阶段。整个流程走完游戏结束 this.nextStage(); } betStage(){ // 进入下注阶段 this.noticeChangeStage(esydConsts.gameStage.BET_STAGE); /** * 其余操做 */ this.betStageTimer = setTimeout(() => { this.betStageTimer = null; // 超时,直接进入下一步。没有下注的玩家使用默认底注 this.nextStage(); }, esydConsts.stageTime.BET_STAGE); } assignStage(){ /** * ... * 分牌操做,完成直接下一步 */ this.nextStage(); } ensureStage(){ /** * ... * 各类操做,如通知客户端、开始超时定时器等。操做完后直接下一步就Ok了。只须要专一当前函数的功能,完成直接下一步 */ this.nextStage(); } // 监听用户下注操做 userBetOperateListener(uid){ /** * ... * 检查是否在下注阶段,不是不能下注、记录每一个玩家下注等 */ // 记录已下注的玩家 this.betedPlayers[uid] = true; if (Object.keys(this.betedPlayers).length === this.seatCount) { // 若是全部玩家都押注完毕, this.nextStage(); } } /** * 其余函数... */ }