摘要:系統(tǒng)結(jié)構(gòu)系統(tǒng)考慮使用和實現(xiàn)服務(wù)器端邏輯,前端使用。邏輯流程主要邏輯包括用戶進入游戲等待對家進入游戲游戲過程結(jié)束統(tǒng)計這個過程。
1. 系統(tǒng)結(jié)構(gòu)
系統(tǒng)考慮使用Nodejs和SocketIo實現(xiàn)服務(wù)器端邏輯,前端使用HTML5。
1 . 主要邏輯包括用戶進入游戲、等待對家進入游戲、游戲過程、結(jié)束統(tǒng)計這4個過程。
2 . 游戲過程的邏輯具體如下
3 . 服務(wù)器-客戶端通訊邏輯如下
3. 客戶端界面設(shè)計1 . 登錄界面
2 . 發(fā)牌界面
4. 數(shù)據(jù)結(jié)構(gòu)4.1 牌型
為了便于計算,使用一維數(shù)組定義每張撲克的index,根據(jù)圖中順序,按從左到右以及從上到下遞增(即左上角的紅桃A為0,右上角的紅桃K為12,方塊A為13,以此類推)
>
4.2 出牌規(guī)則
牌的大小順序:大王,小王,2,A,K,Q,J,10,9,8,7,6,5,4,3。
牌形分為:單張、 一對、 三張、姐妹對(兩張三張都可以連接,且連接數(shù)量無限)、順子(數(shù)量無限制)、炸彈(不能4帶1):
除了炸彈以外,普通牌形不允許對壓,相同牌形只有比它大的才能出。
炸彈任何牌形都能出,炸彈的大小為:天王炸,2,A,K,Q,J,10,9,8,7,6,5,4,3。
4.3 比較大小
根據(jù)牌型用整數(shù)定義撲克的數(shù)值大小
從3到K對應(yīng)的value為2到12
A對應(yīng)13
2對應(yīng)14
大小王對應(yīng)16與15
5. 系統(tǒng)模塊設(shè)計5.1 出牌對象
var MODAL; $(init); function init() { new modal(); //綁定頁面上的出牌按鈕,根據(jù)當(dāng)前不同的狀態(tài)運行不同的函數(shù) $("body").on("click","#sendCards",statusMachine); } function statusMachine() {} var modal = function () { var ptrThis; var modalBox = { //出牌對象的數(shù)據(jù) default:{ //cards存儲服務(wù)器發(fā)送過來的撲克數(shù)組 cards:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37, 38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53], //當(dāng)前游戲的狀態(tài),有DISCARD(發(fā)牌),WATING(等待),GAMEOVER(游戲結(jié)束)三個狀態(tài) status:"", //myIndex為玩家所處于的座位的座位號 myIndex:0, //leftIndex為位于進行游戲的玩家左邊的玩家的座位號 leftIndex:0, rightIndex:0, //turn與座位號對應(yīng),turn表示由對應(yīng)的座位號玩家進行操作(例如發(fā)牌,放棄) turn:0, //若有兩位玩家放棄出牌,則第三位玩家必須出牌,用于標志新的出牌回合的開始 disCardTrue:false, //記錄前一位玩家所處的牌,用于實現(xiàn)壓牌邏輯 formercardsType:{} }, //$goal為待插入撲克的jquery對象,cardArray為撲克數(shù)組,isDelay為true則延遲插入(隔0.3s插入一張牌) placeCards:function ($goal,cardArray,isDelay) {}, //sort函數(shù)所用到的比較函數(shù),a,b都為撲克的index,將撲克按照value從大到小降序排列,value相同則按照花色排序 comp:function (a,b) {}, //變換當(dāng)前撲克牌的狀態(tài),未選取->選取,選取->未選取 toggleCard:function ($this) {}, //將服務(wù)器發(fā)送的無序數(shù)組按照一定規(guī)則進行排序 cardsSort:function (cards) {}, //將已被選中并發(fā)送的撲克牌從手牌中刪除 removeCards:function () {}, //判斷從服務(wù)器發(fā)送撲克牌數(shù)組是由誰發(fā)出的,調(diào)用placeCards函數(shù)插入撲克 //turn設(shè)置為下一位玩家,根據(jù)turn設(shè)置status //如果撲克牌已被出完,則根據(jù)最后一位出牌人來判斷當(dāng)前玩家是勝利還是失敗 justifyWhich:function (obj) {}, //收到來自服務(wù)器轉(zhuǎn)發(fā)的某一位玩家發(fā)送的投降信息 someOneTouXiang:function (seats) {}, //清空玩家發(fā)送的撲克 clearCards:function () {}, //繪制左右兩位玩家的界面,objLeft為左邊的玩家的信息,objRight同上 drawothers:function (objLeft,objRight) {}, //繪制玩家的界面,包含手牌,obj為相關(guān)信息 drawuser:function (obj) {}, //向目標jquery對象插入圖片,$this為目標jquery對象,obj為相關(guān)信息(例如圖片路徑) insertImg:function ($this,obj) {}, //移除目標jquery對象的圖片,$this為目標jquery對象 removeImg:function ($this) {}, //開始游戲,seats為服務(wù)器發(fā)送過來的座位對應(yīng)著的用戶的信息,turn指定座位下標為turn的用戶先出牌(turn由服務(wù)器的隨機數(shù)產(chǎn)生) //存儲服務(wù)器發(fā)送過來的撲克牌數(shù)組,調(diào)用cardsSort,drawothers,drawuser,placeCards,initPlay startGame:function (seats,turn) {}, //出牌前的邏輯判斷,判斷牌是否能壓過上家或者是否符合邏輯 preSend:function () {}, //在status為WATING時點擊出牌調(diào)用的函數(shù) notYourTurn:function () {}, //壓牌邏輯的實現(xiàn),temp存儲著牌型,牌的值和牌的數(shù)量 compWhichLarger:function (temp) {}, //綁定座位點擊坐下事件 init:function () {}, //游戲結(jié)束正常調(diào)用end函數(shù),isWin為true則該玩家勝利 end:function (isWin) {}, //重開一局,array為來自服務(wù)器的撲克牌數(shù)組,turn為先出牌的人 reStart:function (array,turn) {}, //切換準備按鈕的狀態(tài),準備->取消,取消->準備 readyGame:function () {}, //游戲結(jié)束 gameover:function (isWin) {}, //放棄出牌 giveUp:function () {}, //放棄出牌得到服務(wù)器回應(yīng) giveUpReply:function (giupCount) {}, //綁定一系列點擊事件 initPlay:function () {} } MODAL = modalBox; return modalBox.init(); }
5.2 出牌流程
//出牌按鈕綁定狀態(tài)機,根據(jù)當(dāng)前狀態(tài)運行對應(yīng)的函數(shù),只有在處于DISCARD狀態(tài)才能正常發(fā)牌 $("body").on("click","#sendCards",statusMachine); function statusMachine() { switch(MODAL.default.status){ case "DISCARD": //運行至preSend函數(shù) MODAL.preSend(); break; case "WAITNG": MODAL.notYourTurn(); break; case "GAMEOVER": MODAL.readyGame(); default: break; } } var modalBox = { preSend:function () { var array = new Array(); //將被選擇(用select來標識)的撲克牌的下標取出,插入數(shù)組array中 $(".cardsLine .card").each(function () { if($(this).hasClass("select")){ array.push($(this).attr("index")); } }); //compCards函數(shù)參數(shù)為排過序的array,因為用戶手牌已經(jīng)按照一定順序排過序,所以按照一個方向取出來的牌也是具有一定是有序列的 var temp = compCards(array); //console.log(compCards(array)); //console.log(temp); //disCardTrue為true標識之前已經(jīng)有兩個人放棄出牌,所以不需要考慮壓牌,只需要牌型符合一定規(guī)則即可出牌 if(MODAL.default.disCardTrue){ if(temp.type!="ERR"){ socketFun.sendCards(array); }else{ alert("無法出牌"); } }else{ //temp為儲存array牌型以及大小等數(shù)據(jù)的對象,compWhichLarger函數(shù)則是將temp與上一位玩家發(fā)的牌進行比較,如果大于則flag為true var flag = ptrThis.compWhichLarger(temp); if(flag){ //將array發(fā)送至服務(wù)器,如果服務(wù)器將接受成功的消息發(fā)回,則調(diào)用 justifyWhich函數(shù) socketFun.sendCards(array); }else{ alert("無法出牌"); } } //ptrThis.sendCards(); }, justifyWhich:function (obj) {//ojb為服務(wù)器發(fā)送的消息,包含發(fā)牌人,發(fā)的牌的信息 if(obj.posterIndex!=MODAL.default.myIndex){ //如果是別人出的牌,則儲存該牌型 MODAL.default.formercardsType=compCards(obj.array); } MODAL.default.disCardTrue = false; var $goal;//$goal為待渲染的部位 switch(obj.posterIndex){ case MODAL.default.myIndex: ptrThis.removeCards(); $goal = $(".showCardLine"); break; case MODAL.default.leftIndex: $goal = $(".leftPlayer").children(".otherCards"); break; case MODAL.default.rightIndex: $goal = $(".rightPlayer").children(".otherCards"); break; default: break; } ptrThis.placeCards($goal,obj.array,false); //進入下一回合,輪次加一 MODAL.default.turn = (MODAL.default.turn+1)%3; console.log("Now turn is"+MODAL.default.turn); //設(shè)置下一回合該玩家是出牌還是等待 if(MODAL.default.turn==MODAL.default.myIndex){ MODAL.default.status = "DISCARD"; }else{ MODAL.default.status = "WAITNG" } //如果某一位玩家出完牌,則游戲結(jié)束 if(obj.sendOut){ if(obj.posterIndex==MODAL.default.myIndex){ ptrThis.end(true); }else{ ptrThis.end(false); } } } }
5.3 客戶端SocketIO消息模型
var socket = io.connect("http://localhost:3000"); var X = window.scriptData; //截取服務(wù)器發(fā)送過來的數(shù)據(jù) //收到服務(wù)器發(fā)送的不同的消息類型,調(diào)用對應(yīng)的出牌模型中的函數(shù) socket.on("connect",function () { socket.emit("addUser",X._id); //添加用戶 }) socket.on("playerSit",function (obj) { MODAL.insertImg($(".seat").eq(obj.index).children(),obj); }) socket.on("leave",function (index) { MODAL.removeImg($(".seat").eq(index).children()); }) socket.on("seatsInfo",function (obj) { console.log("seatsInfo"+obj); for(var key in obj){ console.log(key); MODAL.insertImg($(".seat").eq(obj[key].index).children(),obj[key]); } }) socket.on("gameStart",function (obj,turn) {//服務(wù)器通知玩家游戲開始 MODAL.startGame(obj,turn); }) socket.on("postCards",function (obj) {//服務(wù)器返回出牌人以及出牌信息 MODAL.justifyWhich(obj); }) socket.on("reStart",function (array,turn) {//服務(wù)器返回重新開始游戲的信息 MODAL.reStart(array,turn); }) socket.on("giveup",function (giupCount) {//服務(wù)器返回放棄信息 MODAL.giveUpReply(giupCount); }) socket.on("renshu",function (seats) { MODAL.someOneTouXiang(seats); }) var socketFun = { //出牌對象通過socketFun調(diào)用相關(guān)函數(shù)與服務(wù)器通信 sit:function ($this) { var obj = { id:X._id, index:$this.parent().index() } socket.emit("sitSeat",obj); }, sendCards:function (array) { var sendOut; if(($(".cardsLine .cards").children().length-array.length)==0){ sendOut = true; }else{ sendOut = false; } var obj = { array:array, posterIndex:MODAL.default.myIndex, sendOut:sendOut } socket.emit("postCards",obj); }, readyMsg:function (obj) {//告知服務(wù)器該玩家準備 socket.emit("readyMsg",obj); }, giveUp:function () {//告知服務(wù)器放棄出牌 socket.emit("giveup"); }, touxiang:function (index) {//告知服務(wù)器該玩家投降 socket.emit("touxiang",index) } }
5.4 壓牌邏輯
根據(jù)牌型數(shù)組判斷牌型的邏輯使用狀態(tài)機實現(xiàn),其狀態(tài)遷移圖如下:
function compCards(array) { if(array.length==2&&data[array[0]].value==16&&data[array[1]].value==15){//天王炸 var cardsType={ count:array.length, type:"KINGBOMB", value:data[array[0]].value }; return cardsType; } //ptr指向array的下標 var ptr; //end標志狀態(tài)機是否結(jié)束 var end = false; //data存儲著每一張撲克的value,避免多次運算value var box = { cardsType:{ count:array.length, type:"ONE", value:data[array[0]].value }, setType:function (type) { this.cardsType.type = type; }, statusOne:function () { if(this.cardsType.count==1){ end = true; return ; } if(data[array[0]].value==data[array[1]].value){ //如果第一個和第二個數(shù)字相同 this.setType("TWO"); return ; } if(data[array[0]].value==data[array[1]].value+1){ this.setType("STRAIGHT"); }else{ this.setType("ERR"); } return ; }, statusTwo:function () { if(this.cardsType.count==2){ end = true; return ; } if(data[array[1]].value==data[array[2]].value){ this.setType("THREE"); return ; } if(data[array[1]].value==data[array[2]].value+1){ this.setType("TWO-ONE"); }else{ this.setType("ERR"); } }, statusThree:function () { if(this.cardsType.count==3){ end = true; return ; } if(data[array[2]].value==data[array[3]].value){ this.setType("BOMB"); return ; } if(data[array[2]].value==data[array[3]].value+1){ this.setType("THREE-ONE"); }else{ this.setType("ERR"); } return ; }, statusStraight:function () { if(this.cardsType.count< 5){ this.setType("ERR"); end = true; return ; } if(ptr< this.cardsType.count-1){ if(data[array[ptr]].value!=data[array[ptr+1]].value+1){ this.setType("ERR"); end = true; return ; } }else{ end = true; return ; } }, statusTwoOne:function () { if(ptr==this.cardsType.count-1){ //TwoOne處于中間狀態(tài),結(jié)束則出錯 this.setType("ERR"); return ; } if(data[array[ptr]].value==data[array[ptr+1]].value){ this.setType("TWO-TWO"); }else{ this.setType("ERR"); } return ; }, statusTwoTwo:function () { if(ptr==this.cardsType.count-1){ end = true; return ; } if(data[array[ptr]].value==data[array[ptr]].value+1){ this.setType("TWO-ONE"); }else{ this.setType("ERR"); } return ; }, statusThreeOne:function () { if(ptr==this.cardsType.count-1){ this.setType("ERR"); return ; } if(data[array[ptr]].value==data[array[ptr+1]].value){ this.setType("THREE-TWO"); }else{ this.setType("ERR"); } return ; }, statusThreeTwo:function () { if(ptr==this.cardsType.count-1){ this.setType("ERR"); return ; } if(data[array[ptr]].value==data[array[ptr+1]].value){ this.setType("THREE-THREE"); }else{ this.setType("ERR"); } return ; }, statusThreeThree:function () { if(ptr==this.cardsType.count-1){ end = true; return ; } if(data[array[ptr]].value==data[array[ptr+1]].value+1){ this.setType("THREE-ONE"); }else{ this.setType("ERR"); } return ; }, statusBomb:function () { if(ptr==this.cardsType.count-1){ end = true; return ; } if(data[array[ptr]].value!=data[array[ptr+1]].value){ this.setType("ERR"); } }, ERR:function () { end = true; return ; } }; for(ptr = 0;ptr< box.cardsType.count;++ptr){ console.log("END:"+end); console.log(box.cardsType); if(end){ break; } switch(box.cardsType.type){ //ONE表示單張牌,這個ONE狀態(tài)結(jié)束有效 case "ONE": box.statusOne(); break; //TWO表示一對,結(jié)束有效 case "TWO": box.statusTwo(); break; //THREE表示三張一樣的牌,結(jié)束有效 case "THREE": box.statusThree(); break; //STRAIGHT表示順子,根據(jù)array長度判斷是否有效 case "STRAIGHT": box.statusStraight(); break; //TWO-ONE表示形如xx(x+1)(x+1)(x+2)的牌型,結(jié)束無效,返回類型ERR case "TWO-ONE": box.statusTwoOne(); break; case "TWO-TWO": //TWO-TWO表示形如xx(x+1)(x+1)(x+2)(x+2)的牌型,結(jié)束有效 box.statusTwoTwo(); break; //THREE-ONE表示形如xxx(x+1)(x+1)(x+1)(x+2)的牌型,結(jié)束無效,返回類型ERR case "THREE-ONE": box.statusThreeOne(); break; //THREE-TWO表示形如xxx(x+1)(x+1)(x+1)(x+2)(x+2)的牌型,結(jié)束無效,返回類型ERR case "THREE-TWO": box.statusThreeTwo(); break; //THREE-THREE表示形如xxx(x+1)(x+1)(x+1)(x+2)(x+2)(x+2)的牌型,結(jié)束有效 case "THREE-THREE": box.statusThreeThree(); break; //BOMB表示炸彈,返回有效 case "BOMB": box.statusBomb(); break; //ERR表示牌型不合邏輯,無效 case "ERR": box.ERR(); break; } } return box.cardsType; }
詳細代碼見GITHUB的pokepoke項目
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/115353.html
摘要:系統(tǒng)結(jié)構(gòu)系統(tǒng)考慮使用和實現(xiàn)服務(wù)器端邏輯,前端使用。邏輯流程主要邏輯包括用戶進入游戲等待對家進入游戲游戲過程結(jié)束統(tǒng)計這個過程。 1. 系統(tǒng)結(jié)構(gòu) 系統(tǒng)考慮使用Nodejs和SocketIo實現(xiàn)服務(wù)器端邏輯,前端使用HTML5。showImg(https://segmentfault.com/img/remote/1460000007643089); 2. 邏輯流程 1 . 主要邏輯包括用戶...
摘要:技術(shù)棧項目背景這個項目主要是為了玩玩,項目的方向大概是做出類似的在線聊天系統(tǒng)。項目使用進行部署和管理,功能在不斷的迭代開發(fā)中。首頁用戶列表用戶中心注冊登陸注銷用戶資料指定聊天室開始安裝使用之前,請在中修改的安裝路徑。 技術(shù)棧:NodeJS & SocketIO & Express & EJS & MongoDB & Gulp 項目背景 這個項目主要是為了玩玩NodeJS,項目的方向大概...
摘要:技術(shù)棧項目背景這個項目主要是為了玩玩,項目的方向大概是做出類似的在線聊天系統(tǒng)。項目使用進行部署和管理,功能在不斷的迭代開發(fā)中。首頁用戶列表用戶中心注冊登陸注銷用戶資料指定聊天室開始安裝使用之前,請在中修改的安裝路徑。 技術(shù)棧:NodeJS & SocketIO & Express & EJS & MongoDB & Gulp 項目背景 這個項目主要是為了玩玩NodeJS,項目的方向大概...
摘要:在現(xiàn)如今的游戲市場寒冬中,擁有微信龐大的用戶量以及更好兼容性的小程序游戲,優(yōu)勢就顯得格外明顯。掃描二維碼即可報名您在現(xiàn)場將有這些體驗來自騰訊云云開發(fā)團隊與微信團隊聯(lián)合打造干貨分享,內(nèi)容包括微信小游戲首發(fā)經(jīng)驗分享。 有人說微信小程序游戲的百花齊放 活像十幾年前的4399小游戲稱霸互聯(lián)網(wǎng)的景象 歪,斗地主嗎,三缺二, 不用下app,小程序就能玩,我保證不搶地主讓你搶! ...... ‘...
閱讀 1446·2021-09-10 11:27
閱讀 2400·2019-08-30 15:53
閱讀 1317·2019-08-30 13:10
閱讀 2968·2019-08-30 11:09
閱讀 1073·2019-08-29 17:23
閱讀 663·2019-08-29 17:05
閱讀 2943·2019-08-29 15:10
閱讀 2338·2019-08-29 13:22