vue+canvas 实现围棋棋盘,棋盘每行每列有数字和字母,用canvas画的棋子要求真实,实现落子功能,悔棋功能,悔棋功能能够准确的回到上一步(把棋子覆盖),具体代码,每一行代码有具体注释
时间: 2024-05-22 21:15:20 浏览: 95
<template>
<div class="board">
<canvas ref="canvas" @click="placeStone"></canvas>
</div>
</template>
<script>
export default {
data() {
return {
rows: 19, // 棋盘行数
cols: 19, // 棋盘列数
gridWidth: 30, // 棋盘格子宽度
boardMargin: 50, // 棋盘边距
boardSize: 580, // 棋盘大小
boardColor: "#EBCB8B", // 棋盘颜色
stoneRadius: 13, // 棋子半径
stoneColor: "#000000", // 棋子颜色
stoneSpacing: 0.8, // 棋子之间的间隔
lastX: -1, // 上一个落子的x坐标
lastY: -1, // 上一个落子的y坐标
lastColor: "", // 上一个落子的颜色
board: [], // 棋盘矩阵
history: [], // 落子历史记录
};
},
mounted() {
this.initBoard();
this.drawBoard();
},
methods: {
// 初始化棋盘矩阵
initBoard() {
for (let i = 0; i < this.rows; i++) {
this.board[i] = [];
for (let j = 0; j < this.cols; j++) {
this.board[i][j] = "";
}
}
},
// 绘制棋盘
drawBoard() {
const canvas = this.$refs.canvas;
const ctx = canvas.getContext("2d");
// 设置画布尺寸
canvas.width = this.boardSize + this.boardMargin * 2;
canvas.height = this.boardSize + this.boardMargin * 2;
// 绘制棋盘背景
ctx.fillStyle = this.boardColor;
ctx.fillRect(0, 0, canvas.width, canvas.height);
// 绘制棋盘线条
ctx.strokeStyle = "#000000";
ctx.lineWidth = 1;
ctx.beginPath();
for (let i = 0; i < this.rows; i++) {
ctx.moveTo(this.boardMargin, this.boardMargin + i * this.gridWidth);
ctx.lineTo(
this.boardMargin + this.gridWidth * (this.rows - 1),
this.boardMargin + i * this.gridWidth
);
ctx.moveTo(this.boardMargin + i * this.gridWidth, this.boardMargin);
ctx.lineTo(
this.boardMargin + i * this.gridWidth,
this.boardMargin + this.gridWidth * (this.cols - 1)
);
}
ctx.stroke();
// 绘制棋盘数字和字母
ctx.fillStyle = "#000000";
ctx.font = "14px Arial";
for (let i = 0; i < this.rows; i++) {
ctx.fillText(
String.fromCharCode(65 + i),
this.boardMargin - 14,
this.boardMargin + i * this.gridWidth + 6
);
ctx.fillText(
i + 1,
this.boardMargin + i * this.gridWidth - 4,
this.boardMargin - 8
);
}
},
// 落子
placeStone(e) {
const canvas = this.$refs.canvas;
const ctx = canvas.getContext("2d");
// 获取落子坐标
const x = e.offsetX - this.boardMargin;
const y = e.offsetY - this.boardMargin;
const i = Math.floor(x / this.gridWidth);
const j = Math.floor(y / this.gridWidth);
// 判断落子是否合法
if (this.board[i][j] !== "") {
return;
}
// 绘制棋子
ctx.beginPath();
ctx.fillStyle = this.lastColor === "black" ? "white" : "black";
ctx.arc(
this.boardMargin + i * this.gridWidth,
this.boardMargin + j * this.gridWidth,
this.stoneRadius,
0,
2 * Math.PI
);
ctx.fill();
// 保存落子历史记录
this.history.push({
x: i,
y: j,
color: this.lastColor === "black" ? "white" : "black",
});
// 更新棋盘矩阵
this.board[i][j] = this.lastColor === "black" ? "white" : "black";
// 更新上一个落子的坐标和颜色
this.lastX = i;
this.lastY = j;
this.lastColor = this.lastColor === "black" ? "white" : "black";
},
// 悔棋
undo() {
const canvas = this.$refs.canvas;
const ctx = canvas.getContext("2d");
// 获取上一个落子的坐标和颜色
const last = this.history.pop();
const x = last.x;
const y = last.y;
const color = last.color;
// 清除棋子
ctx.beginPath();
ctx.fillStyle = this.boardColor;
ctx.arc(
this.boardMargin + x * this.gridWidth,
this.boardMargin + y * this.gridWidth,
this.stoneRadius + this.stoneSpacing,
0,
2 * Math.PI
);
ctx.fill();
// 更新棋盘矩阵
this.board[x][y] = "";
// 更新上一个落子的坐标和颜色
this.lastX = x;
this.lastY = y;
this.lastColor = color;
},
},
};
</script>
<style>
.board {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #F0D9B5;
}
canvas {
border: 1px solid #000000;
}
</style>
阅读全文