HTML5+JavaScript实现消消乐游戏
HTML5+JavaScript实现消消乐游戏
点击两个相邻的方块来交换它们位置。
如果交换后形成三个或更多相同图案的方块连成一线,这些方块会被消除。
消除后,上方的方块会下落填补空缺,顶部会生成新的方块。
每消除一个方块得10分。例如,如果一次消除了4个方块,玩家将得到40分。
运行效果如下图:
源码如下:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>基础消消乐游戏 - Emoji版</title>
<style>
body {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
background-color: #f0f0f0;
font-family: Arial, sans-serif;
}
#gameContainer {
display: flex;
flex-direction: column;
align-items: center;
}
canvas {
border: 2px solid #000;
margin-bottom: 10px;
}
#scoreDisplay {
font-size: 24px;
margin-bottom: 10px;
}
</style>
</head>
<body>
<div id="gameContainer">
<div id="scoreDisplay">分数: 0</div>
<canvas id="gameCanvas" width="400" height="400"></canvas>
</div>
<script>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const scoreDisplay = document.getElementById('scoreDisplay');
const GRID_SIZE = 8;
const CELL_SIZE = canvas.width / GRID_SIZE;
const EMOJIS = ['☮', '⚜', '♾ ', '☯', '⚛', '✳'];
let grid = [];
let selectedCell = null;
let score = 0;
function initGrid() {
for (let i = 0; i < GRID_SIZE; i++) {
grid[i] = [];
for (let j = 0; j < GRID_SIZE; j++) {
grid[i][j] = EMOJIS[Math.floor(Math.random() * EMOJIS.length)];
}
}
}
function drawGrid() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.font = `${CELL_SIZE * 0.8}px Arial`;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
for (let i = 0; i < GRID_SIZE; i++) {
for (let j = 0; j < GRID_SIZE; j++) {
ctx.fillText(
grid[i][j],
i * CELL_SIZE + CELL_SIZE / 2,
j * CELL_SIZE + CELL_SIZE / 2
);
}
}
if (selectedCell) {
ctx.strokeStyle = 'black';
ctx.lineWidth = 2;
ctx.strokeRect(
selectedCell.x * CELL_SIZE,
selectedCell.y * CELL_SIZE,
CELL_SIZE,
CELL_SIZE
);
}
}
function checkMatches() {
let matched = [];
// 检查水平匹配
for (let j = 0; j < GRID_SIZE; j++) {
let streak = 1;
for (let i = 1; i < GRID_SIZE; i++) {
if (grid[i][j] === grid[i-1][j]) {
streak++;
} else {
if (streak >= 3) {
for (let k = i - streak; k < i; k++) {
matched.push({x: k, y: j});
}
}
streak = 1;
}
}
if (streak >= 3) {
for (let k = GRID_SIZE - streak; k < GRID_SIZE; k++) {
matched.push({x: k, y: j});
}
}
}
// 检查垂直匹配
for (let i = 0; i < GRID_SIZE; i++) {
let streak = 1;
for (let j = 1; j < GRID_SIZE; j++) {
if (grid[i][j] === grid[i][j-1]) {
streak++;
} else {
if (streak >= 3) {
for (let k = j - streak; k < j; k++) {
matched.push({x: i, y: k});
}
}
streak = 1;
}
}
if (streak >= 3) {
for (let k = GRID_SIZE - streak; k < GRID_SIZE; k++) {
matched.push({x: i, y: k});
}
}
}
return matched;
}
function removeMatches(matches) {
matches.forEach(cell => {
grid[cell.x][cell.y] = null;
});
//updateScore(matches.length);
}
function updateScore(matchCount) {
score += matchCount * 10;
scoreDisplay.textContent = `分数: ${score}`;
}
function fillBlanks() {
for (let i = 0; i < GRID_SIZE; i++) {
let blanks = 0;
for (let j = GRID_SIZE - 1; j >= 0; j--) {
if (!grid[i][j]) {
blanks++;
} else if (blanks > 0) {
grid[i][j + blanks] = grid[i][j];
grid[i][j] = null;
}
}
for (let j = 0; j < blanks; j++) {
grid[i][j] = EMOJIS[Math.floor(Math.random() * EMOJIS.length)];
}
}
}
function swapCells(cell1, cell2) {
const temp = grid[cell1.x][cell1.y];
grid[cell1.x][cell1.y] = grid[cell2.x][cell2.y];
grid[cell2.x][cell2.y] = temp;
}
canvas.addEventListener('click', (event) => {
const rect = canvas.getBoundingClientRect();
const x = Math.floor((event.clientX - rect.left) / CELL_SIZE);
const y = Math.floor((event.clientY - rect.top) / CELL_SIZE);
if (selectedCell) {
if ((Math.abs(selectedCell.x - x) === 1 && selectedCell.y === y) ||
(Math.abs(selectedCell.y - y) === 1 && selectedCell.x === x)) {
swapCells(selectedCell, {x, y});
let matches = checkMatches();
if (matches.length === 0) {
swapCells(selectedCell, {x, y});
} else {
let totalMatches = 0;
while (matches.length > 0) {
totalMatches += matches.length;
removeMatches(matches);
fillBlanks();
matches = checkMatches();
}
updateScore(totalMatches); // 在所有匹配处理完后更新分数
}
}
selectedCell = null;
} else {
selectedCell = {x, y};
}
drawGrid();
});
function gameLoop() {
drawGrid();
requestAnimationFrame(gameLoop);
}
initGrid();
gameLoop();
</script>
</body>
</html>