首页 > 其他分享 >HTML实现2048小游戏

HTML实现2048小游戏

时间:2024-08-18 09:52:23浏览次数:13  
标签:case tiles HTML color 2048 width 小游戏 currentIndex tile

游戏概述

 

实现一个基本的2048游戏涉及综合运用HTML、CSS和JavaScript这三种关键技术。

 

HTML用于构建游戏的结构框架,包括游戏容器、网格布局以及可能的用户交互元素(如按钮或得分显示)。

 

CSS则负责美化游戏界面,通过样式表定义网格的样式、瓷砖的外观、动画效果以及整体布局的视觉呈现。

 

JavaScript则是游戏逻辑的核心,它处理用户的输入(如键盘事件监听),控制游戏状态的更新(如瓷砖的移动和合并),以及动态地更新DOM以反映游戏状态的变化。

 

通过这三者的紧密协作,可以创建出一个既美观又富有挑战性的2048游戏。

 

使用工具

 

本篇文章有用到GPT代码更正,国内可稳定使用,感兴趣的大佬可以试试。

 

传送门:ChatGPT-4o


 

实现步骤

 

 

HTML结构

代码部分:

<div id="gameContainer">
    <div id="score">Score: 0</div>
    <div id="gridContainer"></div>
    <div id="gameOverContainer">
        <div id="gameOver">Game Over!</div>
        <button id="restartButton">Restart</button>
    </div>
</div>

 

解释:

  • gameContainer: 包含整个游戏的容器。
  • score: 显示当前分数。
  • gridContainer: 游戏的主要区域,包含瓷砖。
  • gameOverContainer: 游戏结束时显示的消息和重启按钮。

 


 

CSS样式

 

代码部分:

body {
    text-align: center;
    margin-top: 50px;
    font-family: Arial, sans-serif;
    background-color: #f0f0f0;
}

#gridContainer {
    width: 360px;
    height: 360px;
    border: 1px solid #8b8b8b;
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    grid-gap: 5px;
    background-color: #dcdcdc;
    padding: 10px;
}

.tile {
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: 36px;
    font-weight: bold;
    border-radius: 6px;
    width: 80px;
    height: 80px;
    color: #fff;
}

 

解释:

 

  • body: 设置页面的基本样式,包括字体、背景颜色和对齐方式。
  • gridContainer: 使用 CSS Grid 布局创建了一个 4x4 的网格,定义了网格的宽度、高度以及瓷砖之间的间距。
  • .tile: 定义了瓷砖的样式,包括大小、颜色和字体。

 


 

JavaScript逻辑

 

初始化

 

function init() {
    score = 0;
    gameOverFlag = false;
    updateScore();
    gameOverContainer.style.display = "none";
    resetGrid();
    tiles = Array(width * width).fill(null);
    addTile();
    addTile();
    drawTiles();
}

解释:

  • 初始化游戏状态:重置分数和游戏结束标志。
  • resetGrid(): 清空现有的网格。
  • addTile(): 添加两个初始瓷砖。
  • drawTiles(): 绘制当前的瓷砖状态。

 

 

 

添加瓷砖

 

function addTile() {
    const emptyTiles = tiles.map((tile, index) => tile === null ? index : null).filter(index => index !== null);

    if (emptyTiles.length > 0) {
        const randomIndex = emptyTiles[Math.floor(Math.random() * emptyTiles.length)];
        tiles[randomIndex] = Math.random() < 0.9 ? 2 : 4;
    }
}

 

解释:

  • 查找空位置:创建一个包含所有空位置索引的数组。
  • 随机添加:在空位置随机添加一个值为 2 或 4 的瓷砖。

 

 

绘制瓷砖

 

function drawTiles() {
    resetGrid();
    tiles.forEach(tile => {
        const tileElement = document.createElement("div");
        tileElement.classList.add("tile");
        if (tile !== null) {
            tileElement.textContent = tile;
            tileElement.classList.add(`tile-${tile}`);
        }
        gridContainer.appendChild(tileElement);
    });
}

解释:

 

  • 清空网格:每次重新绘制时清空网格。
  • 创建瓷砖元素:为每个瓷砖创建一个新的 div 元素并设置其样式和内容。

 

 

 

移动逻辑

 

