You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何完善基于Canvas的简易贪吃蛇游戏水平移动及吃食物逻辑?

完善贪吃蛇吃食物逻辑及功能实现

看起来你已经搭好了贪吃蛇的基础框架,现在咱们来把吃食物的逻辑补全,顺便完善蛇身增长、新食物生成这些核心功能。

首先修复吃食物的判断逻辑

原代码里的eat函数判断条件没写完,其实因为蛇头和食物都是以10px为单位的格子(你设置了size_x=10,食物坐标也是*10的整数),所以直接判断蛇头的x和food_position_x相等、y和food_position_y相等就可以了,不用做多余的取整计算。

然后补充核心功能

要实现完整的吃食物流程,还需要:

  • 用数组管理蛇身的每一段坐标,方便后续增长
  • 吃到食物后,蛇身增加一段
  • 生成新的食物,并且避免食物出现在蛇身上

完整改进后的代码示例

(function() {
    var canvas = document.getElementById('canvas'),
        ctx = canvas.getContext('2d'),
        speed = 2,
        // 用数组存储蛇的每一段,初始蛇头在(0,0)
        snake = [{x: 0, y: 0}],
        // 初始移动方向:水平向右,每次移动10px(匹配格子大小)
        x_move = speed * 10,
        y_move = 0,
        food_position_x,
        food_position_y,
        size = 10; // 统一格子大小

    // 初始化生成食物
    generateFood();

    function generateFood() {
        // 生成随机食物坐标(10px倍数)
        food_position_x = Math.floor(Math.random() * canvas.width / size) * size;
        food_position_y = Math.floor(Math.random() * canvas.height / size) * size;

        // 避免食物出现在蛇身上,如果重合就重新生成
        for (let segment of snake) {
            if (segment.x === food_position_x && segment.y === food_position_y) {
                generateFood();
                return;
            }
        }
    }

    function eat() {
        const head = snake[0];
        // 判断蛇头是否碰到食物
        if (head.x === food_position_x && head.y === food_position_y) {
            console.log('吃到食物啦!');
            // 蛇身增长:在蛇尾添加一段(坐标和当前蛇尾一致,下一次移动会自动跟上)
            snake.push({...snake[snake.length - 1]});
            // 生成新的食物
            generateFood();
        }
    }

    function draw() {
        // 清空画布
        ctx.clearRect(0, 0, canvas.width, canvas.height);

        // 绘制蛇
        ctx.fillStyle = '#00ff00';
        snake.forEach(segment => {
            ctx.fillRect(segment.x, segment.y, size, size);
        });

        // 绘制食物
        ctx.fillStyle = '#ff0000';
        ctx.fillRect(food_position_x, food_position_y, size, size);
    }

    function update() {
        const head = {...snake[0]};
        // 更新蛇头位置
        head.x += x_move;
        head.y += y_move;

        // 把新蛇头放到数组最前面,移除蛇尾(除非吃到食物)
        snake.unshift(head);
        // 只有没吃到食物的时候才移除蛇尾,吃到的话蛇身就会增长
        if (!(head.x === food_position_x && head.y === food_position_y)) {
            snake.pop();
        }

        // 检查是否吃到食物
        eat();
        // 绘制画面
        draw();

        // 循环调用,实现动画
        requestAnimationFrame(update);
    }

    // 启动游戏
    update();
})();

关键改动说明

  • 蛇身管理:用snake数组存储每一段的坐标,初始只有蛇头,吃到食物时在数组末尾添加一段,移动时通过unshift添加新蛇头、pop移除蛇尾来实现移动效果。
  • 食物生成逻辑:新增generateFood函数,不仅生成随机坐标,还会检查是否和蛇身重合,避免食物出现在蛇身上。
  • 移动逻辑优化:把每次移动的距离改成speed*10,这样蛇每次移动一个格子的距离,和你的坐标系统更匹配。
  • 吃食物判断:直接比较蛇头和食物的坐标,逻辑更清晰准确。

你可以把这段代码替换原来的部分,然后给canvas设置合适的宽高(比如width="400" height="400"),就能看到完整的吃食物和蛇身增长效果啦!

内容的提问来源于stack exchange,提问作者Reza Saadati

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 08:05:28