Generator函数在流程掌握中的运用

扯蛋

做了两年的Nodejs全栈开辟,不知道为何跑来做游戏呢(大概是厦门nodejs不好找事情吧)。用的是网易的pomelo的游戏框架。现接办了一个棋牌游戏:二十一点,不懂的划定规矩的能够自行百度。
《Generator函数在流程掌握中的运用》

二十一点游戏流程图

《Generator函数在流程掌握中的运用》

近况

接办了平台其他相干游戏的代码,流程掌握互相交织,不轻易明白、难以保护。(多是刚做游戏的缘由,假如你们有什么更简朴的流程掌握要领,迎接分享)。我下意识的就想到了Generator函数的特征,以为用着这里异常轻易(之前一向以为这是个异步流程掌握中过分性子的要领,而且须要合营co才自动实行,所以基础没现实用过,koa不算…)

Js Generator函数完成流程掌握的长处

1、易于明白、便于开辟、轻易保护(看到Generator函数如同看到了流程图)
2、开辟思路清晰(每一个阶段(函数)只须要关注本身的营业逻辑,完成直接下一步,而不必管下一步要做什么操纵)
3、不存在会遗忘消灭定时器的题目

简朴说下Generator的实行流程

1、Generator函数实行后会天生一个Iterator。(注重不要加new)(简朴说就是个有next要领的对象,实行一次返回一个值)
2、每次next的挪用,实行yield背面的语句并返回该语句实行的效果
3、每次只实行一个yield,背面的语句不会再实行、只要在实行下次next函数时才实行。(能够应用这点做定时器的清算事情,而且能够说基础不会遗忘)
4、yield* 能够将背面的变量(可迭代的变量,字符串、数组等)中的值一个一个的返回。实行一次返回个中的一个值

Js Generator函数圆满完成流程图代码(部份)

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();
        }
    }
    
    /**
     *  其他函数...
     */

}
    原文作者:YAOHAO
    原文地址: https://segmentfault.com/a/1190000017195986
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