function move(direction) {
    if (gameOverFlag) return;
    let hasChanged = false;

    const moveTile = (currentIndex, newIndex) => {
        if (tiles[newIndex] === null) {
            tiles[newIndex] = tiles[currentIndex];
            tiles[currentIndex] = null;
            hasChanged = true;
        } else if (tiles[newIndex] === tiles[currentIndex]) {
            tiles[newIndex] *= 2;
            tiles[currentIndex] = null;
            score += tiles[newIndex];
            hasChanged = true;
        }
    };

    // Define moveUp, moveDown, moveLeft, moveRight

    switch (direction) {
        case "up":
            moveUp();
            break;
        case "down":
            moveDown();
            break;
        case "left":
            moveLeft();
            break;
        case "right":
            moveRight();
            break;
    }

    if (hasChanged) {
        addTile();
        drawTiles();
        updateScore();
        checkGameOver();
    }
}

解释:

 

  • 检查变动:检测移动是否改变了网格。
  • 移动函数:定义不同方向的移动逻辑,合并相同的瓷砖。

 

 

 

检查游戏结束

代码部分:

 

function checkGameOver() {
    if (!tiles.includes(null) && !checkMove()) {
        gameOverFlag = true;
        gameOverContainer.style.display = "block";
        restartButton.addEventListener("click", restart, { once: true });
    }
}

 

解释:

  • 游戏结束条件:当没有空格且不能移动时,游戏结束。
  • 显示游戏结束信息:并提供重启按钮。

 

 

重启游戏

function restart() {
    init();
}

重新初始化游戏:调用 init() 函数,重置游戏状态。

 

 

事件监听

document.addEventListener("keydown", event => {
    switch (event.key) {
        case "ArrowUp":
        case "w":
            move("up");
            break;
        case "ArrowDown":
        case "s":
            move("down");
            break;
        case "ArrowLeft":
        case "a":
            move("left");
            break;
        case "ArrowRight":
        case "d":
            move("right");
            break;
    }
});
  • 键盘事件:监听方向键和 WASD 键来移动瓷砖。

 


 

运行界面:

 

