为了使 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 的样式。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |