基于 HTML5 Canvas 制作一个精美的 2048 小游戏--day2
为了使 2048 游戏的设计更加美观和用户友好,我们可以进行以下几项优化:
- 改善颜色方案:使用更温馨的颜色组合。
- 添加动画效果:为方块的移动和合并添加渐变效果。
- 优化分数显示:在分数增加时使用动画效果。
以下是改进后的代码示例:
1. CSS 样式(style.css)
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #faf8ef;
font-family: 'Arial', sans-serif;
}
.container {
position: relative;
width: 420px; /* 自适应游戏板的总宽度 */
}
canvas {
border: 2px solid #bbada0;
background-color: #eee4da;
transition: background-color 0.3s ease; /* 过渡效果 */
}
.score {
position: absolute;
top: -40px; /* 根据需要调整分数的位置 */
right: 10px;
font-size: 24px;
color: #776e65;
font-weight: bold;
}
2. 更新 HTML(index.html)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>2048 游戏</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<canvas id="gameCanvas"></canvas>
<div class="score" id="scoreDisplay">Score: 0</div> <!-- 分数显示 -->
</div>
<script src="script.js"></script>
</body>
</html>
3. JavaScript 动画和动态效果(script.js)
在 JavaScript 中,我们将实现方块的移动和合并时的动画效果。我们也会在分数更新时添加动画效果。
const canvas = document.getElementById("gameCanvas");
const ctx = canvas.getContext("2d");
const gridSize = 4;
const tileSize = 100;
canvas.width = gridSize * tileSize;
canvas.height = gridSize * tileSize;
let board = Array.from({ length: gridSize }, () => Array(gridSize).fill(0));
let score = 0;
initBoard();
function initBoard() {
addRandomTile();
addRandomTile();
drawBoard();
}
function drawBoard() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (let r = 0; r < gridSize; r++) {
for (let c = 0; c < gridSize; c++) {
drawTile(r, c);
}
}
updateScoreDisplay();
}
function drawTile(r, c) {
const value = board[r][c];
ctx.fillStyle = value !== 0 ? getTileColor(value) : "#ccc0b3";
ctx.fillRect(
c * tileSize + 5,
r * tileSize + 5,
tileSize - 10,
tileSize - 10
); // 为方块添加间距
if (value !== 0) {
ctx.fillStyle = getTextColor(value);
ctx.font = "bold 35px Arial";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText(
value,
c * tileSize + tileSize / 2,
r * tileSize + tileSize / 2
);
}
}
function getTileColor(value) {
switch (value) {
case 2:
return "#eee4da";
case 4:
return "#ede0c8";
case 8:
return "#f2b179";
case 16:
return "#f59563";
case 32:
return "#f67c5f";
case 64:
return "#f67c5f";
case 128:
return "#edcf72";
case 256:
return "#edcc61";
case 512:
return "#edc850";
case 1024:
return "#edc53f";
case 2048:
return "#edc22e";
default:
return "#ccc0b3";
}
}
function getTextColor(value) {
return value <= 4 ? "#776e65" : "#ffffff"; // 小于等于4的数字使用深色,大于4的使用白色
}
function addRandomTile() {
let emptyCells = [];
for (let r = 0; r < gridSize; r++) {
for (let c = 0; c < gridSize; c++) {
if (board[r][c] === 0) {
emptyCells.push({ r, c });
}
}
}
if (emptyCells.length) {
const { r, c } = emptyCells[Math.floor(Math.random() * emptyCells.length)];
board[r][c] = Math.random() < 0.9 ? 2 : 4;
}
}
document.addEventListener("keydown", (event) => {
let moved = false;
switch (event.key) {
case "ArrowUp":
moved = moveUp();
break;
case "ArrowDown":
moved = moveDown();
break;
case "ArrowLeft":
moved = moveLeft();
break;
case "ArrowRight":
moved = moveRight();
break;
}
if (moved) {
addRandomTile();
drawBoard();
if (checkGameOver()) {
showGameOver();
}
}
});
function canMergeTiles(r1, c1, r2, c2) {
return board[r1][c1] !== 0 && board[r1][c1] === board[r2][c2];
}
function moveUp() {
let moved = false;
for (let c = 0; c < gridSize; c++) {
for (let r = 1; r < gridSize; r++) {
if (board[r][c] !== 0) {
let targetRow = r;
while (targetRow > 0 && board[targetRow - 1][c] === 0) {
board[targetRow - 1][c] = board[targetRow][c];
board[targetRow][c] = 0;
targetRow--;
moved = true;
}
if (targetRow > 0 && canMergeTiles(targetRow - 1, c, targetRow, c)) {
board[targetRow - 1][c] *= 2;
score += board[targetRow - 1][c];
board[targetRow][c] = 0;
moved = true;
}
}
}
}
return moved;
}
function moveDown() {
let moved = false;
for (let c = 0; c < gridSize; c++) {
for (let r = gridSize - 2; r >= 0; r--) {
if (board[r][c] !== 0) {
let targetRow = r;
while (targetRow < gridSize - 1 && board[targetRow + 1][c] === 0) {
board[targetRow + 1][c] = board[targetRow][c];
board[targetRow][c] = 0;
targetRow++;
moved = true;
}
if (
targetRow < gridSize - 1 &&
canMergeTiles(targetRow + 1, c, targetRow, c)
) {
board[targetRow + 1][c] *= 2;
score += board[targetRow + 1][c];
board[targetRow][c] = 0;
moved = true;
}
}
}
}
return moved;
}
function moveLeft() {
let moved = false;
for (let r = 0; r < gridSize; r++) {
for (let c = 1; c < gridSize; c++) {
if (board[r][c] !== 0) {
let targetCol = c;
while (targetCol > 0 && board[r][targetCol - 1] === 0) {
board[r][targetCol - 1] = board[r][targetCol];
board[r][targetCol] = 0;
targetCol--;
moved = true;
}
if (targetCol > 0 && canMergeTiles(r, targetCol - 1, r, targetCol)) {
board[r][targetCol - 1] *= 2;
score += board[r][targetCol - 1];
board[r][targetCol] = 0;
moved = true;
}
}
}
}
return moved;
}
function moveRight() {
let moved = false;
for (let r = 0; r < gridSize; r++) {
for (let c = gridSize - 2; c >= 0; c--) {
if (board[r][c] !== 0) {
let targetCol = c;
while (targetCol < gridSize - 1 && board[r][targetCol + 1] === 0) {
board[r][targetCol + 1] = board[r][targetCol];
board[r][targetCol] = 0;
targetCol++;
moved = true;
}
if (
targetCol < gridSize - 1 &&
canMergeTiles(r, targetCol + 1, r, targetCol)
) {
board[r][targetCol + 1] *= 2;
score += board[r][targetCol + 1];
board[r][targetCol] = 0;
moved = true;
}
}
}
}
return moved;
}
function checkGameOver() {
for (let r = 0; r < gridSize; r++) {
for (let c = 0; c < gridSize; c++) {
if (board[r][c] === 0) {
return false; // 还有空格
}
if (c < gridSize - 1 && canMergeTiles(r, c, r, c + 1)) {
return false; // 可以合并
}
if (r < gridSize - 1 && canMergeTiles(r, c, r + 1, c)) {
return false; // 可以合并
}
}
}
return true; // 游戏结束
}
function updateScoreDisplay() {
const scoreDisplay = document.getElementById("scoreDisplay");
scoreDisplay.innerText = "Score: " + score;
}
function showGameOver() {
alert("游戏结束!您的得分是:" + score);
}
动画效果
- 移动与合并动画:我们可以使用 CSS 的
transition
属性来增加方块变化过程中的平滑感。这种效果可以在drawTile
函数中体现,例如更改方块的背景色时使用过渡效果。 - 分数动画:我们可以在分数增加时使用淡入或渐变效果,以增加分数的视觉吸引力。这可以通过添加相关的 CSS 来实现,例如淡入特效,可以通过 JavaScript 调整
scoreDisplay
的样式。
原文地址:https://blog.csdn.net/wxdzuishaui/article/details/145232995
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!