基于vue框架怎样制作五子棋游戏
Admin 2022-07-19 群英技术资讯 1182 次浏览
这篇文章给大家分享的是基于vue框架怎样制作五子棋游戏。小编觉得挺实用的,因此分享给大家做个参考,文中的介绍得很详细,而要易于理解和学习,有需要的朋友可以参考,接下来就跟随小编一起了解看看吧。在布局上,五子棋相比那些目标是随机运动的游戏,实现起来相对简单许多,思路也很清晰,总共分为:
(1)画棋盘;
(2)监听点击事件画黑白棋子;
(3)每次落子之后判断是否有5子相连,有则赢。
最复杂的恐怕就是如何判断五子棋赢了,那么就先从简单的开始,画个棋盘吧~
棋盘很简单,我们画个15*15的棋盘,横线竖线相交错:
drawCheckerboard() {
// 画棋盘
let _this = this;
_this.ctx.beginPath();
_this.ctx.fillStyle = "#fff";
_this.ctx.rect(0, 0, 450, 450);
_this.ctx.fill();
for (var i = 0; i < 15; i++) {
_this.ctx.beginPath();
_this.ctx.strokeStyle = "#D6D1D1";
_this.ctx.moveTo(15 + i * 30, 15); //垂直方向画15根线,相距30px;
_this.ctx.lineTo(15 + i * 30, 435);
_this.ctx.stroke();
_this.ctx.moveTo(15, 15 + i * 30); //水平方向画15根线,相距30px;
_this.ctx.lineTo(435, 15 + i * 30);
_this.ctx.stroke();
_this.resultArr.push(new Array(15).fill(0));
}
}
先用一个450 * 450 的正方形打底,四周留15宽度的空白,然后画上间隔为30的线。在for循环里,我们还初始化了一个15 * 15的二维数组,并全部填上0,没错,就是记录落子的。

好了,我们在获取dom的时候顺便监听一下click事件,来画棋子:
let container = document.getElementById("gobang");
container.addEventListener("click", _this.handleClick);
handleClick(event) {
let x = event.offsetX - 70;
let y = event.offsetY - 70;
if (x < 15 || x > 435 || y < 15 || y > 435) {
// 点出界的
return;
}
this.drawChess(x, y);
if(this.winGame){
this.drawResult();
return;
}
this.whiteTurn = !this.whiteTurn;
this.drawText();
}
画棋子的代码:
drawChess(x, y) {
let _this = this;
let xLine = Math.round((x - 15) / 30); // 竖线第x条
let yLine = Math.round((y - 15) / 30); // 横线第y条
if(_this.resultArr[xLine][yLine] !== 0){
return;
}
let grd = _this.ctx.createRadialGradient(
xLine * 30 + 15,
yLine * 30 + 15,
4,
xLine * 30 + 15,
yLine * 30 + 15,
10
);
grd.addColorStop(0, _this.whiteTurn ? "#fff" : "#4c4c4c");
grd.addColorStop(1, _this.whiteTurn ? "#dadada" : "#000");
_this.ctx.beginPath();
_this.ctx.fillStyle = grd;
_this.ctx.arc(
xLine * 30 + 15,
yLine * 30 + 15,
10,
0,
2 * Math.PI,
false
);
_this.ctx.fill();
_this.ctx.closePath();
_this.setResultArr(xLine, yLine);
_this.checkResult(xLine, yLine);
}
很容易可以计算出点击坐标最近的那个棋盘交叉点,当然,如果那里已经落了子,就得return。然后在交点处画上白子或者黑子,这里用渐变填充使棋子看起来更像那么回事。接着,在对应的二维数组里记录一下棋子状况:
setResultArr(m, n) {
let _this = this;
_this.resultArr[m][n] = _this.whiteTurn ? 1 : 2; // 白棋为1;黑棋为2
}

