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

JS实现Canvas贪吃蛇 方向控制与蛇身绘制问题修复

贪吃蛇代码Bug修复方案

问题根因汇总

蛇身绘制不符合预期(要求3方块宽度)

  • 遍历蛇身的for循环存在语法错误:一是数组长度属性拼写错误,把length写成了lenght;二是for循环括号后多写了一个分号,导致循环体和遍历逻辑脱钩,根本不会逐块绘制整个蛇身
  • 初始化蛇身时传入的数组长度为5,要满足3方块宽度的要求,初始化body参数改为3个坐标元素即可

蛇无法响应方向键移动

  • 键盘事件绑定方式错误:addEventListener是DOM方法,不能直接给它赋值函数来绑定事件,必须传入事件名和回调函数作为参数才能生效
  • 作用域错误:原代码把键盘回调函数写在window.onload代码块外面,无法访问onload内部定义的snakee实例,调用转向方法时会直接报变量未定义错误
  • 方向键键值映射完全写反:上箭头(keyCode 38)、右箭头(keyCode 39)对应的方向赋值错误,按键后触发的方向完全不对
  • 移动逻辑存在拼写错误:向左移动的分支里把nextPosition拼成了nexPosition,触发引用错误直接中断移动逻辑
  • 上下移动的坐标逻辑写反:Canvas坐标系中y轴向下为正方向,向下移动时y坐标应该+1、向上移动时y坐标应该-1,原代码逻辑完全颠倒
  • 方向校验存在拼写错误:允许转向的方向列表里把down拼成了donw,导致水平移动时无法切换到向下方向
  • 构造函数冗余问题:定义Snake时传入了_direction参数但未使用,直接硬编码初始方向为right,不影响运行但属于无效参数

修复后完整代码

window.onload = function()
{
    var canvasWidth = 900;
    var canvasHeight = 600;
    var blockSize = 30;
    var ctx;
    var delay = 100;
    var snakee;

    init();

    function init()
    {
        var canvas = document.createElement('canvas')
        canvas.width = canvasWidth;
        canvas.height = canvasHeight;
        canvas.style.border = "1px solid"
        document.body.appendChild(canvas);
        ctx = canvas.getContext('2d');
        // 初始化蛇身改为3个方块,满足宽度要求
        snakee = new Snake([[6,4],[5,4],[4,4]], "right");
        // 正确绑定键盘事件
        document.addEventListener('keydown', handleKeyDown);
        refreshCanvas();
       
    }
    
    function refreshCanvas()
    {
        ctx.clearRect (0,0,canvasWidth, canvasHeight);  
        snakee.draw();
        snakee.advance();
        setTimeout(refreshCanvas, delay);
    }

    function drawBlock(ctx, position)
     {
        var x = position[0] * blockSize;
        var y = position[1] * blockSize;
        ctx.fillRect(x ,y , blockSize , blockSize );
     }

    function Snake(body, direction)
    {
        this.body = body;
        // 使用传入的初始方向参数,而非硬编码
        this.direction = direction;
        this.draw = function ()
        {
            ctx.save();
            ctx.fillStyle =  "#ff0000";
            // 修正length拼写错误,去掉for循环后多余的分号
            for(var i = 0; i < this.body.length; i++)
            {
                drawBlock(ctx, this.body[i]);
            }
            ctx.restore();
        };
        this.advance = function()
        {
            var nextPosition = this.body[0].slice();
            switch(this.direction)
            {
                case "left":
                    // 修正变量拼写错误
                    nextPosition[0] -= 1;
                    break;
                case "right":
                    nextPosition[0] += 1;
                    break;
                case "down":
                    // 修正上下移动坐标逻辑,down对应y+1
                    nextPosition[1] += 1;
                    break;
                case "up":
                    // 修正up对应y-1
                    nextPosition[1] -= 1;
                    break;
                default:
                        throw("Invalid Direction");
            
            }
            this.body.unshift(nextPosition);
            this.body.pop();
        };
        this.setDirection = function(newDirection)
        {
            var allowedDirections;
            switch(this.direction)
            {
                case "left":   
                case "right":
                    // 修正down拼写错误
                    allowedDirections = ["up", "down"];
                    break;                
                case "down":
                case "up":
                    allowedDirections = ["left","right"]
                    break;
                default:
                        throw("Invalid Direction");
            
            }
            if(allowedDirections.indexOf(newDirection) > -1 )
            {
                this.direction = newDirection;
            }
        };
    }

    function handleKeyDown(e)
    {
        const key = e.keyCode;
        var newDirection;
        switch(key)
        {
            case 37:
                newDirection = "left";
                break;
            case 38:
                // 修正上箭头对应up方向
                newDirection = "up";
                break;
            case 39:
                // 修正右箭头对应right方向
                newDirection = "right";
                break;
            case 40:
                // 修正下箭头对应down方向
                newDirection = "down";
                break;
            default:
                return; 
        }
        snakee.setDirection(newDirection);
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 17:12:29