之前的canvas小游戏系列欢迎大家戳:
在布局上,五子棋相比那些目标是随机运动的游戏,实现起来相对简单许多,思路也很清晰,总共分为:
(1)画棋盘;
(2)监听点击事件画黑白棋子;
(3)每次落子之后判断是否有5子相连,有则赢。
最复杂的恐怕就是如何判断五子棋赢了,那么就先从简单的开始,画个棋盘吧~
1、画棋盘
棋盘很简单,我们画个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,没错,就是记录落子的。
2、监听点击事件画黑白棋子
好了,我们在获取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
-
-
}
3、检查五子棋输赢结果
输赢结果怎么判断?肉眼看去,无非就是以当前落子为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>
转载:https://blog.csdn.net/denglouhen/article/details/116485952