Html贪吃蛇游戏 手把手(简易版)

导言

贪吃蛇,这个简单而经典的游戏陪伴我们很多人度过精彩的青春。它的魅力在于简洁,但是又让人上瘾的玩法,让人忍不住一次一次的挑战自己的极限。这里想通过一个H5制作贪吃蛇的案例来分享一下制作的过程,以及一些思路,希望大家能从中获取对自己有用的东西,思路也好,代码逻辑也好。

思路

讲到思路这一部分其实更多的我更想把他叫做思想,因为思想,思维这个工具可以帮助我们做很多事,而不是局限于一道题的解答。这里我自己用的思想是拆分和简化思想。不过同时还是要讲一下思路,才能让我们知道从哪里着手做一个贪吃蛇的小游戏。这里主要是拆分为游戏界面的设计,然后是游戏行为的设计。

游戏界面详解

首先看下我们游戏最终效果的样子,其实并不难,组成部分有游戏区域,蛇,食物,重新开始按钮、游戏规则

在这里插入图片描述

游戏区域结构和样式

这里的设计用我开篇说的思维工具拆分,将上面的最终结果进行拆分,得到一个400*400的区域,这里学过Html的都知道怎么写,其实就是一个div

在这里插入图片描述
Html代码:

<div id="game-board"></div>

Css代码:
这里解释一下,其实这里的代码很简单,新手也可以看得懂,这里主要是游戏区域的设计,设计了一个400*400px的块,然后将位置设置为相对定位。第一部分的代码这里用了弹性盒子布局,将游戏区域放到屏幕的正中间。为了照顾不了解弹性盒子的朋友这里穿插一点相关的知识。
弹性盒子布局(Flexbox layout):是一种用于创建灵活且自适应的网页布局的技术。它可以轻松地实现元素的水平和垂直居中、等高列布局等效果,使得页面布局更加简单和响应式。
display:将body设置为弹性盒子布局
flex-direction:控制子元素的排列方向,可以设置为 row(水平方向)、column(垂直方向)等。
justify-content:控制子元素在主轴上的对齐方式,例如 flex-start(靠左对齐)、center(居中对齐)等。
align-items:控制子元素在交叉轴上的对齐方式,例如 flex-start(靠上对齐)、center(居中对齐)等。

  /* 将 body 的 display 属性设置为 flex,使其可以垂直和水平居中 */
        body {
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            height: 100vh;
            margin: 0;
            padding: 0;
            background-color: #f5f5f5;
        }
        /* 游戏区域的样式 */
        #game-board {
            width: 400px;
            height: 400px;
            border: 1px solid black;
            position: relative;
            /*border-radius: 50%; !*圆形*!*/
        }

游戏结束区域结构和样式

这部分不是很重要代码也比较简单就不解释了,看下最终效果就行,因为后面要用到。
游戏结束和游戏规则Html代码:

<div id="game-over">
    <h2>游戏结束!</h2>
    <p>你的得分是 <span id="score"></span> 分。</p>
    <button id="restart-btn">重新开始</button>
</div>
<div id="game-rule">
    <p>游戏规则:</p>
    <p>1. 使用方向键控制小蛇的移动方向,吃掉食物增加得分。</p>
    <p>2. 小蛇撞墙或者撞到自己的身体,游戏结束。</p>
    <p>3. 点击重新开始按钮可以重新开始游戏。</p>
</div>

游戏结束和游戏规则Css代码:

/* 游戏结束界面的样式 */
        #game-over {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            display: none;
        }

        /* 重新开始按钮的样式 */
        #restart-btn {
            background-color: #00bcd4;
            border: none;
            border-radius: 8px;
            color: white;
            padding: 10px 20px;
            font-size: 16px;
            cursor: pointer;
            margin-top: 20px;
        }

        /* 游戏规则的样式 */
        #game-rule {
            margin-top: 20px;
            font-size: 16px;
            text-align: center;
            color: #666;
        }

效果图:
分成两部分
在这里插入图片描述

蛇身和食物结构和样式

这里设计也是用拆分的思维工具帮助我们思考,这里设计了两个块,一个是用来表示蛇的块,一个是用来表示食物的块。这里是用JavaScript生成到刚才的游戏区域。

蛇的JavaScript生成部分:
这部分的代码,先获取游戏区域的父元素,在用文档document生成一个表示的div,并为它添加类名.snake。最后追加到游戏区域中,食物也是同理。

因为食物是要随机的,所以要随机生成它的x,y坐标,这里食物的位置就是用随机函数进行随机生成一个0-400的数。

Math.random() 函数用于生成一个介于 0(包含)和 1(不包含)之间的随机数,乘于20是0-20。再用Math.floor()向下取整得到一个整数,最后*20,得到0-400之间的整数。x,y坐标就在0-400之间。

最后几行代码初始化蛇和食物的位置。

// 获取游戏板的元素
var gameBoard = document.getElementById("game-board");

// 创建表示蛇的div元素,并添加snake类名
var snake = document.createElement("div");
snake.classList.add("snake");

