李优秀 发表于 4 小时前

基于 HTML5 Canvas 制作一个精致的 2048 小游戏--day2

为了使 2048 游戏的设计更加美观和用户友好,我们可以进行以下几项优化:

[*]改善颜色方案:使用更温馨的颜色组合。
[*]添加动画效果:为方块的移动和归并添加渐变效果。
[*]优化分数显示:在分数增长时使用动画效果。
以下是改进后的代码示例:
https://i-blog.csdnimg.cn/direct/77ee489b5a154c36a12e4bd722d10bc9.png
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;
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 === 0) {
      emptyCells.push({ r, c });
      }
    }
}

if (emptyCells.length) {
    const { r, c } = emptyCells;
    board = 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 !== 0 && board === board;
}

function moveUp() {
let moved = false;
for (let c = 0; c < gridSize; c++) {
    for (let r = 1; r < gridSize; r++) {
      if (board !== 0) {
      let targetRow = r;
      while (targetRow > 0 && board === 0) {
          board = board;
          board = 0;
          targetRow--;
          moved = true;
      }
      if (targetRow > 0 && canMergeTiles(targetRow - 1, c, targetRow, c)) {
          board *= 2;
          score += board;
          board = 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 !== 0) {
      let targetRow = r;
      while (targetRow < gridSize - 1 && board === 0) {
          board = board;
          board = 0;
          targetRow++;
          moved = true;
      }
      if (
          targetRow < gridSize - 1 &&
          canMergeTiles(targetRow + 1, c, targetRow, c)
      ) {
          board *= 2;
          score += board;
          board = 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 !== 0) {
      let targetCol = c;
      while (targetCol > 0 && board === 0) {
          board = board;
          board = 0;
          targetCol--;
          moved = true;
      }
      if (targetCol > 0 && canMergeTiles(r, targetCol - 1, r, targetCol)) {
          board *= 2;
          score += board;
          board = 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 !== 0) {
      let targetCol = c;
      while (targetCol < gridSize - 1 && board === 0) {
          board = board;
          board = 0;
          targetCol++;
          moved = true;
      }
      if (
          targetCol < gridSize - 1 &&
          canMergeTiles(r, targetCol + 1, r, targetCol)
      ) {
          board *= 2;
          score += board;
          board = 0;
          moved = true;
      }
      }
    }
}
return moved;
}

function checkGameOver() {
for (let r = 0; r < gridSize; r++) {
    for (let c = 0; c < gridSize; c++) {
      if (board === 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 的样式。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 基于 HTML5 Canvas 制作一个精致的 2048 小游戏--day2