贪吃蛇游戏的原生代码开发

本文介绍了一个基于HTML、CSS和JavaScript实现的蛇形游戏。游戏通过网格化管理蛇的移动、食物生成及碰撞检测等核心功能,并实现了键盘控制、自动移动及暂停等功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

该游戏的主要思想:将目标区域或者说盒子网格化,通过网格化来对蛇进行生成、移动等操作

 html和css很少,主要是规划盒子的将要用到的开始按钮、暂停按钮以及蛇的头和身体、食物的大小、定位和类名。

 html:

    <div class="game">
        <div class="game_start">
            <img src="img/btn1.gif">
        </div>
        <div class="game_pause">
            <img src="img/btn4.png">
        </div>
    </div>

 css:

  * {
            padding: 0;
            margin: 0;
        }
        
        .game {
            position: relative;
            width: 600px;
            height: 600px;
            background-color: #fce4ec;
            margin: 50px auto;
            border: 20px solid #f8bbd0;
        }
        
        .game_start,
        .game_pause {
            position: absolute;
            left: 50%;
            top: 50%;
            transform: translate(-50%, -50%);
            cursor: pointer;
        }
        
        .game_pause {
            display: none;
        }
        
        .game_start img {
            width: 300px;
        }
        
        .game_pause img {
            width: 100px;
        }
        
        .snake_hd {
            position: absolute;
            width: 20px;
            height: 20px;
            top: 0;
            left: 0px;
            background-image: url(img/snake.png);
            background-size: cover;
            background-position: center;
            background-repeat: no-repeat;
        }
        
        .snake_bd {
            position: absolute;
            top: 0;
            left: 0px;
            width: 20px;
            height: 20px;
            background-color: #649c49;
            border-radius: 50%;
        }
        
        .food {
            position: absolute;
            width: 20px;
            height: 20px;
            left: 0px;
            top: 0px;
            background-image: url(img/food2.png);
            background-size: cover;
            background-position: center;
            background-repeat: no-repeat;
        }

 以下js中:建议将每一块的第一部分放在所有方法的前面(因为他们都是全局配置,放前面预防出差错),我文中这样放置是为了方便大家观看。

一、初始化游戏(initGame)

1、地图的初始化

这个盒子是600x600 px的盒子,我将其分成30x30 的网格,每个格子是20x20 px大小

用双重for循环对地图进行初始化,用对象将获取的地图储存

 var gridData = []; //存储地图对象
 // 整个网格的行与列
    var tr = 30;
    var td = 30;
 function initGame() {
        // 1.初始化地图
        for (var i = 0; i < tr; i++) {
            for (var j = 0; j < td; j++) {
                gridData.push({
                    x: j,
                    y: i
                })
            }
        }
        // console.log(gridData);
        // 2.绘制蛇
        drawSnake(snake);

        // 3.绘制食物
        drawFood();
    }

2.绘制蛇(因为初始化需要调用绘制蛇的方法,所有书写时应该在initGame前面)

 // 蛇的身体大小
    var snakeBody = 20;

