- 作者:老汪软件技巧
- 发表时间:2024-12-03 15:12
- 浏览量:
ctx.lineTo(200, 200)
循环boardSize次代表着一共有多少条线,是从最上方和最左边开始绘制,从(0,0)点开始绘制到(边长,0)一条直线,因为起始点y坐标没有改变所以绘制的都是竖线;那么相反的X坐标不变绘制的就是横线。不过从上面代码可以看出,我们不是从(0,0)点开始的,目的是不让棋盘完全占满整个canvas画布,留有一定的边距。
上图为循环第一次绘制的线段
3.实现落子棋盘绘制完成之后就开始实现“下棋”的功能了。其实实现原理就是给canvas画布绑定一个点击函数,每点击一次就绘制一个棋子,但需要注意的是要判断当前位置是否已经有棋子,而且要确保棋子的位置正好能落在棋盘线段的交汇处,不能是任意位置都能落子。
实现落子的功能的时候,如果我们单纯的从canvas画图角度考虑可能就走了弯路了。我们应该更好的转化数据的处理。一个完整的棋盘共30行,每一行包含了30个交汇处,我们就可以将这个棋盘转换成一个二维数组,数组中的每一个元素就相当于一个位置,只需要判断落子的那个元素是否有值就可以了。
this.board = Array.from({ length: this.boardSize }, () => Array(this.boardSize).fill(null));
如果猛地看不懂这段代码,问一下MarsCode,详细的解释了这段代码的含义。其实就是根据刚才的思路分析,初始化了一个二维数组,每个元素的初始值为null。
const rect = event.target.getBoundingClientRect();
const x = event.clientX - rect.left;
const y = event.clientY - rect.top;
const row = Math.floor(y / this.cellSize);
const col = Math.floor(x / this.cellSize);
获取了触发事件的目标元素(canvas 元素)的边界矩形,getBoundingClientRect() 方法返回一个 DOMRect 对象,包含了元素的位置和大小信息。
const x = event.clientX - rect.left;:这行代码计算了鼠标点击位置相对于 canvas 元素左边缘的水平距离。
const y = event.clientY - ;:这行代码计算了鼠标点击位置相对于 canvas 元素上边缘的垂直距离。
Math.floor(x / this.cellSize) 方法计算鼠标位置在第几个完整的线段交汇处,确保棋子位置落在交汇中心。
currentPlayer: 'black', // 当前玩家
placeStone(row, col, ctx) {
this.board[row][col] = this.currentPlayer;
ctx.beginPath();
ctx.arc(col * this.cellSize + this.cellSize / 2, row * this.cellSize + this.cellSize / 2, this.cellSize / 3, 0, 2 * Math.PI);
ctx.fillStyle = this.currentPlayer;
ctx.fill();
},
如果落子成功就将二维数组对应位置的数值改变,currentPlayer代表当前玩家黑色方或白色方。棋子就是绘制一个圆圈,填充黑色或白色即可。落子之前我们还要进行一些必要的判断,判断当前位置是否有棋子,判断是否有玩家已经获胜,不满足上述的两个条件才能调用这个绘制棋子的方法。
if (this.board[row][col] === null) {
this.placeStone(row, col, ctx);
if (this.checkWin(row, col)) {
alert(`${this.currentPlayer} wins!`);
this.initBoard();
this.drawBoard(ctx);
} else {
this.currentPlayer = this.currentPlayer === 'black' ? 'white' : 'black';
}
}
checkWin方法就是用来判断是否有玩家获胜。判断是否胜利的标准是在水平、垂直、两条对角线方向是否有连续的并且为同色的五颗棋子。
checkWin(row, col) {
const directions = [
{ dx: 1, dy: 0 }, // 水平
{ dx: 0, dy: 1 }, // 垂直
{ dx: 1, dy: 1 }, // 对角线 \
{ dx: 1, dy: -1 } // 对角线 /
];
for (const { dx, dy } of directions) {
let count = 1;
for (let i = 1; i < 5; i++) {
const r = row + dy * i;
const c = col + dx * i;
if (r >= 0 && r < this.boardSize && c >= 0 && c < this.boardSize && this.board[r][c] === this.currentPlayer) {
count++;
} else {
break;
}
}
for (let i = 1; i < 5; i++) {
const r = row - dy * i;
const c = col - dx * i;
if (r >= 0 && r < this.boardSize && c >= 0 && c < this.boardSize && this.board[r][c] === this.currentPlayer) {
count++;
} else {
break;
}
}
if (count >= 5) {
return true;
}
}
return false;
}
count初始值为1,每遇到一个同色的便++,如果最终count大于等于5就证明有五颗连续的棋子,返回true即为胜利。如果胜利之后需要重置一下棋盘,清除掉之前绘制的棋子。
最后加一些提示性的东西,一个简易的五子棋小游戏就制作完成了。
<div class="game">
<h1>Welcome to Go Game!h1>
<div><span class="playerTips">{{currentPlayer==='black'? '请黑方玩家落子' : '请白方玩家落子'}}span>div>
<canvas id="chessBoard" width="800" height="800">canvas>
div>
结语
在本文中,我们详细探讨了如何使用Canvas元素来创建一个简单而富有挑战性的五子棋小游戏。从基础的Canvas绘图操作,到五子棋的逻辑实现,再到用户交互的设计,我们一步步构建了这个小游戏。希望本文能够帮助读者更好地理解Canvas在小游戏开发中的应用,同时也能够激发大家对游戏编程的兴趣和热情。
在整个小游戏的开发过程中,MarsCode AI也是为我提供了极大地便利。MarsCode AI提供了智能补全功能,在编写代码时,它能够根据上下文自动补全代码片段,减少了重复劳动和错误输入的可能性。在五子棋游戏的开发中,这一功能使得开发者能够更专注于游戏逻辑的实现,而无需花费过多时间在代码编写上。除此之外,代码生成、优化到补全、预测,它都能够胜任。这使得开发者在编程时能够更加得心应手,提高开发效率。
静Yu 正在“豆包MarsCode AI 红人创造营”中借助 AI 工具创作精彩内容,请帮TA投上一票吧! …
每日投票还能参与抽奖哦,快来领取你的专属福利。