当前位置: 首页 > news >正文

2048小游戏实现

2048小游戏实现

将创建一个完整的2048小游戏,包含游戏核心逻辑和美观的用户界面。
在这里插入图片描述

设计思路

  • 4x4网格布局
  • 响应式设计,适配不同设备
  • 分数显示和最高分记录
  • 键盘控制(方向键)和触摸滑动支持
  • 游戏状态提示(胜利/失败)

完整代码实现

<!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><style>* {margin: 0;padding: 0;box-sizing: border-box;font-family: 'Arial Rounded MT Bold', 'Arial', sans-serif;}body {background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);min-height: 100vh;display: flex;justify-content: center;align-items: center;padding: 20px;}.container {max-width: 500px;width: 100%;}.header {display: flex;justify-content: space-between;align-items: center;margin-bottom: 20px;}h1 {color: #776e65;font-size: 60px;font-weight: 700;text-shadow: 2px 2px 4px rgba(0,0,0,0.1);}.scores-container {display: flex;gap: 10px;}.score-box {background: #bbada0;color: white;padding: 10px 15px;border-radius: 6px;text-align: center;min-width: 100px;position: relative;}.score-box:after {content: attr(data-label);display: block;font-size: 12px;font-weight: bold;text-transform: uppercase;color: #eee4da;}.score {font-size: 22px;font-weight: bold;}.game-intro {display: flex;justify-content: space-between;align-items: center;margin-bottom: 20px;}.game-explanation {color: #776e65;font-size: 16px;line-height: 1.4;max-width: 250px;}.restart-button {background: #8f7a66;color: #f9f6f2;border: none;border-radius: 6px;padding: 12px 20px;font-size: 18px;font-weight: bold;cursor: pointer;transition: all 0.2s;}.restart-button:hover {background: #7c6b5a;transform: scale(1.05);}.game-container {background: #bbada0;border-radius: 6px;padding: 15px;position: relative;box-shadow: 0 10px 30px rgba(0,0,0,0.15);}.grid-container {display: grid;grid-template-columns: repeat(4, 1fr);grid-gap: 10px;background: rgba(238, 228, 218, 0.35);border-radius: 6px;padding: 10px;position: relative;touch-action: none;}.grid-cell {background: rgba(238, 228, 218, 0.35);border-radius: 4px;height: 0;padding-bottom: 100%;}.tile-container {position: absolute;top: 0;left: 0;right: 0;bottom: 0;padding: 10px;}.tile {position: absolute;width: calc(25% - 12.5px);height: calc(25% - 12.5px);border-radius: 4px;display: flex;justify-content: center;align-items: center;font-size: 35px;font-weight: bold;transition: all 0.15s ease;z-index: 10;}.tile-2 { background: #eee4da; color: #776e65; }.tile-4 { background: #ede0c8; color: #776e65; }.tile-8 { background: #f2b179; color: #f9f6f2; }.tile-16 { background: #f59563; color: #f9f6f2; }.tile-32 { background: #f67c5f; color: #f9f6f2; }.tile-64 { background: #f65e3b; color: #f9f6f2; }.tile-128 { background: #edcf72; color: #f9f6f2; font-size: 30px; }.tile-256 { background: #edcc61; color: #f9f6f2; font-size: 30px; }.tile-512 { background: #edc850; color: #f9f6f2; font-size: 30px; }.tile-1024 { background: #edc53f; color: #f9f6f2; font-size: 25px; }.tile-2048 { background: #edc22e; color: #f9f6f2; font-size: 25px; }.tile-super { background: #3c3a32; color: #f9f6f2; font-size: 20px; }.game-message {display: none;position: absolute;top: 0;left: 0;right: 0;bottom: 0;background: rgba(238, 228, 218, 0.73);border-radius: 6px;flex-direction: column;justify-content: center;align-items: center;z-index: 100;}.game-message.game-won, .game-message.game-over {display: flex;}.game-message p {font-size: 50px;font-weight: bold;color: #776e65;margin-bottom: 20px;}.instructions {margin-top: 30px;color: #776e65;text-align: center;line-height: 1.6;font-size: 16px;}@media (max-width: 520px) {.header {flex-direction: column;align-items: flex-start;}h1 {font-size: 50px;margin-bottom: 15px;}.game-intro {flex-direction: column;align-items: flex-start;gap: 15px;}.tile {font-size: 24px;}.tile-128, .tile-256, .tile-512 {font-size: 22px;}.tile-1024, .tile-2048 {font-size: 18px;}}</style>
</head>
<body><div class="container"><div class="header"><h1>2048</h1><div class="scores-container"><div class="score-box" data-label="分数"><div class="score" id="score">0</div></div><div class="score-box" data-label="最高分"><div class="score" id="best-score">0</div></div></div></div><div class="game-intro"><div class="game-explanation">合并相同数字的方块,得到2048方块!</div><button class="restart-button" id="restart-button">新游戏</button></div><div class="game-container"><div class="grid-container"><!-- 4x4网格 --><div class="grid-cell"></div><div class="grid-cell"></div><div class="grid-cell"></div><div class="grid-cell"></div><div class="grid-cell"></div><div class="grid-cell"></div><div class="grid-cell"></div><div class="grid-cell"></div><div class="grid-cell"></div><div class="grid-cell"></div><div class="grid-cell"></div><div class="grid-cell"></div><div class="grid-cell"></div><div class="grid-cell"></div><div class="grid-cell"></div><div class="grid-cell"></div><div class="tile-container" id="tile-container"></div><div class="game-message" id="game-message"><p id="message-text"></p><button class="restart-button" id="keep-playing-button">继续游戏</button></div></div></div><div class="instructions"><p><strong>游戏指南:</strong>使用键盘方向键(↑, ↓, ←, →)或触摸屏滑动移动方块。当两个相同数字的方块碰撞时,它们会合并成它们的和!</p></div></div><script>document.addEventListener('DOMContentLoaded', () => {// 游戏常量const GRID_SIZE = 4;const CELL_SIZE = 20; // 百分比const CELL_GAP = 2;   // 百分比// 游戏状态let grid = [];let score = 0;let bestScore = localStorage.getItem('bestScore') || 0;let gameOver = false;let gameWon = false;// DOM元素const gridContainer = document.querySelector('.grid-container');const tileContainer = document.getElementById('tile-container');const scoreDisplay = document.getElementById('score');const bestScoreDisplay = document.getElementById('best-score');const restartButton = document.getElementById('restart-button');const gameMessage = document.getElementById('game-message');const messageText = document.getElementById('message-text');const keepPlayingButton = document.getElementById('keep-playing-button');// 初始化游戏function initGame() {// 重置游戏状态grid = Array(GRID_SIZE).fill().map(() => Array(GRID_SIZE).fill(0));tileContainer.innerHTML = '';score = 0;gameOver = false;gameWon = false;// 更新UIupdateScore();gameMessage.className = 'game-message';// 添加初始方块addRandomTile();addRandomTile();// 渲染游戏板render();}// 添加随机方块function addRandomTile() {const emptyCells = [];// 查找所有空格子for (let row = 0; row < GRID_SIZE; row++) {for (let col = 0; col < GRID_SIZE; col++) {if (grid[row][col] === 0) {emptyCells.push({ row, col });}}}// 如果有空格子,随机选择一个并添加2或4if (emptyCells.length > 0) {const randomCell = emptyCells[Math.floor(Math.random() * emptyCells.length)];grid[randomCell.row][randomCell.col] = Math.random() < 0.9 ? 2 : 4;}}// 渲染游戏板function render() {tileContainer.innerHTML = '';for (let row = 0; row < GRID_SIZE; row++) {for (let col = 0; col < GRID_SIZE; col++) {const value = grid[row][col];if (value !== 0) {const tile = document.createElement('div');tile.className = `tile tile-${value}`;tile.textContent = value;// 设置位置tile.style.left = `${col * (CELL_SIZE + CELL_GAP) + CELL_GAP}%`;tile.style.top = `${row * (CELL_SIZE + CELL_GAP) + CELL_GAP}%`;tileContainer.appendChild(tile);}}}}// 移动方块function move(direction) {if (gameOver) return;let moved = false;let newGrid = JSON.parse(JSON.stringify(grid));// 根据方向处理移动switch (direction) {case 'up':for (let col = 0; col < GRID_SIZE; col++) {const column = [];for (let row = 0; row < GRID_SIZE; row++) {if (newGrid[row][col] !== 0) {column.push(newGrid[row][col]);}}// 合并相同数字for (let i = 0; i < column.length - 1; i++) {if (column[i] === column[i + 1]) {column[i] *= 2;score += column[i];column.splice(i + 1, 1);}}// 更新列for (let row = 0; row < GRID_SIZE; row++) {newGrid[row][col] = row < column.length ? column[row] : 0;}}break;case 'down':for (let col = 0; col < GRID_SIZE; col++) {const column = [];for (let row = GRID_SIZE - 1; row >= 0; row--) {if (newGrid[row][col] !== 0) {column.push(newGrid[row][col]);}}// 合并相同数字for (let i = 0; i < column.length - 1; i++) {if (column[i] === column[i + 1]) {column[i] *= 2;score += column[i];column.splice(i + 1, 1);}}// 更新列for (let row = GRID_SIZE - 1; row >= 0; row--) {newGrid[row][col] = (GRID_SIZE - 1 - row) < column.length ? column[GRID_SIZE - 1 - row] : 0;}}break;case 'left':for (let row = 0; row < GRID_SIZE; row++) {const rowData = [];for (let col = 0; col < GRID_SIZE; col++) {if (newGrid[row][col] !== 0) {rowData.push(newGrid[row][col]);}}// 合并相同数字for (let i = 0; i < rowData.length - 1; i++) {if (rowData[i] === rowData[i + 1]) {rowData[i] *= 2;score += rowData[i];rowData.splice(i + 1, 1);}}// 更新行for (let col = 0; col < GRID_SIZE; col++) {newGrid[row][col] = col < rowData.length ? rowData[col] : 0;}}break;case 'right':for (let row = 0; row < GRID_SIZE; row++) {const rowData = [];for (let col = GRID_SIZE - 1; col >= 0; col--) {if (newGrid[row][col] !== 0) {rowData.push(newGrid[row][col]);}}// 合并相同数字for (let i = 0; i < rowData.length - 1; i++) {if (rowData[i] === rowData[i + 1]) {rowData[i] *= 2;score += rowData[i];rowData.splice(i + 1, 1);}}// 更新行for (let col = GRID_SIZE - 1; col >= 0; col--) {newGrid[row][col] = (GRID_SIZE - 1 - col) < rowData.length ? rowData[GRID_SIZE - 1 - col] : 0;}}break;}// 检查是否有移动moved = JSON.stringify(grid) !== JSON.stringify(newGrid);if (moved) {grid = newGrid;addRandomTile();updateScore();render();checkGameStatus();}}// 检查游戏状态function checkGameStatus() {// 检查是否达到2048for (let row = 0; row < GRID_SIZE; row++) {for (let col = 0; col < GRID_SIZE; col++) {if (grid[row][col] === 2048 && !gameWon) {gameWon = true;messageText.textContent = '恭喜你赢了!';gameMessage.className = 'game-message game-won';}}}// 检查是否有空格子for (let row = 0; row < GRID_SIZE; row++) {for (let col = 0; col < GRID_SIZE; col++) {if (grid[row][col] === 0) {return;}}}// 检查是否可以移动for (let row = 0; row < GRID_SIZE; row++) {for (let col = 0; col < GRID_SIZE; col++) {const value = grid[row][col];// 检查右侧if (col < GRID_SIZE - 1 && grid[row][col + 1] === value) {return;}// 检查下方if (row < GRID_SIZE - 1 && grid[row + 1][col] === value) {return;}}}// 如果没有空格子且无法移动,游戏结束gameOver = true;messageText.textContent = '游戏结束!';gameMessage.className = 'game-message game-over';}// 更新分数function updateScore() {scoreDisplay.textContent = score;// 更新最高分if (score > bestScore) {bestScore = score;localStorage.setItem('bestScore', bestScore);}bestScoreDisplay.textContent = bestScore;}// 键盘控制document.addEventListener('keydown', (event) => {switch (event.key) {case 'ArrowUp':move('up');break;case 'ArrowDown':move('down');break;case 'ArrowLeft':move('left');break;case 'ArrowRight':move('right');break;}});// 触摸控制let touchStartX, touchStartY;gridContainer.addEventListener('touchstart', (event) => {touchStartX = event.touches[0].clientX;touchStartY = event.touches[0].clientY;event.preventDefault();});gridContainer.addEventListener('touchmove', (event) => {event.preventDefault();});gridContainer.addEventListener('touchend', (event) => {if (!touchStartX || !touchStartY) return;const touchEndX = event.changedTouches[0].clientX;const touchEndY = event.changedTouches[0].clientY;const dx = touchEndX - touchStartX;const dy = touchEndY - touchStartY;// 确定主要移动方向if (Math.abs(dx) > Math.abs(dy)) {// 水平移动if (dx > 0) {move('right');} else {move('left');}} else {// 垂直移动if (dy > 0) {move('down');} else {move('up');}}// 重置触摸起点touchStartX = null;touchStartY = null;});// 按钮事件restartButton.addEventListener('click', initGame);keepPlayingButton.addEventListener('click', () => {gameMessage.className = 'game-message';});// 初始化游戏initGame();bestScoreDisplay.textContent = bestScore;});</script>
</body>
</html>

功能说明

  1. 游戏核心功能

    • 4x4网格布局
    • 方块移动和合并逻辑
    • 随机生成新方块(90%概率生成2,10%概率生成4)
    • 分数计算(每次合并累加得分)
    • 最高分记录(使用localStorage保存)
  2. 游戏状态

    • 胜利条件:创建出2048方块
    • 失败条件:棋盘填满且无法继续合并
    • 游戏结束后可重新开始
  3. 控制方式

    • 键盘方向键(↑, ↓, ←, →)
    • 触摸屏滑动操作(支持移动设备)
  4. UI设计

    • 响应式布局,适配不同屏幕尺寸
    • 不同数字的方块有不同的颜色
    • 分数显示和最高分记录
    • 游戏状态提示(胜利/失败)

使用说明

  1. 使用键盘方向键或触摸屏滑动来移动方块
  2. 当两个相同数字的方块碰撞时,它们会合并成它们的和
  3. 每次移动后,会在空白位置随机生成一个新的方块(2或4)
  4. 游戏目标:创建出一个2048方块
  5. 当无法再移动方块时,游戏结束

这个2048小游戏包含了所有核心功能,界面美观,操作流畅,适合在桌面和移动设备上使用。

http://www.lryc.cn/news/581702.html

相关文章:

  • 线性代数--AI数学基础复习
  • 深度学习6(多分类+交叉熵损失原理+手写数字识别案例TensorFlow)
  • Chunking-free RAG
  • Web-API-day2 间歇函数setInterval与事件监听addEvenListener
  • 【Note】《Kafka: The Definitive Guide》第四章:Kafka 消费者全面解析:如何从 Kafka 高效读取消息
  • Apache Spark 4.0:将大数据分析提升到新的水平
  • A O P
  • 金融级B端页面风控设计:操作留痕与异常预警的可视化方案
  • 深度学习篇---深度学习常见的应用场景
  • 容声W60以光水离子科技实现食材“主动养鲜”
  • [Qt] visual studio code 安装 Qt插件
  • FastAPI + Tortoise-ORM + Aerich 实现数据库迁移管理(MySQL 实践)
  • 深度学习 必然用到的 线性代数知识
  • 嵌入式 数据结构学习(五) 栈与队列的实现与应用
  • React Ref 指南:原理、实现与实践
  • 【PyTorch】PyTorch中torch.nn模块的卷积层
  • 零基础,使用Idea工具写一个邮件报警程序
  • Solidity——什么是状态变量
  • 计算机网络:(七)网络层(上)网络层中重要的概念与网际协议 IP
  • Kafka “假死“现象深度解析与解决方案
  • UI前端大数据可视化进阶:交互式仪表盘的设计与应用
  • 数据驱动实时市场动态监测:让商业决策跑赢时间
  • 【LeetCode 热题 100】240. 搜索二维矩阵 II——排除法
  • 黑马点评系列问题之实战篇02短信登录 利用资料中的mysql语句创建数据表时报错
  • 关于 栈帧变化完整流程图(函数嵌套)
  • Java 双亲委派机制笔记
  • QML 使用QtObject定义私有变量
  • 基于Flask和机器学习开发的米其林餐厅数据可视化平台
  • 单片机:STM32F103的开发环境搭建
  • 单片机物联网应用中的 Pogopin、串口与外围模组通信技术解析