“2048”游戏网页版html+css+js

"2048"游戏网页版html+css+js

++别忘了请点个赞+收藏+关注支持一下博主喵!!!++

2048 游戏是一个非常流行的数字拼图游戏,玩家通过移动方块使相同数字的方块合并,最终达到 2048 或更高分数。本教程将详细介绍如何使用 HTML、CSS 和 JavaScript 创建一个简单的 2048 游戏网页。

项目结构如下:(懒得搭vue了)

2048-game/
├── index.html
├── styles.css
└── script.js

1. index.html

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"> <!-- 设置文档的字符编码为 UTF-8 -->
    <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- 使页面在移动设备上适配屏幕宽度 -->
    <title>2048 Game</title> <!-- 页面标题 -->
    <link rel="stylesheet" href="styles.css"> <!-- 引入外部 CSS 文件 -->
</head>
<body>
    <div class="game-container"> <!-- 游戏容器,用于包裹整个游戏界面 -->
        <div class="score-container">0</div> <!-- 分数显示区域 -->
        <div class="grid-container"> <!-- 网格容器,用于包裹 4x4 的游戏网格 -->
            <div class="grid-row"> <!-- 每一行的网格 -->
                <div class="grid-cell"></div> <!-- 每一个网格单元 -->
                <div class="grid-cell"></div>
                <div class="grid-cell"></div>
                <div class="grid-cell"></div>
            </div>
            <div class="grid-row">
                <div class="grid-cell"></div>
                <div class="grid-cell"></div>
                <div class="grid-cell"></div>
                <div class="grid-cell"></div>
            </div>
            <div class="grid-row">
                <div class="grid-cell"></div>
                <div class="grid-cell"></div>
                <div class="grid-cell"></div>
                <div class="grid-cell"></div>
            </div>
            <div class="grid-row">
                <div class="grid-cell"></div>
                <div class="grid-cell"></div>
                <div class="grid-cell"></div>
                <div class="grid-cell"></div>
            </div>
        </div>
        <button id="restart-button">Restart</button> <!-- 重新开始按钮 -->
    </div>
    <script src="script.js"></script> <!-- 引入外部 JavaScript 文件 -->
</body>
</html>

2. styles.css

css 复制代码
body {
    display: flex; /* 使用 Flexbox 布局 */
    justify-content: center; /* 水平居中 */
    align-items: center; /* 垂直居中 */
    height: 100vh; /* 占满整个视窗高度 */
    margin: 0; /* 移除默认外边距 */
    background-color: #faf8ef; /* 背景颜色 */
    font-family: Arial, sans-serif; /* 字体设置 */
}

.game-container {
    width: 500px; /* 容器宽度 */
    height: 500px; /* 容器高度 */
    position: relative; /* 相对定位 */
    background-color: #bbada0; /* 背景颜色 */
    border-radius: 10px; /* 圆角 */
    box-shadow: 5px 5px 15px rgba(0, 0, 0, 0.3); /* 阴影效果 */
}

.score-container {
    position: absolute; /* 绝对定位 */
    top: 10px; /* 距离顶部 10px */
    left: 10px; /* 距离左边 10px */
    background-color: #eee4da; /* 背景颜色 */
    padding: 10px; /* 内边距 */
    border-radius: 5px; /* 圆角 */
    font-size: 24px; /* 字体大小 */
    font-weight: bold; /* 加粗字体 */
}

.grid-container {
    width: 400px; /* 网格容器宽度 */
    height: 400px; /* 网格容器高度 */
    position: absolute; /* 绝对定位 */
    top: 50%; /* 距离顶部 50% */
    left: 50%; /* 距离左边 50% */
    transform: translate(-50%, -50%); /* 居中对齐 */
    display: grid; /* 使用 Grid 布局 */
    grid-template-columns: repeat(4, 100px); /* 4 列,每列 100px */
    grid-template-rows: repeat(4, 100px); /* 4 行,每行 100px */
    gap: 10px; /* 网格间距 */
}

.grid-cell {
    background-color: #cdc1b4; /* 背景颜色 */
    border-radius: 3px; /* 圆角 */
    display: flex; /* 使用 Flexbox 布局 */
    justify-content: center; /* 水平居中 */
    align-items: center; /* 垂直居中 */
    font-size: 32px; /* 字体大小 */
    font-weight: bold; /* 加粗字体 */
    color: #776e65; /* 文字颜色 */
}