// 蛇相关的配置信息
    var snake = {
        // 蛇一开始移动的方向
        direction: directionNum.right, //一开始向右边移动
        // 蛇的初始位置
        snakePos: [
            { x: 0, y: 0, domContent: '', flag: 'body' },
            { x: 1, y: 0, domContent: '', flag: 'body' },
            { x: 2, y: 0, domContent: '', flag: 'body' },
            { x: 3, y: 0, domContent: '', flag: 'head' },
        ]
    }
 // 绘制蛇的方法
    function drawSnake(snake) {
        for (var i = 0; i < snake.snakePos.length; i++) {
            if (!snake.snakePos[i].domContent) {
                // 进入此说明第一次创建蛇
                snake.snakePos[i].domContent = document.createElement('div');
                snake.snakePos[i].domContent.style.left = snake.snakePos[i].x * snakeBody + 'px';
                snake.snakePos[i].domContent.style.top = snake.snakePos[i].y * snakeBody + 'px';
                if (snake.snakePos[i].flag === 'head') {
                    // 进入此if说明是蛇头
                    snake.snakePos[i].domContent.className = 'snake_hd';
                    // 根据方向进行旋转
                    switch (snake.direction.flag) {
                        case 'top':
                            {
                                snake.snakePos[i].domContent.style.transform = 'rotate(-90deg)';
                                break;
                            }
                        case 'bottom':
                            {
                                snake.snakePos[i].domContent.style.transform = 'rotate(90deg)';
                                break;
                            }
                        case 'left':
                            {
                                snake.snakePos[i].domContent.style.transform = 'rotate(180deg)';
                                break;
                            }
                        case 'right':
                            {
                                snake.snakePos[i].domContent.style.transform = 'rotate(0deg)';
                                break;
                            }
                    }
                } else {
                    // 说明是蛇身
                    snake.snakePos[i].domContent.className = 'snake_bd';
                }
            }
            // 需要将创建的 DOM元素添加到container 容器上面
            document.querySelector('.game').append(snake.snakePos[i].domContent);
        }
    }

3.绘制食物(因为初始化需要调用绘制食物的方法,所有书写时应该在initGame前面)

//食物相关的配置信息
    var food = {
            x: 0,
            y: 0,
            domContent: ''
        }
 // 绘制食物的方法
    function drawFood() {
        // 1.食物的坐标是随机的
        // 2.食物不能生成在蛇头或者蛇身上面
        while (true) {
            // 构成一个死循环,直到生成符合要求的食物坐标才能退出该循环
            var isRepeat = false; //默认生成的坐标是符合要求的
            // 随机生成一个坐标
            food.x = Math.floor(Math.random() * tr);
            food.y = Math.floor(Math.random() * tr);


            // 查看坐标是否符合要求(遍历蛇)
            for (var i = 0; i < snake.snakePos.length; i++) {
                if (snake.snakePos[i].x === food.x && snake.snakePos[i].y === food.y) {
                    //    进入此if 说明当前生成的食物坐标和蛇的坐标冲突了
                    isRepeat = true;
                    break;
                }
            }
            if (!isRepeat) {
                // 跳出while循环
                break;
            }
        }
        // 跳出while循环说明食物的坐标符合要求
        if (!food.domContent) {
            food.domContent = document.createElement('div');
            food.domContent.className = 'food';
            document.querySelector('.game').append(food.domContent);
        }
        food.domContent.style.left = food.x * snakeBody + 'px';
        food.domContent.style.top = food.y * snakeBody + 'px';
    }

二、碰撞测试

   //游戏分数
    var score = 0;
 // 碰撞检测
    function isCollide(newHead) {
        var collideCheckInfo = {
                isCollide: false, //是否碰撞墙壁、蛇身
                isEat: false //是否吃到食物
            }
            // 1、检测是否碰到墙壁
        if (newHead.x < 0 || newHead.x > td - 1 || newHead.y < 0 || newHead.y > tr - 1) {
            collideCheckInfo.isCollide = true;
            return collideCheckInfo;
        }

        // 2、检测是否碰到自己
        for (var i = 0; i < snake.snakePos.length; i++) {
            if (snake.snakePos[i].x === newHead.x && snake.snakePos[i].y === newHead.y) {
                collideCheckInfo.isCollide = true;
                return collideCheckInfo;
            }
        }
        // 3、检测是否吃到东西
        if (newHead.x === food.x && newHead.y === food.y) {
            collideCheckInfo.isEat = true;
            score++; //分数自增
        }
        return collideCheckInfo;
    }

三、蛇移动

蛇移动的核心方法就是:获取旧头的位置,通过旧头确定新头的位置(旧头位置+键盘绑定事件)

再将旧头改成身体。