输赢结果怎么判断?肉眼看去,无非就是以当前落子为0,0原点建立坐标系,然后判断0°,180°,45°和135°四条线上是否有连续5子。相比于直接遍历计数,更好的方法就是取出四条线上的数据,然后判断是否有相连的5个1或者2字符。
假设我们落子的数组坐标是[m, n]。
(1)横线的结果数组字符串:this.resultArr[m].join('');
(2)竖线的结果数组字符串:
for(let i = 0; i<15; i++){
lineHorizontal.push(_this.resultArr[i][n]);
}
(3)135°(左上到右下):j从0-15,分别取this.resultArr[m - j][n -j]结果unshift进临时数组头部,取this.resultArr[m + j][n + j]放到临时数组尾部,行成结果;
(4)45°(左下到右上):j从0-15,分别取this.resultArr[m + j][n -j]结果unshift进临时数组头部,取this.resultArr[m - j][n + j]放到临时数组尾部,行成结果;
当然这里面都是要判断一下数组越界。
得到结果字符串后,我们判断是否有“22222”或者“11111”这样的字符串存在,有则说明胜利。
checkResult(m ,n){ // 判断是否有5子相连
let _this = this;
let checkStr = _this.whiteTurn ? CheckStrWhite : CheckStrBlack;
// 取出[m,n]横竖斜四条线的一维数组
let lineVertical = _this.resultArr[m].join('');
if(lineVertical.indexOf(checkStr) > -1){
_this.winGame = true;
return;
}
let lineHorizontal = [];
for(let i = 0; i<15; i++){
lineHorizontal.push(_this.resultArr[i][n]);
}
lineHorizontal = lineHorizontal.join('');
if(lineHorizontal.indexOf(checkStr) > -1){
_this.winGame = true;
return;
}
let line135 = [];
for(let j = 0; j < 15; j++){
if(m - j >= 0 && n - j >= 0){ // 左上角
line135.unshift(_this.resultArr[m - j][n -j]);
}
if(j > 0 && m + j < 15 && n + j < 15){ // 右下角
line135.push(_this.resultArr[m + j][n + j]);
}
}
line135 = line135.join('');
if(line135.indexOf(checkStr) > -1){
_this.winGame = true;
return;
}
let line45 = [];
for(let j = 0; j < 15; j++){
if(m + j < 15 && n - j >= 0){ // 右上角
line45.unshift(_this.resultArr[m + j][n -j]);
}
if(j > 0 && m - j >=0 && n + j < 15){ // 左下角
line45.push(_this.resultArr[m - j][n + j]);
}
}
line45 = line45.join('');
if(line45.indexOf(checkStr) > -1){
_this.winGame = true;
return;
}
}
最后胜出,我们显示一下是哪方获胜。

