前言
以下只是学习websocket过程中开发的一个demo,功能有限可能还会有些bug。
首先,这是线上链接。
技术栈和已实现功能
技术栈:
* 前端:vue
* 后端:nodejs+websocket+ws
复制代码
已实现功能:
* 随机发牌(自动分配地主和地主牌)
* 出牌同步
* 断线重连(依据ip。demo中为了方便演示,并没有限定一个ip只能加入一次)
* 退出游戏(同房间其他玩家也会清除手牌)
* 游戏大厅与多房间游戏
* log公告窗口
复制代码
基本功能的实现
websocket基础知识
WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。 WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。 demo中使用的ws库,npm i ws 安装完成之后,开启websocket服务:
const WebSocket = require('ws');//引入ws
const wss = new WebSocket.Server({ port: 8002 });//开启服务
wss.on('connection',function(ws,req){ //客户端链接
ws.on('message', function incoming(data) {}); //接收客户端消息
ws.on('close',function reset(){}) //客户端关闭触发
})
wss.broadcast = function broadcast(data) { //广播
wss.clients.forEach(function each(client) {
if (client.readyState === WebSocket.OPEN) {
client.send(data);
}
});
};
复制代码
与之对应,在客户端需要:
const ws = new WebSocket('ws://localhost:8002');
ws.onopen = function(e){} //客户端链接
ws.onclose = function(e){} //客户端关闭
ws.onerror = function(){} //连接出错
ws.onmessage = function(e){} //接收服务端消息
复制代码
由于ws只能发送二进制和string,但是我们数据传输需求基本都是复杂数据对象,因此每次发送和接收前都需要用JSON.stringfy()和JSON.parse()转换。
发牌函数
首先需要获得所有牌型
function Card(){
var type = ['黑桃','红心','梅花','方块']
var nume = [
{label:'A',value:14},{label:'2',value:16},{label:'3',value:3},{label:'4',value:4},
{label:'5',value:5},{label:'6',value:6},{label:'7',value:7},{label:'8',value:8},
{label:'9',value:9},{label:'10',value:10},{label:'J',value:11},{label:'Q',value:12},{label:'K',value:13}]
var All = []
type.forEach(v=>{
nume.forEach(cv=>{
All.push({
type:v,
label:cv.label,
value:cv.value,
isOn:false
})
})
})
All.push({
type:'大王',
label:'大王',
value:100,
isOn:false
})
All.push({
type:'小王',
label:'小王',
value:50,
isOn:false
})
return All
}
复制代码
然后根据随机数生成4个数组,前三个为玩家手牌,第四个为地主牌。
module.exports = function initCard(num){ //初始化手牌
var AllCard = Card()
var player = []
for(var i=0;i<num;i++){
player.push([])
for(var j=0;j<(51/num);j++){
var n = Math.floor(Math.random()*AllCard.length)
player[i].push(AllCard[n])
AllCard.splice(n,1)
}
}
player.push(AllCard)
AllCard=[]
for(var i=0;i<player.length;i++){
player[i]=player[i].sort(reSort('value'))
}
return player
}
复制代码
发牌展示
html结构如下:
<ul :style="'width:'+((bossCard.length-1)*24+100)+'px'" class="cardList" v-show="bossCard.length>0" v-if="bossCard">
<li v-for="(item,ci) in bossCard" :class="item.isOn==true?'isOn':''" :key="ci" :style="'left:'+ci*24+'px;z-index:'+ci">
<div :class="item|setClass" style="text-align: left;">{{item.label}}</div>
<div class="cardBg"></div>
</li>
</ul>
复制代码
- 画一张扑克牌
根据type添加不通类名,然后通过背景图添加花色
filters: {
setClass(item){
if(item.type == '黑桃') return 'heitao'
if(item.type == '红心') return 'hongxin'
if(item.type == '梅花') return 'meihua'
if(item.type == '方块') return 'fangkuai'
if(item.type == '大王') return 'dawang'
if(item.type == '小王') return 'xiaowang'
}
}
复制代码
- 发牌动画
接收到服务端的手牌后通过定时器一张一张添加到vm,然后添加transition: all linear 0.2s即可实现类似qq斗地主的发牌效果。
var t = setInterval(()=>{
if(i+1>cardArr.length){
_this.isInit = true
return clearInterval(t)
}
_this.player.push(cardArr[i])
i++
},200)
复制代码
待续
也不知道有没有人看,先写到这里。感兴趣的可以看下github源码。 整个demo都是想到哪写到哪,代码特别乱还没来得及整理,出牌验证规则也还没有写。后边有时间了整理一下代码然后补全功能。