/* 不同数字的方块样式 */
.grid-cell.number-2 { background-color: #eee4da; color: #776e65; }
.grid-cell.number-4 { background-color: #ede0c8; color: #776e65; }
.grid-cell.number-8 { background-color: #f2b179; color: #f9f6f2; }
.grid-cell.number-16 { background-color: #f59563; color: #f9f6f2; }
.grid-cell.number-32 { background-color: #f67c5f; color: #f9f6f2; }
.grid-cell.number-64 { background-color: #f65e3b; color: #f9f6f2; }
.grid-cell.number-128 { background-color: #edcf72; color: #f9f6f2; }
.grid-cell.number-256 { background-color: #edcc61; color: #f9f6f2; }
.grid-cell.number-512 { background-color: #edc850; color: #f9f6f2; }
.grid-cell.number-1024 { background-color: #edc53f; color: #f9f6f2; }
.grid-cell.number-2048 { background-color: #edc22e; color: #f9f6f2; }

#restart-button {
    position: absolute; /* 绝对定位 */
    bottom: 10px; /* 距离底部 10px */
    left: 50%; /* 距离左边 50% */
    transform: translateX(-50%); /* 水平居中 */
    padding: 10px 20px; /* 内边距 */
    background-color: #8f7a66; /* 背景颜色 */
    color: #f9f6f2; /* 文字颜色 */
    border: none; /* 无边框 */
    border-radius: 5px; /* 圆角 */
    cursor: pointer; /* 鼠标指针样式 */
    font-size: 18px; /* 字体大小 */
    font-weight: bold; /* 加粗字体 */
}

#restart-button:hover {
    background-color: #746655; /* 鼠标悬停时的背景颜色 */
}

3. 最难的script.js

javascript 复制代码
const grid = document.querySelector('.grid-container'); // 获取网格容器
const cells = document.querySelectorAll('.grid-cell'); // 获取所有网格单元
const scoreContainer = document.querySelector('.score-container'); // 获取分数显示区域
const restartButton = document.getElementById('restart-button'); // 获取重新开始按钮

let score = 0; // 初始化分数
let hasWon = false; // 标记是否已经赢得游戏

const matrix = [
    [0, 0, 0, 0], // 初始化 4x4 的矩阵
    [0, 0, 0, 0],
    [0, 0, 0, 0],
    [0, 0, 0, 0]
];

const winNumber = 2048; // 赢得游戏的目标数字

// 获取一个随机的空格子
function getRandomEmptyCell() {
    const emptyCells = []; // 存储所有空格子的坐标
    for (let i = 0; i < 4; i++) {
        for (let j = 0; j < 4; j++) {
            if (matrix[i][j] === 0) { // 如果格子为空
                emptyCells.push({ row: i, col: j }); // 将坐标加入空格子列表
            }
        }
    }
    if (emptyCells.length > 0) { // 如果有空格子
        const randomIndex = Math.floor(Math.random() * emptyCells.length); // 随机选择一个空格子
        return emptyCells[randomIndex];
    }
    return null; // 没有空格子返回 null
}

// 在随机选择的空格子中添加一个新方块(2 或 4)
function addRandomTile() {
    const cell = getRandomEmptyCell();
    if (cell) {
        const value = Math.random() < 0.9 ? 2 : 4; // 90% 的概率生成 2,10% 的概率生成 4
        matrix[cell.row][cell.col] = value; // 更新矩阵
        updateGrid(); // 更新网格显示
    }
}

// 更新 HTML 网格中的方块显示
function updateGrid() {
    cells.forEach((cell, index) => {
        const row = Math.floor(index / 4); // 计算当前单元格所在的行
        const col = index % 4; // 计算当前单元格所在的列
        const value = matrix[row][col]; // 获取矩阵中的值
        cell.textContent = value || ''; // 显示值,如果没有值则显示空字符串
        cell.classList.remove('number-2', 'number-4', 'number-8', 'number-16', 'number-32', 'number-64', 'number-128', 'number-256', 'number-512', 'number-1024', 'number-2048'); // 移除所有样式类
        if (value !== 0) { // 如果有值,添加对应的样式类
            cell.classList.add(`number-${value}`);
        }
    });
}

// 向上移动
function moveUp() {
    for (let col = 0; col < 4; col++) { // 遍历每一列
        let tempCol = []; // 临时存储非零值
        for (let row = 0; row < 4; row++) {
            if (matrix[row][col] !== 0) {
                tempCol.push(matrix[row][col]); // 将非零值加入临时列表
            }
        }
        tempCol = mergeTiles(tempCol); // 合并相同的值
        for (let row = 0; row < 4; row++) {
            matrix[row][col] = tempCol[row] || 0; // 更新矩阵
        }
    }
    addRandomTile(); // 添加新的方块
    checkGameOver(); // 检查游戏是否结束
}

// 向下移动
function moveDown() {
    for (let col = 0; col < 4; col++) { // 遍历每一列
        let tempCol = []; // 临时存储非零值
        for (let row = 3; row >= 0; row--) {
            if (matrix[row][col] !== 0) {
                tempCol.push(matrix[row][col]); // 将非零值加入临时列表
            }
        }
        tempCol = mergeTiles(tempCol); // 合并相同的值
        for (let row = 3; row >= 0; row--) {
            matrix[row][col] = tempCol[3 - row] || 0; // 更新矩阵
        }
    }
    addRandomTile(); // 添加新的方块
    checkGameOver(); // 检查游戏是否结束
}

// 向左移动
function moveLeft() {
    for (let row = 0; row < 4; row++) { // 遍历每一行
        let tempRow = []; // 临时存储非零值
        for (let col = 0; col < 4; col++) {
            if (matrix[row][col] !== 0) {
                tempRow.push(matrix[row][col]); // 将非零值加入临时列表
            }
        }
        tempRow = mergeTiles(tempRow); // 合并相同的值
        for (let col = 0; col < 4; col++) {
            matrix[row][col] = tempRow[col] || 0; // 更新矩阵
        }
    }
    addRandomTile(); // 添加新的方块
    checkGameOver(); // 检查游戏是否结束
}

// 向右移动
function moveRight() {
    for (let row = 0; row < 4; row++) { // 遍历每一行
        let tempRow = []; // 临时存储非零值
        for (let col = 3; col >= 0; col--) {
            if (matrix[row][col] !== 0) {
                tempRow.push(matrix[row][col]); // 将非零值加入临时列表
            }
        }
        tempRow = mergeTiles(tempRow); // 合并相同的值
        for (let col = 3; col >= 0; col--) {
            matrix[row][col] = tempRow[3 - col] || 0; // 更新矩阵
        }
    }
    addRandomTile(); // 添加新的方块
    checkGameOver(); // 检查游戏是否结束
}

// 合并相同的值
function mergeTiles(tiles) {
    for (let i = 0; i < tiles.length - 1; i++) {
        if (tiles[i] === tiles[i + 1]) { // 如果相邻的两个值相同
            tiles[i] *= 2; // 合并值
            tiles.splice(i + 1, 1); // 删除合并后的值
            score += tiles[i]; // 更新分数
            scoreContainer.textContent = score; // 更新分数显示
            if (tiles[i] === winNumber && !hasWon) { // 如果达到目标值且未赢过
                alert('You Win!'); // 提示胜利
                hasWon = true; // 标记已赢
            }
        }
    }
    while (tiles.length < 4) { // 确保列表长度为 4
        tiles.push(0);
    }
    return tiles;
}

// 检查游戏是否结束
function checkGameOver() {
    let gameOver = true; // 默认游戏结束
    for (let i = 0; i < 4; i++) {
        for (let j = 0; j < 4; j++) {
            if (matrix[i][j] === 0 || // 如果有空格子
                (i < 3 && matrix[i][j] === matrix[i + 1][j]) || // 或者有相邻的相同值
                (j < 3 && matrix[i][j] === matrix[i][j + 1])) {
                gameOver = false; // 游戏未结束
                break;
            }
        }
        if (!gameOver) break;
    }
    if (gameOver) {
        alert('Game Over!'); // 提示游戏结束
    }
}

// 重新开始游戏
function restartGame() {
    matrix.forEach(row => row.fill(0)); // 重置矩阵
    score = 0; // 重置分数
    hasWon = false; // 重置胜利标记
    scoreContainer.textContent = score; // 更新分数显示
    addRandomTile(); // 添加初始方块
    addRandomTile(); // 添加初始方块
    updateGrid(); // 更新网格显示
}

// 监听键盘事件
document.addEventListener('keydown', (event) => {
    switch (event.key) {
        case 'ArrowUp': // 上箭头
            moveUp();
            break;
        case 'ArrowDown': // 下箭头
            moveDown();
            break;
        case 'ArrowLeft': // 左箭头
            moveLeft();
            break;
        case 'ArrowRight': // 右箭头
            moveRight();
            break;
    }
});

// 监听重新开始按钮点击事件
restartButton.addEventListener('click', restartGame);

// 初始化游戏
restartGame();

++别忘了请点个赞+收藏+关注支持一下博主喵!!!++

++累了,水一下吧。。。。。。∗︎˚(* ˃̤൬˂̤ *)˚∗︎++

++gitee:++ 2048-game: html+css+js设计的一个2048游戏(网页)

相关推荐
雪峰11 分钟前
使用 Web Search 插件扩展 GitHub Copilot 问答
vscode·github·copilot
亿牛云爬虫专家15 分钟前
如何在Puppeteer中实现表单自动填写与提交:问卷调查
javascript·爬虫·爬虫代理·puppeteer·问卷调查·代理ip·表单
FIRE27 分钟前
uniapp小程序分享使用canvas自定义绘制 vue3
前端·小程序·uni-app
四喜花露水28 分钟前
vue elementui el-dropdown-item设置@click无效的解决方案
前端·vue.js·elementui
jokerest1231 小时前
web——sqliabs靶场——第五关——报错注入和布尔盲注
前端
焦糖酒1 小时前
终端应用开发沉思录
javascript·前端框架
谢尔登1 小时前
前端开发调试之 PC 端调试
开发语言·前端
每天吃饭的羊1 小时前
在循环中只set一次
开发语言·前端·javascript
_默_4 小时前
adminPage-vue3依赖DetailsModule版本说明:V1.2.1——1) - 新增span与labelSpan属性
前端·javascript·vue.js·npm·开源
也无晴也无风雨6 小时前
深入剖析输入URL按下回车,浏览器做了什么
前端·后端·计算机网络