美文网首页前端社团
斗地主游戏文档

斗地主游戏文档

作者: Zoemings | 来源:发表于2016-11-23 11:26 被阅读42次

    1.体系结构图

    体系结构图.png

    2.逻辑流程图

    2.1简易流程图

    逻辑流程图.png

    2.2详细流程图

    详细逻辑流程图.png

    3.服务器-客户端通讯图

    sc通讯图.png

    4.数据结构

    4.1牌型

    Paste_Image.png
    • 一副牌,共54张,由左至右相应的index从0开始排开;
    • 牌型:
      单牌(ONE):任意一张单牌(3 < 4 <… < K< A < 2 < 小王<大王)。
      对子(TWO):任意两张点数相同的牌,如:66。
      三头(THREE):任意三张点数相同的牌,如666。
      连三(THREE_2): 二个连续三张牌,如:333444
      单顺(STRAIGHT): 任意五张或五张以上点数相连的牌,如:45678或78910JQK。不包括 2和双王。
      双顺(TWO_2): 三对或更多的连续对牌
      三顺(THREE_3): 三对或更多连续三张牌,如:333444555
      炸弹(FOUR):任意四张点数相同的牌,如:6666

    4.2牌型比较

    • 大小顺序:3,4,5,6,7,8,9,10,J,Q,K,A,2,大王,小王。
    • 根据相应的index转为对应大小的value,3-K分别对应3-13,A:14,2:15,小王:16 , 大王:17
    • 除炸弹以外,普通牌型不允许对压,相同牌型下比它大的能对压。

    4.3压牌逻辑

    压牌逻辑.png

    5.页面展示

    5.1开始游戏

    开始游戏.PNG

    5.2等待页面

    等待.PNG

    5.3发牌页面

    发牌页面.PNG

    6代码展示

    6.1页面渲染

    //等待页面
    var htmlWait = "<h3 class='waiting'><h2>Waiting....</h2><h5>正在为你寻找小伙伴</h5></div>";
    //发牌页面
    var htmlPoker="<div class='choose'><div class='oppo-usr'></div><div class='oppo-pokers'></div></div><div class='display'></div><div class='choose'><div class='user'><div class='usr'></div><button class='abandon'></button></div><div class='pokers'></div> <div class='button'> <button class='cancel'></button> <button class='no'></button> <button class='confirm'></button> </div></div>";
    //登录页面
    var htmlStart="<div class='menu'><button type='button' id='login'></button></div>";
    //忙碌页面
    var htmlCrowded="<h3 class='waiting'><h2>Cowded....</h2><h5>房间好挤呀,你暂时进不来</h5></div>";
    

    6.2结构定义

    • 用户对象
    //状态定义
    var INIT="INIT";//初始化
    var WAITING="WAITING";//等待
    var DISCARD="DISCARD";//发牌
    var GAMEOVER="GAMEOVER";//游戏结束
    var pkObj = {
        data:{
            status:INIT,
            count:27,
            pokers:[]
        },
        from:id,
        to: fid,
        success:0,
        init:function (){
            if(pkObj.data.status===INIT){
                $("#login").click(doInit);
            }
            socketInit();
        }
    };
    
    • 牌对象
    var ONE = "ONE";
    var TWO = "TWO";
    var TWO_2 = "TWO_2";
    var THREE = "THREE";
    var THREE_2 = "THREE_2";
    var THREE_3 = "THREE_3";
    var FOUR = "FOUR";
    var STRAIGHT = "STRAIGHT";
    var ERROR = "ERROR";
    var KING = "KING";
     var poker= {
            type: type,                        //类型
            val: m,                            //大小
            length: pokerList.length  //张数
        };
    

    6.3消息模型

    • 服务器端
    io.on('connection', function(socket){
    //添加用户
    socket.on('add user', function (obj) {
        count++;
        //玩家一加入
         if(count===1){
            socket.join(obj.from);
            first=obj;
            first.authority=true;
         }
      //玩家二加入
        else if(count===2){
            socket.join(obj.from);
            second=obj;
            //洗牌
            var res=shuffle();
            first.data.pokers=res.poker1;
            second.data.pokers=res.poker2;
            first.to=second.from;
            second.to=first.from;
            //用户状态改变由WAITING到DISCARD发牌
            first.data.status=DISCARD;
            second.data.status=DISCARD;
            //发送发牌事件
            io.to(first.from).emit("start poker", first);
            io.to(second.from).emit("start poker", second);
            }
          //玩家三登入
            else{
                socket.join(obj.from);
                other=obj;
                 io.to(other.from).emit("crowded", other);
            }
      }
    //监听discard事件,当一方的牌数剩余为0,发送游戏结束信号
    socket.on('discard',function(data,sendMessage){
        if(data.data.count===0){
            io.to(data.from).emit("game over", 1);
            io.to(data.to).emit("game over",2 );
        }
        else{
          //当牌还有剩余时,向对手发送接收牌的信号
            io.to(data.to).emit("receive poker", sendMessage,data.data.count);
        }
      })
      //监听abandon事件,当有一方放弃游戏,发送游戏结束信号
      socket.on('abandon',function(data){
          io.to(data.from).emit("game over", 3);
          io.to(data.to).emit("game over",4);
        })
      })
    
    • 客户端
    function socketInit() {
        //发牌
        socket.on('start poker', function (data) {
            doDiscard(data);
        });
      //接收对方的牌
        socket.on('receive poker',function (data,count) {
            doReceive(data,count);
        });
      //拥挤
        socket.on('crowded',function () {
            doCrowded();
        });
      //游戏结束
        socket.on('game over',function (data) {
            //自己获胜
            if(data===1)
            {
                alert("you win!");
            }
          //对方获胜
            else if(data===2){
                alert("you lose!");
            }
            //自己放弃
            else if(data===3){
                alert("你放弃啦!");
                $(".wrapper").html("");
               //回到初始页面
                $(".wrapper").append(htmlStart);
                $("#login").click(doInit);
                pkObj.data.status=INIT;
            }
            else{
                alert("对方落荒而逃,恭喜你,不战而胜!");
            }
        })
    }  
                                
    

    6.4函数介绍

    服务端
    • 洗牌函数
    //洗牌
    function shuffle() {
      var pokers = new Array();
      for(var i = 0; i < 54; i++) {
        pokers[i]=i;
      }
      for (var i = 0; i < 54; i++) {
        var rd=parseInt(Math.random()*54);
        var b=pokers[i] ;
        pokers[i]= pokers[rd];
        pokers[rd]=b;
    }
       var poker1 = [];
       var poker2 = [];
       for(var i = 0; i < 54; i++) {
        if(i<27)
            poker1[i]=pokers[i];
         else{
            poker2[i-27]=pokers[i];
        }
       }
       sort(poker1);
       sort(poker2);
      result = {
        poker1: poker1,
        poker2: poker2
      };
      return result;
    }
    //排序
    function sort(pokers){
        var i=27;
        var temp;
        while (i > 0) {
        for (var j = 0; j < i - 1; j++) {
            if (((pokers[j]+11)%13> (pokers[j + 1]+11)%13)&&(pokers[j + 1]!==52||pokers[j + 1]!==53)) {
                temp = pokers[j];
                pokers[j] = pokers[j + 1];
                pokers[j + 1] = temp;}
            //小王
            if(pokers[j]===53){
                temp = pokers[j];
                pokers[j] = pokers[26];
                pokers[26] = temp;}
            //大王
            if(pokers[j]===52){
                temp = pokers[j];
                pokers[j] =pokers[j+1];
                pokers[j+1] = temp;}
                       }
                        i--;
             }
    }
    
    客户端
    • 发牌
    function doDiscard(data) {
        pkObj=data;
        $(".wrapper").html("");
        $(".wrapper").append(htmlPoker);
        //自己的牌
        yourPoker();
      //对方的牌
        myPoker(pkObj.data);
        $(".poker").click(function(){
            if($(this).hasClass("select")){
                $(this).removeClass("select");
                $(this).animate({top:"+=50px"});
            }
            else{
                $(this).addClass("select");
                $(this).animate({top:"-=50px"});
            }
        });
        //发牌
        $(".confirm").click(function(){
            //得到对方发来的牌
            var oppo_pokerList=new Array();
            if($(".display").children() !== null){
                $(".display").children().each(function(){
                    oppo_pokerList.push(parseInt($(this).attr("data-value")));});
            }
    
            //得到自己的牌
            var pokerList=new Array();
            for(var i=0;i<27;i++){
                var index=".choose .poker"+i;
                if($(index).hasClass('select')){
                    $(index).html();
                    pokerList.push(parseInt($(index).attr("data-value")));
                }
            }
            if(getPokerType(pokerList).type===ERROR){
                console.log("error");
                alert("发的牌不和标准");
                doCancel();
            }
            //对方没有牌即自己首发or对方放弃 自己没有牌即表示放弃
            else if(oppo_pokerList.length===0||pokerList.length===0){
                doConfirm(pkObj);
            }
             //自己牌合乎标准
             else if(comparePoker(pokerList,oppo_pokerList)) {
                doConfirm(pkObj);
            }
            else{
                alert("发的牌不和标准");
                doCancel();
            }
        });
        //取消
        $(".cancel").click(function(){
            console.log("cancel");
            doCancel();
        });
        //不出
        $(".no").click(function(){
            $(".display .poker").remove();
            var sendMessage=$(".display").html();
            socket.emit('discard', pkObj, sendMessage);
            doCancel();
        });
        //退出游戏
            $(".abandon").click(function(){
            socket.emit('abandon', pkObj);
        })
    }
    
    • 出牌
    function doConfirm(pkObj) {
        var count=0;
        $(".display .poker").remove();
        for(var i=0;i<27;i++){
            var index=".poker"+i;
            if($(index).hasClass('select')){
                $(index).html();
                $(".display").append($(index));
                count++;
            }
        }
        var sendMessage=$(".display").html();
        pkObj.data.count-=count;
        socket.emit('discard', pkObj, sendMessage);
        $(".confirm").hide();
        $(".no").hide();
    }
    
    • 放弃出牌
    function doCancel() {
        for(var i=0;i<13;i++){
            var index=".choose .poker"+i;
            if($(index).hasClass('select')){
                $(index).removeClass('select');
                $(index).animate({top:"+=50px"});
            }
        }
    }
    
    • 牌面大小转换
    function myPoker(data) {
        for(var i=0;i<27;i++){
            var x=data.pokers[i]%13*(-90);
            var y=parseInt(data.pokers[i]/13)*(-120);
            var left=x+"px";
            var top=y+"px";
            var count;
            //大王
            if(data.pokers[i]===52)
                count=17;
            //小王
            else if(data.pokers[i]===53)
                count=16;
            //A
            else if((data.pokers[i]+11)%13===11){
                count=14;
            }
            //2
            else if((data.pokers[i]+11)%13===12){
                count=15;
            }
            else {
                count=(data.pokers[i])%13+1;
            }
            var pokeri="poker"+i;
            var html = $("<button class='poker' data-value=''></button>").addClass(pokeri).attr("data-value", count);
            html.css({"background-position":left+" "+top});
            $(".pokers").append(html);
        }
    }
    
    • 接收牌
    function doReceive(data,after) {
        $(".confirm").show();
        $(".no").show();
         var before= $(".oppo-pokers").children().length;
        for(var i=before;i>after;i--){
            $(".oppo-pokers").children('.oppo-poker:last').remove();
        }
        if($(".display").children() != null){
            $(".display .poker").remove();
        }
        $(".display").append(data);
    }
    
    • 牌型状态机
    function typeState(type, n, m) {
        switch (type) {
            //单
            case ONE:
                if(n == m) {
                    type = TWO;
                } else if(n == m +1 && m == 16) {
                    type = KING;
                } else if(n == m + 1){
                    type = STRAIGHT;
                } else {
                    type = ERROR;
                }
                break;
            //对
            case TWO:
                if(n == m) {
                    type = THREE;
                } else if(n == m + 1){
                    type = TWO_2;
                } else {
                    type = ERROR;
                }
                break;
            case TWO_2:
                if(n == m) {
                    type = TWO;
                } else {
                    type = ERROR;
                }
                break;
            case THREE:
                if(n == m) {
                    type = FOUR;
                } else if(n == m + 1){
                    type = THREE_2;
                } else {
                    type = ERROR;
                }
                break;
            case THREE_2:
                if(n == m) {
                    type = THREE_3;
                } else {
                    type = ERROR;
                }
                break;
            case THREE_3:
                if(n == m) {
                    type = THREE;
                } else {
                    type = ERROR;
                }
                break;
            case STRAIGHT:
                if(n == m + 1) {
                    type = STRAIGHT;
                } else {
                    type = ERROR;
                }
                break;
            default:
                break
        }
        return type;
    }
    
    • 牌型获取
    function getPokerType(pokerList) {
        var type = ONE;
        var n, m;
        if(pokerList.length===1){
            m=pokerList[0];
        }
        else {
            for (var i = 0; i < pokerList.length; i++) {
                n = pokerList[i];
                m = pokerList[i + 1];
                type = typeState(type, n, m);
            }
            if(type == TWO_2 || type == THREE_2 || type == THREE_3 || (type == STRAIGHT && pokerList.length < 5)) {
                type = ERROR;
            }
        }
    
        var poker= {
            type: type,
            val: m,
            length: pokerList.length
        };
        return poker;
    }
    
    • 牌型大小比较
    function comparePoker(pokerList,oppo_pokerList) {
        var flag= false;
        var data1 = getPokerType(oppo_pokerList); //对方的牌类型
        var data2 = getPokerType(pokerList);  //我的牌类型
        if((data1.type == data2.type && (data1.length == data2.length) && pokerList[0] > oppo_pokerList[0]) || (data1.type != FOUR && data2.type == FOUR) || (data2.type == KING)) {
            flag= true;
        }
        //flag为true可出牌,否则不能出牌
        return flag;
    }
    

    相关文章

      网友评论

        本文标题:斗地主游戏文档

        本文链接:https://www.haomeiwen.com/subject/fawmpttx.html