// 将蛇元素添加到游戏板中
gameBoard.appendChild(snake);

// 创建表示食物的div元素,并添加food类名
var food = document.createElement("div");
food.classList.add("food");

// 将食物元素添加到游戏板中
gameBoard.appendChild(food);

// 随机生成食物的位置
var foodX = Math.floor(Math.random() * 20) * 20;
var foodY = Math.floor(Math.random() * 20) * 20;

// 设置食物元素的top和left属性
food.style.top = foodY + "px";
food.style.left = foodX + "px";

// 设置蛇的初始位置
var snakeX = 0;
var snakeY = 0;

蛇和食物的css样式:

/* 蛇的样式 */
        .snake {
            width: 20px;
            height: 20px;
            border: 1px solid black;
            background-color:  orangered; // 橙色
            position: absolute;
            top: 0;
            left: 0;
            /*border-radius: 50%; !*圆形*!*/
        }

        /* 食物的样式 */
        .food {
            width: 20px;
            height: 20px;
            /*width: 25px;*/
            /*height: 25px;*/
            background-color: #01FE00; // 浅绿色
            position: absolute;
            top: 0;
            left: 0;
            /*border-radius: 50%; !*圆形*!*/
        }

运行效果:
因为是食物是随机的,每一次重新加载(重新开始游戏),会的到两个不同的位置。

在这里插入图片描述
在这里插入图片描述

游戏行为详解

到上面这里基本的元素都设计出来了,接下来就是设计游戏的行为,游戏嘛,最重要的还是交互。这里分别为游戏方向控制、蛇的移动、蛇和食物的检测碰撞、游戏结束的检测碰撞。还是依然用拆分和简化的思维工具。

游戏的必要参数(JavaScript)

这里为什么不直接写游戏的控制函数,其实我的思路是既然要进行上面所说的几个行为,有某些参数是必不可少的,比如速度、当前方向、蛇吃到食物后增加长度后要存储的数组、分数的统计等。

    var speed = 200;  // 初始化为200,后面需要用到,值越低速度越高
    var direction = "right";  // 当前方向,因为是简单的键盘控制方向,只有上、下、左、右四个方向
    var snakeBody = [snake]; //组装蛇的数据
    var score = 0;

游戏方向控制(JavaScript)

这里监听一下键盘事件,用来响应用户的按键操作,并根据按键的不同更新游戏对象(蛇)的移动方向。这里要配合后面蛇移动的代码来看,因为那里是调用处

如果按下左箭头键(keyCode 为 37)并且当前方向不是向右,则将 direction 设置为 “left”,表示蛇头向左移动

如果按下上箭头键(keyCode 为 38)并且当前方向不是向下,则将 direction 设置为 “up”,表示蛇头向上移动

如果按下右箭头键(keyCode 为 39)并且当前方向不是向左,则将 direction 设置为 “right”,表示蛇头向右移动

如果按下下箭头键(keyCode 为 40)并且当前方向不是向上,则将 direction 设置为 “down”,表示蛇头向下移动

document.addEventListener("keydown", function (event) {
        if (event.keyCode === 37 && direction !== "right") {
            direction = "left";
        } else if (event.keyCode === 38 && direction !== "down") {
            direction = "up";
        } else if (event.keyCode === 39 && direction !== "left") {
            direction = "right";
        } else if (event.keyCode === 40 && direction !== "up") {
            direction = "down";
        }
    });

这段代码要是一个正反思想,就是比如你按键的同时蛇头的当前方向不能是他的反方向。因为这样就会碰到自己身体,这是不允许的。所以除了不是自己当前运动的反方向,其余方向都是可以控制的。
在这里插入图片描述

蛇的移动

这部分主要设计蛇的移动,拆分来看,要计算出蛇的蛇头和蛇尾的位置。

这段代码定义了一个名为 moveSnake 的函数,用于控制蛇的移动

1.首先获取蛇尾部的坐标,以便在蛇吃到食物时使用。蛇尾总是在数组下标 -1的位置。

2.通过循环移动蛇身体的每个部分,通过设置每个部分的 top 和 left 样式来实现移动效果。也就是定位蛇身体每个部分的坐标,进而实现移动的效果。

3.根据移动方向更新蛇头的坐标。根据 direction 的值,增加或减少 snakeX 或 snakeY 的值来改变蛇的位置。这里配合之前控制方向的函数实现。

4.检查蛇是否超出游戏边界,如果超出则调用 gameOver 函数来结束游戏。这里是在后面游戏结束函数中定义。

5.更新蛇头的位置,通过设置蛇头元素的 top 和 left 样式来改变蛇头的位置。蛇头总是在数组为0的位置。

6.检查蛇是否吃到食物,如果蛇头的坐标与食物的坐标相同,则表示蛇吃到食物。随机生成新的食物位置,并创建一个新的蛇身体部分,将其添加到蛇身体数组中。最后,更新得分。

7.继续移动蛇,设置下一个定时器,通过 setTimeout(moveSnake, speed) 来实现蛇的连续移动。

