在本教程中,我们将学习如何使用HTML5的<canvas>元素来创建一个简单的五子棋游戏。我们将涵盖棋盘的绘制、棋子的放置、鼠标点击事件处理以及检查获胜条件的基本逻辑。
环境准备
确保你的开发环境支持HTML5。你只需要一个文本编辑器来编写代码,以及一个支持HTML5的现代浏览器来运行游戏。
创建HTML结构
首先,我们创建一个基本的HTML文档结构,并添加一个<canvas>元素用于绘制五子棋游戏。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>五子棋游戏</title>
<style>
body {
text-align: center;
margin: 0;
}
canvas {
vertical-align: top;
}
.dialog {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, .45);
display: none;
}
.dialog.open {
display: block;
}
.dialog .alert {
background-color: rgba(255, 255, 255, .9);
border-radius: 5px;
box-shadow: 1px 2px 8px rgba(0, 0, 0, .5);
width: 250px;
height: 160px;
left: 50%;
top: 50%;
position: absolute;
text-align: center;
margin: -80px 0 0 -125px;
}
.dialog button {
border: none;
background-color: rgb(68, 183, 58);
color: #fff;
padding: 10px 20px;
border-radius: 4px;
outline: none;
transition: all 300ms;
-webkit-transition: all 300ms;
}
.dialog button:hover {
background-color: rgba(68, 183, 58, .9);
}
.dialog button:active {
box-shadow: 0 2px 6px rgba(0, 0, 0, .5);
}
.dialog p {
margin: 0 0 16px 0;
}
</style>
</head>
<body>
<canvas id="game" width="480" height="480"></canvas>
<div id="dialog" class="dialog">
<div class="alert">
<h4 id="title">恭喜!</h4>
<p id="winner"></p>
<button onclick="restart()">重新开始</button>
</div>
</div>
<script>
// JavaScript代码将在这里编写
</script>
</body>
</html>
绘制棋盘和棋子
我们将使用JavaScript来获取<canvas>元素的上下文,并绘制一个15x15的棋盘。
const canvas = document.getElementById('game');
const ctx = canvas.getContext('2d');
const cellSize = 30; // 每个格子的大小
const boardSize = 15; // 棋盘的大小,15x15
// 绘制棋盘
function drawBoard() {
ctx.lineWidth = 1;
ctx.strokeStyle = 'black';
for (let i = 0; i < boardSize; i++) {
ctx.beginPath();
ctx.moveTo(cellSize + i * cellSize, cellSize);
ctx.lineTo(cellSize + i * cellSize, cellSize * boardSize);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(cellSize, cellSize + i * cellSize);
ctx.lineTo(cellSize * boardSize, cellSize + i * cellSize);
ctx.stroke();
}
}
// 绘制棋子
function drawPiece(x, y, size, color) {
ctx.beginPath();
ctx.arc(x * size + size, y * size + size, size / 2.5, 0, 2 * Math.PI);
ctx.fillStyle = color;
ctx.fill();
ctx.stroke();
}
游戏逻辑
我们将创建一些变量来维护当前玩家、游戏棋盘的状态以及游戏是否结束的标志。
let currentPlayer = 'black'; // 当前玩家
let gameOver = false; // 游戏是否结束
let gameBoard = Array(boardSize).fill().map(() => Array(boardSize).fill(null)); // 游戏棋盘
let draw = 0; // 判断是否和棋
检查获胜条件
实现一个函数来检查是否有玩家获胜。这涉及到检查所有行、列和对角线。
// 遍历所有行、列和斜线
function traverseDiagonals(matrix, player, fn) {
const m = matrix.length;
const n = matrix[0].length;
// 遍历所有行
for (let i = 0; i < m; i++) {
let diagonal = [];
for (let j = 0; j < n; j++) {
diagonal.push(matrix[i][j]);
}
if (fn(diagonal, player)) return player;
}
// 遍历所有列
for (let i = 0; i < m; i++) {
let diagonal = [];
for (let j = 0; j < n; j++) {
diagonal.push(matrix[j][i]);
}
if (fn(diagonal, player)) return player;
}
// 遍历右上角所有对角线包括从左上到右下对角线
for (let i = 0; i < m; i++) {
let diagonal = [];
for (let j = 0; j < i + 1; j++) {
diagonal.push(matrix[j][n + j - 1 - i]);
}
if (fn(diagonal, player)) return player;
}
// 遍历左下角所有对角线不包括从左上到右下对角线
for (let i = 1; i < m; i++) {
let diagonal = [];
for (let j = i; j < n; j++) {
diagonal.push(matrix[j][j - i]);
}
if (fn(diagonal, player)) return player;
}
// 遍历左上角所有对角线包括从右上到左下对角线
for (let i = m - 1; i >= 0; i--) {
let diagonal = [];
for (let j = 0; j < n - i; j++) {
diagonal.push(matrix[j][n - j - 1 - i]);
}
if (fn(diagonal, player)) return player;
}
// 遍历右下角所有对角线不包括从右上到左下对角线
for (let i = 1; i < m; i++) {
let diagonal = [];
for (let j = i; j < n; j++) {
diagonal.push(matrix[j][n - 1 - j + i]);
}
if (fn(diagonal, player)) return player;
}
}
// 检查是赢棋方
function checkLine(line, player) {
for (let i = 0; i < 11; i++) {
if (line[i] === player && line[i + 1] === player &&
line[i + 2] === player && line[i + 3] === player &&
line[i + 4] === player) {
return true;
}
}
}
事件处理
为<canvas>元素添加点击事件监听器,以处理玩家的落子操作。
function handleMouseClick(event) {
if (gameOver) return;
const rect = canvas.getBoundingClientRect();
const x = Math.floor((event.clientX - rect.left - cellSize / 2) / cellSize);
const y = Math.floor((event.clientY - rect.top - cellSize / 2) / cellSize);
let winner;
if (x >= 0 && y >= 0 && x < boardSize & y < boardSize && gameBoard[y][x] === null) {
gameBoard[y][x] = currentPlayer;
drawPiece(x, y, cellSize, currentPlayer === 'black' ? 'black' : 'white');
winner = traverseDiagonals(gameBoard, currentPlayer, function (line, player) {
if (checkLine(line, player)) return player
});
// 检查是否获胜
if (winner) {
gameOver = true;
openDialog(winner);
return;
}
// 检查是否和棋
if (++draw === boardSize * boardSize) {
gameOver = true;
openDialog();
return;
}
// 切换玩家
currentPlayer = currentPlayer === 'black' ? 'white' : 'black';
}
}
canvas.addEventListener('click', handleMouseClick);
获胜对话框
当玩家获胜时,显示一个对话框来通知玩家。
// 显示获胜方
function openDialog(winner) {
document.getElementById('winner').innerText = winner === 'black' ? '黑方获胜' : winner === 'white' ? '白方获胜' : '势均力敌';
document.getElementById('dialog').className = 'dialog open';
}
初始化游戏棋盘和棋子
- 初始化游戏棋盘和棋子,并通过
start()函数设置游戏的初始状态。 - 通过
restart()函数,玩家可以重置游戏,清除棋盘并重新开始对局。
// 开始游戏
function start() {
currentPlayer = 'black';
gameOver = false;
gameBoard = Array(boardSize).fill().map(() => Array(boardSize).fill(null));
draw = 0;
drawBoard();
}
// 重新开始
function restart() {
document.getElementById('dialog').className = 'dialog';
ctx.clearRect(0, 0, canvas.width, canvas.height); // 清除整个画布
start();
}
结语
在本教程中,我们创建了一个基本的五子棋游戏,包括棋盘的绘制、棋子的放置以及获胜条件的检查。这个示例提供了一个起点,你可以在此基础上添加更多特性,比如计分系统、玩家轮流的自动化等。