Fork me on GitHub

谈谈前端实现五子棋游戏

frontend/talk-about-gobang-game/banner

闲来无事,记录下自己完成的五子棋,纯前端实现,使用到的知识点是canvas和类。运行的时候请使用谷歌浏览器哈➡️休闲游戏–五子棋😊

五子棋的下法我就不介绍了,下面讲下实现的几个点:

  • 实现人人对战
  • 实现悔棋功能
  • 实现撤消悔棋功能
  • 胜利提示功能

嗯,一步一步来讲解下,在下棋的时候,得有棋盘吧,我这里使用canvas进行绘制:

画棋盘

这里分为两种棋盘的表现,一种是看得见的,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

// 画出棋盘
drawChessBoard() {
const {options} = this;
const context = this.chessboard.getContext('2d');
const {count,padding,borderColor} = options.gobangStyle; // 传入棋盘格数,边距和边框颜色
this.chessboard.width = this.chessboard.height = padding * count;
context.strokeStyle = borderColor;

for(var i = 0; i < count; i++){
context.moveTo(15 + i * padding , 15);
context.lineTo(15 + i * padding , count * padding - 15);
context.stroke();
context.moveTo(15 , 15 + i * padding);
context.lineTo(count * padding - 15 , 15 + i * padding);
context.stroke();
}
}

画出的视觉上的棋盘效果如下:

frontend/talk-about-gobang-game/gobang-place

在画出棋盘之后,还是不能够下棋的,需要有一个看不见的棋盘来记录落子的位置,这里使用到矩阵的形式了:

1
2
3
4
5
6
7
8
9
10
11
12
13

// 初始棋盘矩阵
initChessboardMatrix() {
const {options} = this;
const checkerboard = [];
for(let x = 0; x < options.gobangStyle.count; x++){
checkerboard[x] = [];
for(let y = 0; y < options.gobangStyle.count; y++){
checkerboard[x][y] = 0;
}
}
this.checkerboard = checkerboard;
}

下棋

在棋盘准备好之后,就是刻画棋子了,无棋子怎么下棋呢?棋子要考虑到黑白两色的,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

// 刻画棋子
drawChessman(x,y,isBlack ){
const context = this.chessboard.getContext('2d');
context.beginPath();
context.arc(15 + x * 30, 15 + y * 30, 13, 0, 2 * Math.PI);// 画圆
context.closePath();
//渐变
var gradient = context.createRadialGradient(15 + x * 30 + 2, 15 + y * 30 - 2, 13, 15 + x * 30 + 2, 15 + y * 30 - 2, 0);
if(isBlack){ // 黑子
gradient.addColorStop(0,'#0a0a0a');
gradient.addColorStop(1,'#636766');
}else{ // 白子
gradient.addColorStop(0,'#d1d1d1');
gradient.addColorStop(1,'#f9f9f9');
}
context.fillStyle = gradient;
context.fill();
// 每次落子完成后都要判断下输赢
setTimeout(() => {
this.checkReferee(x,y,isBlack ? 1 : 2);
},0);
}

如何下去呢?上面已将打好基础了,在点击棋盘的时候,顺便记录下矩阵上点的位置,如(0,1),(3,1)等位置,然后将绘制好的相应棋子填充在相应的位置就可以了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

// 落子
listenDownChessman() {
console.log('落子');
this.chessboard.onclick = event => {
// 获取棋子的位置(x,y) => (0,1)
let {
offsetX: x,
offsetY: y
} = event;
x = Math.round((x-15) / this.lattice.width);
y = Math.round((y-15) / this.lattice.height);
// console.log(x , y)
// 空的位置才可以落子
if(this.checkerboard[x][y] !== undefined && Object.is(this.checkerboard[x][y] , 0)){
// 落子后更新矩阵,切换角色,并且记录
this.checkerboard[x][y] = this.role;
// 刻画棋子
this.drawChessman(x,y,Object.is(this.role , 1));
// 落子完之后有可能悔棋之后落子,这种情况下应该重置历史记录
this.history.length = this.currentStep;
this.history.push({
x,
y,
role: this.role
});
// 保存坐标,切换角色和保存快照
this.currentStep++;
this.role = Object.is(this.role , 1) ? 2 : 1;
}
}
}

悔棋

实现悔棋,也就是撤销画布的棋子,这里采取重新绘制覆盖已有的棋子方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

// 销毁棋子
minusStep(x,y) {
let {options} = this;
const {count} = options.gobangStyle;
const context = this.chessboard.getContext('2d');
context.clearRect(x * 30, y * 30, 30, 30);
// 重画该圆周围的格子,对边角的格式进行特殊的处理
if(x<=0 && y <=0){
this.fixchessboard(15,15,15,30,15,15,30,15);
}else if(x>=count-1 && y<=0){
this.fixchessboard(count*30-15,15,count*30-30,15,count*30-15,15,count*30-15,30);
}else if(y>=count-1 && x <=0){
this.fixchessboard(15,count*30-15,15,count*30-30,15,count*30-15,30,count*30-15);
}else if(x>=count-1 && y >= count-1){
this.fixchessboard(count*30-15,count*30-15,count*30-30,count*30-15,count*30-15,count*30-15,count*30-15,count*30-30);
}else if(x <=0 && y >0 && y <count-1){
this.fixchessboard(15,30*y+15,30,30*y+15,15,30*y,15,30*y+30);
}else if(y <= 0 && x > 0 && x < count-1){
this.fixchessboard(x*30+15,15,x*30+15,30,x*30,15,x*30+30,15);
}else if(x>=count-1 && y >0 && y < count-1){
this.fixchessboard(count*30-15,y*30+15,count*30-30,y*30+15,count*30-15,y*30,count*30-15,y*30+30);
}else if(y>=count-1 && x > 0 && x < count-1){
this.fixchessboard(x*30+15,count*30-15,x*30+15,count*30-30,x*30,count*30-15,x*30+30,count*30-15);
}else{
this.fixchessboard(15+x*30,y*30,15+x*30,y*30 + 30,x*30,y*30+15,(x+1)*30,y*30+15)
}

}

// 修补删除后的棋盘
fixchessboard (a , b, c , d , e , f , g , h){
const context = this.chessboard.getContext('2d');
context.beginPath();
context.moveTo(a , b);
context.lineTo(c , d);
context.moveTo(e, f);
context.lineTo(g , h);
context.stroke();
}

在进行简单的功能开发之后,就可以简单的玩下小游戏了,放出gif demo 图:

frontend/talk-about-gobang-game/gobang_demo

如有要改善的点,欢迎留言改进。相关的详细代码,请前往我的仓库gobang部分内容。如果能留下一颗小星星就更好了。

frontend/talk-about-gobang-game/qiaoba

<-- 本文已结束  感谢您阅读 -->
客官,且步,赏一个呗 (@ ~ @)