这是两个人间的简单扑克游戏,每人27张牌,由服务器随机分成两组不同的数组传递给客户端。
基本逻辑已实现,剩下扑克牌逻辑:
- 1.用户进入登录界面,点击登录按钮,若当前已有一个人在等待,则直接进入游戏,否则一直等待,直到第二个人登录;
- 2.用户在游戏中随时可退出,刷新页面即视为退出,此时双方都回到登录界面,需要重新登录;
- 3.依据哪方拿到 黑桃♠3,哪方就先出牌;
- 4.假设A先出牌,A出牌给B,B上方出现A发过来的牌,换B出牌,这时有出牌和放弃两个选项。出牌同样发送选中牌的数据,放弃则是不刷新桌上牌列,将出牌权给A。
JS
var socket = io(); //传递给服务器用户Id
var wrapper = ".wrapper";
var htmlLogin = "<div class='login'><button type='button' id='login'>登录</button> </div>";
var htmlWait = "<div class='waiting'> <h3>请等待另一位玩家加入。。。</h3> </div>";
var htmlPoker = "<div class='wrap'> <div class='box-upper'></div> <div class='box-center'> <div class='preview-above' id='preview-above'></div> <div class='preview-below' id='preview-below'></div> </div> <div class='button-turn hide-block'> <button class='discard' id='discard'>出牌</button> <button class='abandon' id='abandon'>放弃</button> </div> <div class='box-below' id='box-below'></div></div>";
var htmlWin = "<div class='mask'><div class='content'>WIN</div> <button type='button' id='reload'>确定</button></div>";
var htmlDefeat = "<div class='mask'><div class='content'>Defeat</div> <button type='button' id='reload'>确定</button></div>";
var INIT = "INIT";
var WAIT = "WAIT";
var DISCARD = "DISCARD";
var GAMEOVER = "GAMEOVER";
var RESTART = "RESTART";
$(init);
function init() {
//绑定点击事件
$("body").on("click", clickEvent);
//初始化socket和登录界面
pkObj.init();
}
//点击事件
function clickEvent(e) {
var target = e.target;
var that = $(target);
switch (pkObj.data.status) {
case INIT: //未登录状态
doInit();
break;
case DISCARD: //出牌状态
doDiscard(that);
break;
case GAMEOVER: //游戏结束状态
doRestart();
break;
default:
break;
}
}
//pkObj
var pkObj = {
data: {
type: 0, //出牌类型
discardList: 0, //出牌数组
remain: 27, //我方牌的剩余量
from: 0, //我方id
to: 0, //对方id
before: false, //先出牌或对方放弃
status: INIT //状态:INIT初始化, DISCARD出牌,GAMEOVER游戏结束
},
init: function () {
//初始化socket
socketInit();
//加载登录界面
$(wrapper).append(htmlLogin);
}
};
//初始化socket
function socketInit() {
//等待状态
socket.on("waiting", function () {
$(wrapper).html("");
$(wrapper).append(htmlWait);
pkObj.data.status = WAIT;
});
//进入打牌界面
socket.on("start poker", function (data) {
pkObj.data.to = data.to;
$(wrapper).html("");
$(wrapper).append(htmlPoker);
if(data.before == true) {
pkObj.data.before = true;
$(".button-turn").removeClass("hide-block");
$("#abandon").attr('disabled',"true");
pkObj.data.status = DISCARD;
} else {
pkObj.data.status = WAIT;
}
poker(data.pokerList, 27);
});
//第三人登录显示拥挤
socket.on("crowded", function () {
alert("棋牌室拥挤,请稍后再试。。。");
});
//对方退出全部初始化
socket.on("exit", function () {
$(wrapper).html("");
$(wrapper).append(htmlLogin);
pkObj.data.status = RESTART;
});
//接受对方的牌
socket.on("receive discard", function (data) {
var num = data.num;
var length = $(".opposite").length;
$("#preview-above").html("");
$("#preview-below").html("");
for(var index in data.discard) {
$("#preview-above").append(data.discard[index]);
}
$(".button-turn").removeClass("hide-block");
// $(".opposite:eq(" + i + ")").remove();
$(".box-upper").html("");
oppositePoker(length - num);
pkObj.data.status = DISCARD;
});
//对方放弃出牌
socket.on("receive abandon", function () {
pkObj.data.before = true;
$("#abandon").attr('disabled',"true");
$("#preview-above").html("");
$(".button-turn").removeClass("hide-block");
pkObj.data.status = DISCARD;
});
//比赛结果
socket.on("receive result", function (data) {
pkObj.data.status = GAMEOVER;
if(data == pkObj.data.from) {
$(wrapper).append(htmlWin);
} else {
$(wrapper).append(htmlDefeat);
}
});
}
//游戏结束
function doRestart() {
location.reload();
}
//登录状态
function doInit() {
//获得唯一的id
window.id = new Date().getTime()+""+Math.floor(Math.random()*899+100);
pkObj.data.from = id;
socket.emit("add user", id);
}
//出牌状态
function doDiscard(that) {
var element = that.attr("id");
var temp = element.replace(/[p]([0-9]+)/g, "p");
switch (temp) {
//p表示点击了选择的牌
case "p":
if(that.parent().attr("id") == "box-below") {
if(that.hasClass("click-up")) {
that.removeClass("click-up");
} else {
that.addClass("click-up");
}
}
break;
//点击出牌按钮
case "discard":
if($(".box-below").find(".click-up").length == 0) {
alert("请选择要出的牌,若没有请点击放弃");
} else {
var list = new Array(); //list中保存选中牌的整个div代码
var aboveList = new Array(); //aboveList 对方的牌
var belowList = new Array(); //belowList 我选中的牌
var i = 0;
var j = 0;
var k = 0;
// $("#preview-above").html("");
// $("#preview-below").html("");
$("#preview-above").find(".poker").each(function () {
var pokerId = $(this).attr("id");
pokerId = pokerId.replace(/[p]([0-9]+)/g, "$1"); //获取选中的牌的id(删掉首字母p)
aboveList[j] = getPokerFace(pokerId);
j++;
});
$("#box-below").find(".click-up").each(function () {
var pokerId = $(this).attr("id");
pokerId = pokerId.replace(/[p]([0-9]+)/g, "$1"); //获取选中的牌的id(删掉首字母p)
belowList[k] = getPokerFace(pokerId);
k++;
});
//先对选中的牌进行比较
if(compare(aboveList, belowList) || (pkObj.data.before && checkPokerType(belowList) != 0)) {
$("#preview-above").html("");
$("#preview-below").html("");
$(".click-up").each(function () {
list[i] = $(this).prop("outerHTML"); //获取选中的牌的整个div代码
$(this).removeClass("click-up");
$("#preview-below").append(list[i]);
$(this).remove();
i++;
});
pkObj.data.remain-=list.length;
var data = {
discard: list,
from: pkObj.data.from,
to: pkObj.data.to,
num: list.length,
remain: pkObj.data.remain
};
pkObj.data.before = false;
$("#abandon").removeAttr("disabled");
socket.emit("discard", data);
$(".button-turn").addClass("hide-block");
pkObj.data.status = WAIT;
} else {
alert("出牌不符合规则!");
}
}
break;
//点击放弃按钮
case "abandon":
$(".click-up").each(function () {
$(this).removeClass("click-up");
});
socket.emit("abandon", pkObj.data.to);
$(".button-turn").addClass("hide-block");
pkObj.data.status = WAIT;
break;
default:
break;
}
}
//初始化扑克牌
function poker(list, n) {}
//展示对方的牌
function oppositePoker(n) {}
//根据余数排序
function sortNumber(a, b) {}
//改变特殊牌的值
function changeNum(n, m) {}
//根据序号指定精灵图的位置
function getPos(index) {}
//检查和确定出牌的类型
function checkPokerType(pokerList) {}
//将选择出的牌和对方出的牌进行比较
function compare(list1, list2) {}
//返回每张牌的面值
function getPokerFace(n) {}
服务器端
//从一个给定的数组arr中,随机返回num个不重复项
function getArrItems(arr, num) {
var temp = new Array();
var result = new Array();
for (var index in arr) {
temp.push(arr[index]);
}
for (var i = 0; i < num; i++) {
if (temp.length > 0) {
var arrIndex = Math.floor(Math.random() * temp.length);
result[i] = temp[arrIndex];
temp.splice(arrIndex, 1);
} else {
break;
}
}
return result;
}
//从一个给定的数组arr中,随机返回num个不重复项
function getArrSubtract(arr, sub) {
var temp1 = new Array();
var temp2 = new Array();
for (var index in arr) {
temp1.push(arr[index]);
}
for (var index in sub) {
temp2.push(sub[index]);
}
for (var i = temp1.length - 1; i >= 0; i--) {
a = temp1[i];
for (var j = temp2.length - 1; j >= 0; j--) {
b = temp2[j];
if (a == b) {
temp1.splice(i, 1);
temp2.splice(j, 1);
break;
}
}
}
return temp1;
}
function getPoker() {
var list = new Array();
var result = {};
for (var i = 0; i < 54; i++) {
list[i] = i + 1;
}
var poker1 = getArrItems(list, 27);
var poker2 = getArrSubtract(list, poker1);
result = {
poker1: poker1,
poker2: poker2
};
return result;
}
//poker
var io = require('socket.io').listen(server);
var count = 0;
var user = {};
var first;
var second;
io.on('connection',
function(socket) {
//用户登录
socket.on('add user', function(id) {
console.log("user login");
count++;
user[id] = socket;
socket.name = id;
if (count == 1) { //只有一个人登录时
first = id;
user[first].emit("waiting");
} else if (count == 2) { //有两个人登录时
second = id;
var result = getPoker();
var data1 = {
to: second,
pokerList: result.poker1,
before: false
};
var data2 = {
to: first,
pokerList: result.poker2,
before: false
};
//判断谁拥有黑桃3
if (result.poker1.indexOf(29) != -1) {
data1.before = true;
} else {
data2.before = true;
}
user[first].emit("start poker", data1);
user[second].emit("start poker", data2);
} else if (count > 2) { //大于两人登录时显示繁忙,并删除这个socket
user[id].emit("crowded");
count = 2;
delete user[id];
}
});
//用户退出
socket.on('disconnect', function() {
//其中一方退出则全部回到起始页面
if (count == 1) {
delete user[socket.name];
} else if (count == 2) {
var person = (socket.name == first) ? second: first;
user[person].emit("exit");
delete user[first];
delete user[second];
}
count = 0;
});
//用户出牌
socket.on('discard', function(data) {
var result = {
discard: data.discard,
num: data.num
};
user[data.to].emit("receive discard", result);
});
//放弃出牌
socket.on("abandon", function(data) {
user[data].emit("receive abandon");
});
});
总结:
- 将点击事件封装到一个函数中,获得点击页面获得被点击元素的id,将
id
进行Switch
$("body").click(function(e) { // 在页面任意位置点击而触发此事件
$(e.target).attr("id"); // e.target表示被点击的目标
})
- .sort()函数
//返回值: 对数组的引用。请注意,数组在原数组上进行排序,不生成副本。
arrayObject.sort(sortby);
//从大到小
function sortNumber(a, b) {
return b - a;
}
//根据余数排序
function sortNumber(a, b) {
var x = changeNum(a % 13, a);
var y = changeNum(b % 13, b);
return y - x;
}
- jQuery :eq() 选择器
//选取第二个 <p> 元素:
$("p:eq(1)")
- 生成时间加上随机数的唯一id
window.id = new Date().getTime()+""+Math.floor(Math.random()*899+100);
- 获得父元素的id值
that.parent().attr("id") == "box-below"
- 判断是否存在某一className的元素
if($(".box-below").find(".click-up").length == 0)
- 获得指定元素的整个div值
list[i] = $(this).prop("outerHTML");
- 删除元素
$(this).remove();
- indexOf() 判断数组中是否存在某一值
/*indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置
如果要检索的字符串值没有出现,则该方法返回 -1。*/
stringObject.indexOf(searchvalue,fromindex);
//fromindex可选的整数参数。规定在字符串中开始检索的位置。它的合法取值是 0 到 stringObject.length - 1。如省略该参数,则将从字符串的首字符开始检索。
- 取随机数和数组相减,传参数后要新建一个数组,将传入的数组复制过来,用于运算,而不要直接操作传入的数组;
//从一个给定的数组arr中,随机返回num个不重复项
function getArrItems(arr, num) {
var temp = new Array();
var result = new Array();
for (var index in arr) {
temp.push(arr[index]);
}
for (var i = 0; i < num; i++) {
if (temp.length > 0) {
var arrIndex = Math.floor(Math.random() * temp.length);
result[i] = temp[arrIndex];
temp.splice(arrIndex, 1);
} else {
break;
}
}
return result;
}
//数组相减
function getArrSubtract(arr, sub) {
var temp1 = new Array();
var temp2 = new Array();
for (var index in arr) {
temp1.push(arr[index]);
}
for (var index in sub) {
temp2.push(sub[index]);
}
for (var i = temp1.length - 1; i >= 0; i--) {
a = temp1[i];
for (var j = temp2.length - 1; j >= 0; j--) {
b = temp2[j];
if (a == b) {
temp1.splice(i, 1);
temp2.splice(j, 1);
break;
}
}
}
return temp1;
}
- CSS精灵图使用方法
//随便一个写div,设置要显示小图尺寸
width: 90px;
height: 120px;
background: url("poker.png") no-repeat; //用于不重复地将图片显示
background-position: -1080px -480px; //两个参数,要显示小图的位置参数,切记都是负的
-
CSS画网格
.grid {
width: 400px;
height: 400px;
background: //关键部分,每格40*40,将39px设置透明,就显示出一条1px的线条
-webkit-linear-gradient(top, transparent 39px, #000 40px),
-webkit-linear-gradient(left, transparent 39px, #000 40px);
background-size: 40px 40px;
}
- CSS动画
transition: all .2s linear; //设置动画属性
-webkit-transform:rotate(-90deg); //旋转一定角度
//获取键盘输入
$("body").keydown(function (event) {
var keyCode = event.keyCode;
}
//设置按键延迟
setTimeout(function () {
purse = false;
}, 200);
- jQuery CSS 操作 - offset() 方法
position()
获取元素top和left
var boxLeft = box.position().left;
var boxTop = box.position().top;
offset()
方法返回或设置匹配元素相对于文档的偏移(位置)。
使用函数来设置偏移坐标
$(selector).offset(function(index, oldoffset));
.
$(document).ready(function() {
$("button").click(function() {
$("p").offset(function(n, c) {
newPos = new Object();
newPos.left = c.left + 100;
newPos.top = c.top + 100;
return newPos;
});
});
});