// 明确新的蛇头和旧的蛇头之间的位置关系
    // 在明确新的蛇头坐标的时候,会拿下面的对象和旧的蛇头做计算
    //得到新的蛇头的坐标
    var directionNum = {
        left: { x: -1, y: 0, flag: 'left' },
        right: { x: 1, y: 0, flag: 'right' },
        top: { x: 0, y: -1, flag: 'top' },
        bottom: { x: 0, y: 1, flag: 'bottom' },
    }
  function snakeMove() {
        var oldHead = snake.snakePos[snake.snakePos.length - 1];
        // 根据方向计算出新的蛇头的坐标
        var newHead = {
            domContent: '',
            x: snake.snakePos[snake.snakePos.length - 1].x + snake.direction.x,
            y: snake.snakePos[snake.snakePos.length - 1].y + snake.direction.y,
            flag: 'head'
        }

        // 碰撞游戏结束检测
        // 看新的蛇头是否碰上食物、身体、墙壁
        var collideCheckResult = isCollide(newHead);
        if (collideCheckResult.isCollide) {
            //进入此if,说明碰墙了
            alert('游戏结束,您当前的分数为' + score + ' 分,是否重新开始游戏?')
          clearInterval(timerStop);
        }
   // 将旧的头改成身体
        oldHead.flag = 'body';
        oldHead.domContent.className = 'snake_bd';
        snake.snakePos.push(newHead);
        // 判断是否吃到东西
        if (collideCheckResult.isEat) {
            // 1.重新生成新的食物
            drawFood();
        } else {
            //说明没有吃到食物
            // 移除最后一个元素
            document.querySelector('.game').removeChild(snake.snakePos[0].domContent);
            snake.snakePos.shift();
        }

        // 重新绘制蛇
        drawSnake(snake);
    }

四、蛇自动移动

 // 停止计时器
    var timerStop = null;
    var time = 100;
 // 自动移动
    function startGame() {
        timerStop = setInterval(function() {
            snakeMove();
        }, time)
    }

五、绑定事件

  // 绑定事件
    function bindEvent() {
        //  1.首先是键盘事件,用户按上下左右,蛇能够移动
        document.onkeydown = function(e) {
                if ((e.key === 'ArrowUp' || e.key.toLocaleLowerCase() === 'w') && snake.direction.flag !== 'bottom') {
                    // 用户按的是上
                    snake.direction = directionNum.top;
                }
                if ((e.key === 'ArrowDown' || e.key.toLocaleLowerCase() === 's') && snake.direction.flag !== 'top') {
                    // 用户按的是下
                    snake.direction = directionNum.bottom;

                }
                if ((e.key === 'ArrowLeft' || e.key.toLocaleLowerCase() === 'a') && snake.direction.flag !== 'right') {
                    // 用户按的是左
                    snake.direction = directionNum.left;
                }
                if ((e.key === 'ArrowRight' || e.key.toLocaleLowerCase() === 'd') && snake.direction.flag !== 'left') {
                    // 用户按的是右
                    snake.direction = directionNum.right;
                }

            }
            // 2. 计时器自动调用蛇移动的方法
        startGame();

        // 3.点击整个容器的时候,可以暂停
        document.querySelector('.game').onclick = function() {
                document.querySelector('.game_pause').style.display = 'block';
                clearInterval(timerStop);
            }
            // 4.给暂停按钮绑定事件
        document.querySelector('.game_pause').onclick = function(e) {
            e.stopPropagation();
            document.querySelector('.game_pause').style.display = 'none';
            startGame();

        }
    }

六、游戏主方法

  function main() {
        // 用户点击了开始游戏后才开始做后续
        game_start.onclick = function(e) {
            e.stopPropagation(); //阻止冒泡
            game_start.style.display = 'none';
            // 1.首先第一步:初始化游戏
            initGame();
            // 2.绑定事件
            bindEvent();
        }

    }
    main();

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值