首页 > 其他分享 >基于 HTML5 Canvas 制作一个精美的 2048 小游戏--day2

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

时间:2025-01-18 21:30:53浏览次数:3  
标签:Canvas gridSize targetRow day2 2048 let board targetCol return

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

  1. 改善颜色方案:使用更温馨的颜色组合。
  2. 添加动画效果:为方块的移动和合并添加渐变效果。
  3. 优化分数显示:在分数增加时使用动画效果。

以下是改进后的代码示例:
在这里插入图片描述

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);
}  

动画效果

  1. 移动与合并动画:我们可以使用 CSS 的 transition 属性来增加方块变化过程中的平滑感。这种效果可以在 drawTile 函数中体现,例如更改方块的背景色时使用过渡效果。
  2. 分数动画:我们可以在分数增加时使用淡入或渐变效果,以增加分数的视觉吸引力。这可以通过添加相关的 CSS 来实现,例如淡入特效,可以通过 JavaScript 调整 scoreDisplay 的样式。

标签:Canvas,gridSize,targetRow,day2,2048,let,board,targetCol,return
From: https://blog.csdn.net/wxdzuishaui/article/details/145232995

相关文章

  • 2024春秋杯冬季赛day2writeup_cyi
     解题过程miscWeevil'sWhisper操作内容:筛选http流,一开始就把马上传了搜索可知这是weevely的webshell这篇讲的很详细了https://xz.aliyun.com/t/11246?time__1311=Cq0xRD0Q0QD%3DdGNeeeqk75YitmczLbD#toc-5拿了这篇的解密脚本https://blog.csdn.net/m0_74091653/artic......
  • Java入门学习Day2
    目录(一)Java01:Java帝国的诞生(二)Java02:特性与优势(三)Java03:三大版本(四)Java04:JDK、JRE、JVM(五)Java05:安装开发环境(六)Java06:HelloWorld详解(七)Java07:编译型和解释型(八)Java08:使用IDEA开发(一)Java01:Java帝国的诞生先附上学习的链接:b站狂神说Java入门011995年诞生三高......
  • day2
    1.css引入方式行内样式:内嵌样式:eg:点击查看代码<html><head><title>新闻</title><style>h1{color:brown;}</style></head><body><imgsrc="55a5bd46d103204cbde397e6ae7......
  • [CF2048F] Kevin and Math Class 题解
    注意到这里有个区间的\(b_i\)最小。我们考虑每个\(b_i\)作为最小的时候各操作几次。显然每个\(b_i\)的【操作区间】更长是不劣的。于是这些个\(b_i\)是可以打成笛卡尔树,进行DP。想到这一点,DP便是不难的了。定义\(f_{i,j}\)为以\(i\)为根的子树内,最优操作后最大值......
  • canvas默认画布的尺寸是多大?怎样设置才能不会变形?
    canvas默认画布的尺寸是300像素×150像素。这一默认尺寸可以通过在HTML中设置canvas元素的width和height属性来自定义。为了确保canvas画布在设置尺寸后不会变形,应当遵循以下步骤:直接在canvas元素上设置尺寸:在HTML中定义canvas元素时,可以直接在标签内设置width和height属性,如<......
  • 使用canvas画出一个矩形
    在HTML5中,<canvas>元素可以用于在网页上绘制图形。以下是一个简单的示例,展示如何使用JavaScript和<canvas>元素来绘制一个矩形:<!DOCTYPEhtml><html><body><canvasid="myCanvas"width="500"height="500"style="border:1pxsolid#d3d3d3......
  • Cesium结合html2canvas进行截图
    按照html2canvas正常操作是可以进行截图操作的,但是发现没有截取到地球,发现cesium内也需要进行设置需要先安装html2canvas引入cesium创建视图时也需要添加对应参数preserveDrawingBuffer上代码!!constviewer=newCesium.Viewer("cesiumContainer",{contextOptio......
  • 解决htmlcanvas遇到图片较多的复杂首页,保存截图特别慢的问题
    先说问题:在首页新增个保存部分dom截图的功能,但首页加载接口较多,图片跨域加载比较慢,而htmlcanvas保存截图前会将整个页面渲染一遍,这就导致有些图片没加载完成,dom渲染不然,canvas保存就会延迟四五秒之久 解决方法:增加这个参数ignoreElements:function(element){......
  • 解决 IDEA 编译报错:Error:(2048,1024) java: 找不到符号
    摘要在使用IntelliJIDEA开发Java项目时,“找不到符号”(Cannotfindsymbol)是一种常见的编译错误。本文将从初学者的角度,详细分析这一问题的可能原因,提供排查步骤,并附上代码示例,帮助你快速解决问题。引言“找不到符号”是Java编译器的一种错误提示,通常发生在......
  • 十分钟写作Day2 1.14
    前言这是十分钟写作的第二天,也是假期的第二天。回应张老师的号召,今天的题目为《养起一团火》,表达我对\(2.5\)班美好友谊和青春的赞美。正文养一团火握在手心中,伤心的时候低头看看它,它能以微笑回应,给你无尽的前行力量。在春风暖暖中让它盘旋在我手心中,感受生命力量;在夏日炎......