d7a5f6905ea24856b904f350387c249c.png

 

 

 以下是完整代码:

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>2048 Game</title>
    <style>
        body {
            text-align: center;
            margin-top: 50px;
            font-family: Arial, sans-serif;
            background-color: #f0f0f0;
        }

        h1 {
            font-size: 50px;
            color: #333;
        }

        #gameContainer {
            margin-top: 20px;
            display: inline-block;
        }

        #score {
            font-size: 24px;
            margin-bottom: 10px;
            color: #333;
        }

        #gridContainer {
            width: 360px;
            height: 360px;
            border: 1px solid #8b8b8b;
            display: grid;
            grid-template-columns: repeat(4, 1fr);
            grid-gap: 5px;
            background-color: #dcdcdc;
            padding: 10px;
        }

        .tile {
            display: flex;
            justify-content: center;
            align-items: center;
            font-size: 36px;
            font-weight: bold;
            border-radius: 6px;
            width: 80px;
            height: 80px;
            color: #fff;
        }

        .tile-2 { background-color: #f78c6b; }
        .tile-4 { background-color: #f7b26b; }
        .tile-8 { background-color: #f7d06b; }
        .tile-16 { background-color: #f4f76b; }
        .tile-32 { background-color: #a3f76b; }
        .tile-64 { background-color: #6bf7c4; }
        .tile-128 { background-color: #6baff7; }
        .tile-256 { background-color: #a26bf7; }
        .tile-512 { background-color: #f76bf7; }
        .tile-1024 { background-color: #f76b9f; }
        .tile-2048 { background-color: #f76b6b; }

        #gameOverContainer {
            display: none;
            margin-top: 20px;
        }

        #gameOver {
            font-size: 36px;
            color: #333;
            margin-bottom: 10px;
        }

        #restartButton {
            font-size: 20px;
            padding: 8px 20px;
            border-radius: 6px;
            background-color: #444;
            color: #fff;
            border: none;
            cursor: pointer;
            transition: background-color 0.3s;
        }

        #restartButton:hover {
            background-color: #666;
        }
    </style>
</head>
<body>
    <h1>2048</h1>

    <div id="gameContainer">
        <div id="score">Score: 0</div>
        <div id="gridContainer"></div>
        <div id="gameOverContainer">
            <div id="gameOver">Game Over!</div>
            <button id="restartButton">Restart</button>
        </div>
    </div>

    <script>
        document.addEventListener("DOMContentLoaded", () => {
            const gridContainer = document.getElementById("gridContainer");
            const scoreDisplay = document.getElementById("score");
            const gameOverContainer = document.getElementById("gameOverContainer");
            const restartButton = document.getElementById("restartButton");

            const width = 4;
            let tiles = [];
            let score = 0;
            let gameOverFlag = false;

            function init() {
                score = 0;
                gameOverFlag = false;
                updateScore();
                gameOverContainer.style.display = "none";
                resetGrid();
                tiles = Array(width * width).fill(null);
                addTile();
                addTile();
                drawTiles();
            }

            function resetGrid() {
                gridContainer.innerHTML = "";
            }

            function addTile() {
                const emptyTiles = tiles.map((tile, index) => tile === null ? index : null).filter(index => index !== null);

                if (emptyTiles.length > 0) {
                    const randomIndex = emptyTiles[Math.floor(Math.random() * emptyTiles.length)];
                    tiles[randomIndex] = Math.random() < 0.9 ? 2 : 4;
                }
            }

            function drawTiles() {
                resetGrid();
                tiles.forEach(tile => {
                    const tileElement = document.createElement("div");
                    tileElement.classList.add("tile");
                    if (tile !== null) {
                        tileElement.textContent = tile;
                        tileElement.classList.add(`tile-${tile}`);
                    }
                    gridContainer.appendChild(tileElement);
                });
            }

            function updateScore() {
                scoreDisplay.textContent = `Score: ${score}`;
            }

            function move(direction) {
                if (gameOverFlag) return;
                let hasChanged = false;

                const moveTile = (currentIndex, newIndex) => {
                    if (tiles[newIndex] === null) {
                        tiles[newIndex] = tiles[currentIndex];
                        tiles[currentIndex] = null;
                        hasChanged = true;
                    } else if (tiles[newIndex] === tiles[currentIndex]) {
                        tiles[newIndex] *= 2;
                        tiles[currentIndex] = null;
                        score += tiles[newIndex];
                        hasChanged = true;
                    }
                };

                const moveUp = () => {
                    for (let col = 0; col < width; col++) {
                        for (let row = 1; row < width; row++) {
                            let currentIndex = col + row * width;
                            while (currentIndex >= width && tiles[currentIndex] !== null) {
                                moveTile(currentIndex, currentIndex - width);
                                currentIndex -= width;
                            }
                        }
                    }
                };

                const moveDown = () => {
                    for (let col = 0; col < width; col++) {
                        for (let row = width - 2; row >= 0; row--) {
                            let currentIndex = col + row * width;
                            while (currentIndex + width < width * width && tiles[currentIndex] !== null) {
                                moveTile(currentIndex, currentIndex + width);
                                currentIndex += width;
                            }
                        }
                    }
                };

                const moveLeft = () => {
                    for (let row = 0; row < width; row++) {
                        for (let col = 1; col < width; col++) {
                            let currentIndex = row * width + col;
                            while (currentIndex % width !== 0 && tiles[currentIndex] !== null) {
                                moveTile(currentIndex, currentIndex - 1);
                                currentIndex--;
                            }
                        }
                    }
                };

                const moveRight = () => {
                    for (let row = 0; row < width; row++) {
                        for (let col = width - 2; col >= 0; col--) {
                            let currentIndex = row * width + col;
                            while ((currentIndex + 1) % width !== 0 && tiles[currentIndex] !== null) {
                                moveTile(currentIndex, currentIndex + 1);
                                currentIndex++;
                            }
                        }
                    }
                };

                switch (direction) {
                    case "up":
                        moveUp();
                        break;
                    case "down":
                        moveDown();
                        break;
                    case "left":
                        moveLeft();
                        break;
                    case "right":
                        moveRight();
                        break;
                }

                if (hasChanged) {
                    addTile();
                    drawTiles();
                    updateScore();
                    checkGameOver();
                }
            }

            function checkGameOver() {
                if (!tiles.includes(null) && !checkMove()) {
                    gameOverFlag = true;
                    gameOverContainer.style.display = "block";
                    restartButton.addEventListener("click", restart, { once: true });
                }
            }

            function checkMove() {
                for (let i = 0; i < tiles.length; i++) {
                    if (tiles[i] === null) return true;
                    if (i % width !== width - 1 && tiles[i] === tiles[i + 1]) return true;
                    if (i < tiles.length - width && tiles[i] === tiles[i + width]) return true;
                }
                return false;
            }

            function restart() {
                init();
            }

            document.addEventListener("keydown", event => {
                switch (event.key) {
                    case "ArrowUp":
                    case "w":
                        move("up");
                        break;
                    case "ArrowDown":
                    case "s":
                        move("down");
                        break;
                    case "ArrowLeft":
                    case "a":
                        move("left");
                        break;
                    case "ArrowRight":
                    case "d":
                        move("right");
                        break;
                }
            });

            init();
        });
    </script>
</body>
</html>

 

通过这篇文章,你可以了解如何从头开始构建一个简单的 2048 游戏,包括 HTML、CSS 和 JavaScript 的使用。

希望你能从中学习到有用的知识!

 

感谢阅读!!!

 

标签:case,tiles,HTML,color,2048,width,小游戏,currentIndex,tile
From: https://blog.csdn.net/m0_65134936/article/details/141255401

相关文章

  • HTML基础总结
    HTMLHTML4编辑器:VsCodeVsCode中的快捷键:标准结构!删除当前行中的内容ctrl+shift+k注释:语法:<!---->字符编码:默认:绝大多数浏览器认为你使用UTF-8编码,因此会用UTF-8解码语法:<head> <metacharset="utf-8"></head>过程:源代码to编码to编码后的进......
  • HTML基础笔记
    HTMLHTML4编辑器:VsCodeVsCode中的快捷键:标准结构!删除当前行中的内容ctrl+shift+k注释:语法:<!---->字符编码:默认:绝大多数浏览器认为你使用UTF-8编码,因此会用UTF-8解码语法:<head> <metacharset="utf-8"></head>过程:源代码to编码to编......
  • 【html】颜色随机产生器(补充包)
    上一篇文章我们讲了如何制作一个通过滑动产色纯色背景的网页,今天,我们对那个网页进行一个补充,()因为很多人在设计网页的时候没有颜色的灵感这个时候我们我们就可以考虑通过随机产生一种颜色并且能够实时看到效果的网页 我们来看看上次的代码:<!DOCTYPEhtml><htmllang="en">......
  • 【unity2022与html交互】
    一、安装untiy1.官网下载https://unity.com/cn/download,这个类似于untiy管理器,很多版本都可以下2.安装后登陆账号,网页跳转登陆,然后登陆后进入软件页面选择要下载的版本,建议2022lst版本3.下载后,在网页上使用还需要添加模块WEBGL,还有一个中文汉化模块也可以下载 二、模型......
  • 2:html:基础语法2
    目录2.1图像的一些注意点2.2表格2.2.1基本的表格2.2.2表头与边框2.3列表2.3.1无序列表2.3.2有序列表2.4块2.4.1块级元素2.4.2内联元素2.1图像的一些注意点在上一篇中,我们已经知道了怎么样去将图片运用到我们的网站中,但是这里还是有一些特殊情况的,比如说浏览器打......
  • JAVA 解析html 类型字符串(使用jsoup)
    1.引入pom文件<dependency><groupId>org.jsoup</groupId><artifactId>jsoup</artifactId><version>1.17.2</version></dependency>2.使用在线解析html工具,自己先看清html内容 (在线推荐:https://coding.tools/cn/html-beautifier#googl......
  • pygame开发小游戏
    代码:#coding=utf-8importos,sys,re,timeimportpygameimportrandomfromwin32apiimportGetSystemMetricsfromtkinterimportmessageboxfromsqlparse.filtersimportright_margin#pyinstaller-F-wdaziyan.pypygame.init()pygame.display.set_caption(&......
  • html5+CSS3 Canvas动画分享
    1.赛朋博客赛车动画 源码分享:<!DOCTYPEhtml><htmllang="en"><head>  <metacharset="UTF-8">  <title>赛车</title>  <style>    *{      margin:0;      padding:0;      bo......
  • 用JavaScript做超级玛丽小游戏
    一、前言前几天用JS实现扫雷和贪吃蛇(通过HTML的DOM节点实现基本界面,界面背景简单,交互简单)。比较复杂的是植物大战僵尸,不同的关卡设置单独的函数。所以还比较难。超级玛丽通过canvas实现背景,交互很复杂,功能很多,JS代码完全是有汇编语言反编译成C语言,然后把C语言转换成JS实现的......
  • 掌握Golang的html/template:打造动态网页的秘籍
    掌握Golang的html/template:打造动态网页的秘籍在Web开发的世界中,动态内容的生成是至关重要的。Golang以其简洁高效的特性,成为了后端开发的热门选择。而html/template包,则是Golang中用于创建HTML模板的官方工具,它不仅安全,而且功能强大。本文将带领你深入了解如何使用html/te......