至此,一个简单的黑白棋游戏就做好了~~~~~
老规矩,源码贴上:
<template>
<div class="gobang">
<canvas id="gobang" width="800" height="600"></canvas>
</div>
</template>
<script>
const CheckStrWhite = "11111";
const CheckStrBlack = "22222";
export default {
name: "Gobang",
data() {
return {
ctx: null,
winGame: false,
whiteTurn: false, // 白棋轮;true-黑棋轮
resultArr: [] // 记录棋子位置的数组
};
},
mounted() {
let _this = this;
let container = document.getElementById("gobang");
container.addEventListener("click", _this.handleClick);
_this.ctx = container.getContext("2d");
_this.ctx.translate(70,70);
_this.drawCheckerboard();
},
computed:{
chessText(){
return this.whiteTurn ? '白棋' : '黑棋';
}
},
methods: {
drawCheckerboard() {
// 画棋盘
let _this = this;
_this.ctx.beginPath();
_this.ctx.fillStyle = "#fff";
_this.ctx.rect(0, 0, 450, 450);
_this.ctx.fill();
for (var i = 0; i < 15; i++) {
_this.ctx.beginPath();
_this.ctx.strokeStyle = "#D6D1D1";
_this.ctx.moveTo(15 + i * 30, 15); //垂直方向画15根线,相距30px;
_this.ctx.lineTo(15 + i * 30, 435);
_this.ctx.stroke();
_this.ctx.moveTo(15, 15 + i * 30); //水平方向画15根线,相距30px;棋盘为14*14;
_this.ctx.lineTo(435, 15 + i * 30);
_this.ctx.stroke();
_this.resultArr.push(new Array(15).fill(0));
}
_this.drawText();
},
drawChess(x, y) {
let _this = this;
let xLine = Math.round((x - 15) / 30); // 竖线第x条
let yLine = Math.round((y - 15) / 30); // 横线第y条
if(_this.resultArr[xLine][yLine] !== 0){
return;
}
let grd = _this.ctx.createRadialGradient(
xLine * 30 + 15,
yLine * 30 + 15,
4,
xLine * 30 + 15,
yLine * 30 + 15,
10
);
grd.addColorStop(0, _this.whiteTurn ? "#fff" : "#4c4c4c");
grd.addColorStop(1, _this.whiteTurn ? "#dadada" : "#000");
_this.ctx.beginPath();
_this.ctx.fillStyle = grd;
_this.ctx.arc(
xLine * 30 + 15,
yLine * 30 + 15,
10,
0,
2 * Math.PI,
false
);
_this.ctx.fill();
_this.ctx.closePath();
_this.setResultArr(xLine, yLine);
_this.checkResult(xLine, yLine);
},
setResultArr(m, n) {
let _this = this;
_this.resultArr[m][n] = _this.whiteTurn ? 1 : 2; // 白棋为1;黑棋为2
},
checkResult(m ,n){ // 判断是否有5子相连
let _this = this;
let checkStr = _this.whiteTurn ? CheckStrWhite : CheckStrBlack;
// 取出[m,n]横竖斜四条线的一维数组
let lineVertical = _this.resultArr[m].join('');
if(lineVertical.indexOf(checkStr) > -1){
_this.winGame = true;
return;
}
let lineHorizontal = [];
for(let i = 0; i<15; i++){
lineHorizontal.push(_this.resultArr[i][n]);
}
lineHorizontal = lineHorizontal.join('');
if(lineHorizontal.indexOf(checkStr) > -1){
_this.winGame = true;
return;
}
let line135 = [];
for(let j = 0; j < 15; j++){
if(m - j >= 0 && n - j >= 0){ // 左上角
line135.unshift(_this.resultArr[m - j][n -j]);
}
if(j > 0 && m + j < 15 && n + j < 15){ // 右下角
line135.push(_this.resultArr[m + j][n + j]);
}
}
line135 = line135.join('');
if(line135.indexOf(checkStr) > -1){
_this.winGame = true;
return;
}
let line45 = [];
for(let j = 0; j < 15; j++){
if(m + j < 15 && n - j >= 0){ // 右上角
line45.unshift(_this.resultArr[m + j][n -j]);
}
if(j > 0 && m - j >=0 && n + j < 15){ // 左下角
line45.push(_this.resultArr[m - j][n + j]);
}
}
line45 = line45.join('');
if(line45.indexOf(checkStr) > -1){
_this.winGame = true;
return;
}
},
drawText(){
let _this = this;
_this.ctx.clearRect(435 + 60, 0, 100, 70);
_this.ctx.fillStyle = "#fff";
_this.ctx.font="20px Arial";
_this.ctx.fillText('本轮:' + _this.chessText, 435 + 70, 35);
},
drawResult(){
let _this = this;
_this.ctx.fillStyle = "#ff2424";
_this.ctx.font="20px Arial";
_this.ctx.fillText(_this.chessText+'胜!', 435 + 70, 70);
},
handleClick(event) {
let x = event.offsetX - 70;
let y = event.offsetY - 70;
if (x < 15 || x > 435 || y < 15 || y > 435) {
// 点出界的
return;
}
this.drawChess(x, y);
if(this.winGame){
this.drawResult();
return;
}
this.whiteTurn = !this.whiteTurn;
this.drawText();
}
}
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
.gobang {
#gobang {
background: #2a4546;
}
}
</style>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
猜你喜欢
本篇文章带大家了解一下Angular中的独立组件,看看怎么在Angular中创建一个独立组件,怎么在独立组件中导入已有的模块,希望对大家有所帮助!
使用js删除javascript对象的某个属性的方法有3种,我们使用的了js的delete函数,下面是我对js删除对象属性的方法总结,是本人在项目中经过测试的。 js代码 script//定义一个对象varmyObject={username:zhangsan,password:123456,address:hubei};//方式一//de
本文实例为大家分享了JavaScript实现网页贪吃蛇游戏的具体代码,小编通过实际的案例向大家展示了操作过程,简单易懂,有需要的朋友可以参考了解看看,那么接下来就跟随小编的思路来往下学习吧,希望对大家学习或工作能有帮助。
这篇文章主要给大家分享的是JavaScript回调函数的相关内容,回调用于数组,计时器函数,promise,事件处理程序等中,是JavaScript学习中需要掌握的内容,对此本文分享给大家做个参考。另外,一些朋友对于同步和异步回调不是很理解,文中也有很详细的介绍,感兴趣的朋友就继续往下看吧。
随着组件的细化,就会遇到多组件状态共享的情况,今天我们介绍的是 vue.js 2.6 新增加的 Observable API ,通过使用这个 api 我们可以应对一些简单的跨组件数据状态共享的情况,感兴趣的可以了解一下
成为群英会员,开启智能安全云计算之旅
立即注册关注或联系群英网络
7x24小时售前:400-678-4567
7x24小时售后:0668-2555666
24小时QQ客服
群英微信公众号
CNNIC域名投诉举报处理平台
服务电话:010-58813000
服务邮箱:service@cnnic.cn
投诉与建议:0668-2555555
Copyright © QY Network Company Ltd. All Rights Reserved. 2003-2020 群英 版权所有
增值电信经营许可证 : B1.B2-20140078 ICP核准(ICP备案)粤ICP备09006778号 域名注册商资质 粤 D3.1-20240008