使用Canvas实现一个在线发牌游戏 [纯前端、附源码]
程序员文章站
2024-01-23 08:04:04
...
写在开头
一位作者开源了这个游戏,纯前端实现,原生
Canvas
希望大家给他点个
star
,源码地址:https://github.com/leeseean/sic-bo
这个项目克隆很慢,因为比较大,如果你想知道怎么克隆快,可以看今天公众号第二条推文 《如何把github的clone速度提升到1MB/S》
为什么要推荐这个项目
在我看来,这个作者是有一定技术实力的,对canvas理解和使用,以及浏览器渲染机制,都是比较了解的,还有原生dom操作能力都可以
里面大量使用了canvas的路径绘制、填充,以及
requestAnimationFrame
技术栈
使用原生javascript + html +css
主要绘制是canvas实现
项目初始状态
怎么玩这个游戏
点击想押注的地方
筹码会有一个动画飞向你押注的区域
押注完成后,定时开始摇骰子,开奖
大概实现
初始调用 init函数,生成canvas画布,挂载onclick事件
init() {
let _this = this;
_this.loadImage();
_this.scale = screen.width < 1500 ? screen.width / 1920 : 1;
let scale = _this.scale;
//拿到画布
let canvas_fly = document.getElementById('canvas_fly'); //渲染飞出去的筹码
canvas_fly.width = document.body.clientWidth;
canvas_fly.height = 912 * scale || 800;
_this.ctxFly = canvas_fly.getContext('2d');
let canvas_stop = document.getElementById('canvas_stop'); //渲染未确认**放桌面上的筹码
canvas_stop.width = document.body.clientWidth;
canvas_stop.height = 912 * scale || 800;
_this.ctxStop = canvas_stop.getContext('2d');
let canvas_betted = document.getElementById('canvas_betted'); //渲染确认**的筹码
canvas_betted.width = document.body.clientWidth;
canvas_betted.height = 912 * scale || 800;
_this.ctxBetted = canvas_betted.getContext('2d');
//拿到chipsImgObj对象
let img = new Image();
img.onload = function () {
_this.chipsImgObj = this; //拿到chipsImgObj对象
}
img.src = './images/chips.png';
//确定所用筹码
$('.chips>.chip').off('click').on('click', function (e) {
$(this).addClass('on').siblings('.chip').removeClass('on');
_this.priceNum = +$(this).attr('priceNum');
});
$('.chips>.chip10').trigger('click'); //默认筹码10
const pieceIntervalOver = { //连续点击翻倍生不生效的flag
'betFor': false,
'betted': false,
'pieceCount': 0,
};
const cancelOk = {
ok: false,
count: 0,
}; //取消完毕,默认false
const resetOk = {
ok: false,
count: 0,// 防止重复点击
}
//点击桌面选号
$('[rel="selectCode"]').off('click').on('click', function (e) {
if (cancelOk.ok || cancelOk.count === 0) {
cancelOk.count = 0;
} else {
return; //没取消完毕不准过去
}
_this.flyState = 'flyTo';
let code = $(this).attr('value');
let method = $(this).attr('method');
let startPos = {
x: $(`.chips .chip${_this.priceNum}`).offset().left,
y: $(`.chips .chip${_this.priceNum}`).offset().top,
};
let endPos = {
x: $(this).offset().left + $(this)[0].offsetWidth * scale / 2 - $('.chips>.chip').width() * scale / 2,
y: $(this).offset().top + $(this)[0].offsetHeight * scale / 2 - $('.chips>.chip').height() * scale / 2,
};
_this.eachBetCount[code] = _this.eachBetCount[code] || 0;
_this.eachBetCount[code] += _this.priceNum;
_this.betOrderRecords[code] = { //记录order
method: method,
code: code,
price: _this.priceNum,
amount: _this.eachBetCount[code],
piece: _this.eachBetCount[code],
};
let clickedElemOption = { //被点击元素的相关数据
priceNum: _this.priceNum,
code: code,
position: {
x: $(this).offset().left,
y: $(this).offset().top,
},
width: $(this).outerWidth(),
height: $(this).outerHeight(),
};
_this.betForRecords.push({ //记录**
elemOption: copyJSON(clickedElemOption),
priceNum: _this.priceNum,
startPos,
endPos,
});
_this.chipFly(_this.ctxFly, _this.ctxStop, _this.chipsImgObj, _this.priceNum, startPos, endPos, clickedElemOption, 10);
$('.betMoneyAmount').text(_this.calculateBetMoney());
});
//取消**
$('.cancelButton').off('click').on('click', function (e) {
if (cancelOk.ok || cancelOk.count === 0) {
cancelOk.ok = false;
} else {
return; //没取消完毕不准过去
}
if ((pieceIntervalOver.betFor && pieceIntervalOver.betted) || pieceIntervalOver.pieceCount === 0) {
} else {
return; //上次翻倍全部渲染结束才能进行下一次点击操作,没结束操作无效
}
cancelOk.count += 1;
pieceIntervalOver.pieceCount = 0;
if (_this.betForRecords.length === 0) {
return;
}
_this.flyState = 'flyBack';
//timechunk 分时函数
let i = 0;
let interval = setInterval(() => {
if (i === _this.betForRecords.length) {
cancelOk.ok = true;
cancelOk.count = 0; //回到0
_this.betForRecords.length = 0;
_this.betOrderRecords = {};
_this.eachBetCount = {};
_this.ctxStop.clearRect(0, 0, document.body.clientWidth, document.body.clientHeight);
$('.betMoneyAmount').text(_this.calculateBetMoney());
return clearInterval(interval);
}
let record = _this.betForRecords[i];
_this.chipFly(_this.ctxFly, _this.ctxStop, _this.chipsImgObj, record.priceNum, record.endPos, record.startPos, record.elemOption, 10);
i++;
}, 10);
});
//重置**
$('.resetButton').off('click').on('click', function (e) {
if (resetOk.ok || resetOk.count === 0) {
resetOk.ok = false;
} else {
return; //没取消完毕不准过去
}
if ((pieceIntervalOver.betFor && pieceIntervalOver.betted) || pieceIntervalOver.pieceCount === 0) {
} else {
return; //上次翻倍全部渲染结束才能进行下一次点击操作,没结束操作无效
}
resetOk.count += 1;
pieceIntervalOver.pieceCount = 0;
if (_this.betForRecords.length === 0 && _this.bettedRecords.length === 0) {
return;
}
_this.flyState = 'flyBack';
//timechunk 分时函数
let i = 0;
let interval = setInterval(() => {
if (i === _this.betForRecords.length) {
_this.betForRecords.length = 0;
_this.betOrderRecords = {};
_this.eachBetCount = {};
_this.ctxStop.clearRect(0, 0, document.body.clientWidth, document.body.clientHeight);
$('.betMoneyAmount').text(_this.calculateBetMoney());
clearInterval(interval);
let j = 0;
const _interval = setInterval(() => {
if (j === _this.bettedRecords.length) {
resetOk.ok = true;
resetOk.count = 0; //回到0
_this.bettedRecords.length = 0;
_this.ctxBetted.clearRect(0, 0, document.body.clientWidth, document.body.clientHeight);
$('.betMoneyAmount').text(_this.calculateBetMoney());
return clearInterval(_interval);
}
console.log(j)
const bettedRecord = _this.bettedRecords[j];
_this.chipFly(_this.ctxFly, _this.ctxBetted, _this.chipsImgObj, bettedRecord.priceNum, bettedRecord.endPos, bettedRecord.startPos, bettedRecord.elemOption, 10);
j++;
}, 10);
return;
}
const betForRecord = _this.betForRecords[i];
_this.chipFly(_this.ctxFly, _this.ctxStop, _this.chipsImgObj, betForRecord.priceNum, betForRecord.endPos, betForRecord.startPos, betForRecord.elemOption, 10);
i++;
}, 10);
});
//确认**
$('.betButton').off('click').on('click', function (e) {
if (_this.betForRecords.length === 0) {
alert('请先**!');
return;
}
if (cancelOk.ok || cancelOk.count === 0) {
} else {
return; //没取消完毕不准过去
}
if ((pieceIntervalOver.betFor && pieceIntervalOver.betted) || pieceIntervalOver.pieceCount === 0) {
} else {
return; //上次翻倍全部渲染结束才能进行下一次点击操作,没结束操作无效
}
_this.flyState = 'betted';
_this.bettedRecords = _this.bettedRecords.concat(_this.betForRecords);
_this.betForRecords.forEach((record) => {
_this.chipFly(_this.ctxFly, _this.ctxBetted, _this.chipsImgObj, record.priceNum, record.endPos, record.endPos, record.elemOption, 30);
});
_this.ctxStop.clearRect(0, 0, document.body.clientWidth, document.body.clientHeight);
_this.betForRecords.length = 0;
_this.betOrderRecords = {};
_this.eachBetCount = {};
});
//翻倍**
$('.pieceButtoon').off('click').on('click', function (e) {
let bettedLen = _this.bettedRecords.length;
let betForLen = _this.betForRecords.length;
if (bettedLen === 0 && betForLen === 0) {
return;
}
if (cancelOk.ok || cancelOk.count === 0) {
} else {
return; //没取消完毕不准过去
}
if ((pieceIntervalOver.betFor && pieceIntervalOver.betted) || pieceIntervalOver.pieceCount === 0) {
pieceIntervalOver.betFor = false;
pieceIntervalOver.betted = false;
pieceIntervalOver.pieceCount += 1;
} else {
return; //上次翻倍全部渲染结束才能进行下一次点击操作,没结束操作无效
}
//timechunk分时函数,防止短时间多次触发卡死浏览器
let i = 0;
let interval_bet = setInterval(() => {
if (i === bettedLen) {
pieceIntervalOver.betted = true;
return clearInterval(interval_bet);
}
let code = _this.bettedRecords[i]['elemOption']['code'];
_this.priceNum = _this.bettedRecords[i]['priceNum'];
$(`[rel="selectCode"][value="${code}"]`).trigger('click'); //自动桌面选号点击
i++;
}, 10);
let j = 0;
let interval_betted = setInterval(() => {
if (j === betForLen) {
pieceIntervalOver.betFor = true;
return clearInterval(interval_betted);
}
let code = _this.betForRecords[j]['elemOption']['code'];
_this.priceNum = _this.betForRecords[j]['priceNum'];
$(`[rel="selectCode"][value="${code}"]`).trigger('click'); //自动桌面选号点击
j++;
}, 10);
});
},
init函数初始化中将canvas画笔挂载到this中
_this.ctxStop = canvas_stop.getContext('2d');
_this.ctxBetted = canvas_betted.getContext('2d');
...
确认**后,清空未确认**放桌面上的筹码画布
$('.betButton').off('click').on('click'、、、
_this.ctxStop.clearRect(0, 0, document.body.clientWidth, document.body.clientHeight);
如果没有**,就提示:
if (_this.betForRecords.length === 0) {
alert('请先**!');
return;
}
最后,希望大家多看看这个源码,了解canvas使用
记得给作者点个star哦,这是一个入门canvas的一个很好的开源项目,点击左下角的阅读原文就可以进入到源码地址啦:
https://github.com/leeseean/sic-bo
如果深入点的话,可以再学习一下canvas的像素控制,或者
pixijs
的使用在线体验这个游戏的地址是:
https://leeseean.github.io/sic-bo/
如果感觉写得不错,关注下微信公众号 [前端巅峰
]
我是Peter,架构设计过20万人端到端加密超级群功能的桌面IM软件,我的微信:
CALASFxiaotan
另外欢迎收藏我的资料网站:前端生活社区:
https://qianduan.life
,感觉对你有帮助,可以右下角点个在看,关注一波公众号:[前端巅峰
]