斗地主游戏文档
2016-11-23 本文已影响42人
Zoemings
1.体系结构图
体系结构图.png2.逻辑流程图
2.1简易流程图
逻辑流程图.png2.2详细流程图
详细逻辑流程图.png3.服务器-客户端通讯图
sc通讯图.png4.数据结构
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压牌逻辑
压牌逻辑.png5.页面展示
5.1开始游戏
开始游戏.PNG5.2等待页面
等待.PNG5.3发牌页面
发牌页面.PNG6代码展示
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;
}