var moveSnakeTimeout = setTimeout(moveSnake, speed); //这行代码用于设置定时器,控制蛇的移动速度。后面用到
// 移动蛇的函数
function moveSnake() {
    // 获取蛇尾部的坐标
    var tailX = snakeBody[snakeBody.length - 1].offsetLeft;
    var tailY = snakeBody[snakeBody.length - 1].offsetTop;

    // 移动蛇身体的每个部分
    for (var i = snakeBody.length - 1; i > 0; i--) {
        snakeBody[i].style.top = snakeBody[i - 1].style.top;
        snakeBody[i].style.left = snakeBody[i - 1].style.left;
    }

    // 根据移动方向更新蛇头的坐标
    if (direction === "right") {
        snakeX += 20;
    } else if (direction === "left") {
        snakeX -= 20;
    } else if (direction === "up") {
        snakeY -= 20;
    } else if (direction === "down") {
        snakeY += 20;
    }

    // 检查蛇是否超出游戏边界
    if (snakeX < 0 || snakeX >= 400 || snakeY < 0 || snakeY >= 400) {
        // 游戏结束
        gameOver();
        return;
    }

    // 更新蛇头的位置
    snakeBody[0].style.top = snakeY + "px";
    snakeBody[0].style.left = snakeX + "px";

    // 检查蛇是否吃到食物
    if (snakeX === foodX && snakeY === foodY) {
        // 随机生成新的食物位置
        foodX = Math.floor(Math.random() * 20) * 20;
        foodY = Math.floor(Math.random() * 20) * 20;
        food.style.top = foodY + "px";
        food.style.left = foodX + "px";

        // 创建一个新的蛇身体部分
        var newSnakePart = document.createElement("div");
        newSnakePart.classList.add("snake");
        newSnakePart.style.top = tailY + "px";
        newSnakePart.style.left = tailX + "px";

        // 将新的蛇身体部分添加到蛇身体数组中
        snakeBody.push(newSnakePart);
        gameBoard.appendChild(newSnakePart);

        // 更新得分
        score++;
    }
 // 继续移动蛇,设置下一个定时器
    setTimeout(moveSnake, speed);
}

运行效果:
到目前为止蛇已经可以正常移动,游戏的基本组成也差不多完成。看下效果。
其实测试到这里游戏也就差蛇头碰到游戏边界的检测(游戏结束)、和游戏结束后的得分显示、以及重新开始游戏就结束了

20240328_232205

游戏结束的检测碰撞以及得分显示

这里把之前设置继续移动蛇的定时器删除,且显示得分,在显示游戏结束界面就可以了

// 游戏结束函数
function gameOver() {
    // 清除移动蛇的定时器
    clearTimeout(moveSnakeTimeout);

    // 获取游戏结束界面的元素
    var gameOverDiv = document.getElementById("game-over");
    var scoreSpan = document.getElementById("score");

    // 显示游戏得分
    scoreSpan.innerText = score;

    // 显示游戏结束界面
    gameOverDiv.style.display = "block";
}

检测蛇是否超出边界,其实这段代码在移动蛇的时候调用,**为了展示逻辑这里在写一次,**要使用其实用前一段代码即可,这段不需要再写入Html文件当中。

// 检查蛇是否超出游戏边界
    if (snakeX < 0 || snakeX >= 400 || snakeY < 0 || snakeY >= 400) {
        // 游戏结束
        gameOver();
        return;
    }

以下四种情况,都会造成蛇头的碰撞,导致游戏结束。
其实就是left(左边距)、top(上边距)超出边界的情况,|| 条件,只要其中一个满足,就会导致游戏的结束
在这里插入图片描述

游戏重新开始

游戏重新开始就容易的多了,把之前定义的东西初始化,以及回到开始游戏界面,重新调用蛇的移动函数即可、

// 获取重新开始按钮
var restartBtn = document.getElementById("restart-btn");

// 添加点击事件监听器
restartBtn.addEventListener("click", function () {
    // 获取游戏结束界面的元素
    var gameOverDiv = document.getElementById("game-over");

    // 隐藏游戏结束界面
    gameOverDiv.style.display = "none";

    // 重置游戏状态,初始化之前定义的参数
    snakeX = 0;
    snakeY = 0;
    direction = "right";
    score = 0;

    // 移除多余的蛇身体部分
    var currentSnakeLength = snakeBody.length;
    for (var i = 1; i < currentSnakeLength; i++) {
        gameBoard.removeChild(snakeBody[1]); //这里移除游戏界面中蛇的身体结构
        snakeBody.splice(1, 1); //这里用数组中的第一个位置开始移除数组中的一个袁术。
    }

    // 重置蛇头的位置
    snake.style.top = 0;
    snake.style.left = 0;

    // 随机生成新的食物位置
    foodX = Math.floor(Math.random() * 20) * 20;
    foodY = Math.floor(Math.random() * 20) * 20;
    food.style.top = foodY + "px";
    food.style.left = foodX + "px";

    // 开始新的游戏
    moveSnake();
});

到这里代码就结束了,有更好的想法以及反馈欢迎交流学习。

运行效果

贪吃蛇游戏

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值