You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何避免JavaScript贪吃蛇游戏中食物生成在蛇身内部?

解决贪吃蛇食物不在蛇身生成的问题

嘿,我发现你的问题出在食物生成的逻辑顺序上!你写的检查思路是对的,但调用时机不对,导致检查根本没生效。让我拆解下问题,再帮你修复代码。

问题根源

你看这段代码:

while(!checkSnakeForFood()) {
 food = {
 x : Math.floor(Math.random()*((cvsW/unit)-1)+1)*unit,
 y : Math.floor(Math.random()*((cvsH/unit)-1)+1)*unit
 }
}

这里的问题是:你在生成新食物之前就调用了checkSnakeForFood(),而这个函数检查的是全局food变量的旧位置(也就是刚被吃掉的那个食物的位置)。等你生成了新食物,却没有再次验证它是否在蛇身上——这就导致新食物还是可能出现在蛇身范围内。

修复方案

我们需要调整逻辑:先生成随机位置,再检查这个位置是否和蛇身重叠,如果重叠就重新生成,直到找到安全位置。最好把食物生成封装成单独函数,逻辑更清晰。

下面是修复后的完整JavaScript代码:

const canvas = document.querySelector('#canvas');
const ctx = canvas.getContext('2d');
//set canvas dimension equal to css dimension
canvas.width = 768;
canvas.height = 512;
//now put those dimensions into variables
const cvsW = canvas.width;
const cvsH = canvas.height;
//create snake unit
const unit = 16;
//create snake array
let snake = [{x: cvsW/2, y: cvsH/2}];
//delcare global variable to hold users direction
let direction;
//create food object
let food = generateFood(); // 调用生成函数初始化食物

//read user's direction
document.addEventListener('keydown', changeDirection);
function changeDirection(e) {
 //set direction
 if (e.keyCode == 37 && direction != 'right')
 direction = 'left';
 else if (e.keyCode == 38 && direction != 'down')
 direction = 'up';
 else if (e.keyCode == 39 && direction != 'left')
 direction = 'right';
 else if (e.keyCode == 40 && direction != 'up')
 direction = 'down';
}

function draw() {
 //refresh canvas
 ctx.clearRect(0, 0, cvsW, cvsH);
 //draw snake
 for(let i = 0; i < snake.length; i++) {
 ctx.fillStyle = 'limegreen';
 ctx.fillRect(snake[i].x, snake[i].y, unit, unit);
 }
 //grab head position
 let headX = snake[0].x;
 let headY = snake[0].y;
 //posistion food on board
 ctx.fillStyle = 'red';
 ctx.fillRect(food.x, food.y, unit, unit);
 //send the snake in chosen direction
 if(direction == 'left') headX -= unit;
 else if(direction == 'up') headY -= unit;
 else if(direction == 'right') headX += unit;
 else if(direction == 'down') headY += unit;
 //wrap around walls
 if (headX < 0) headX = cvsW - unit;
 else if (headX > cvsW - unit) headX = 0;
 else if (headY < 0) headY = cvsH - unit;
 else if(headY > cvsH - unit) headY = 0;
 //create new head
 let newHead = {x: headX, y: headY}
 //if snake eats food -do this
 if(headX == food.x && headY == food.y) {
 //生成新的安全食物
 food = generateFood();
 //add 3 units to the snake(你原来写的是30,这里保留你的设置)
 for (let i = 30; i > 0; i--) {
 snake.unshift(newHead);
 }
 } else {
 //remove tail
 snake.pop();
 }
 //add head to snake
 snake.unshift(newHead);
}

//run game engine
let runGame = setInterval(draw, 40);

// 生成安全食物的函数
function generateFood() {
 let newFood;
 // 循环生成,直到找到不在蛇身上的位置
 while(!newFood || isPositionOnSnake(newFood)) {
 newFood = {
 x : Math.floor(Math.random()*((cvsW/unit)-1)+1)*unit,
 y : Math.floor(Math.random()*((cvsH/unit)-1)+1)*unit
 }
 }
 return newFood;
}

// 检查某个位置是否在蛇身上的工具函数
function isPositionOnSnake(position) {
 for(let i = 0; i < snake.length; i++) {
 if(snake[i].x === position.x && snake[i].y === position.y) {
 return true;
 }
 }
 return false;
}

关键改动说明

  1. 新增generateFood()函数:负责生成随机位置,通过isPositionOnSnake()验证位置安全性,直到找到符合要求的位置才返回。
  2. 替换食物生成逻辑:初始化和进食后的食物生成都调用generateFood(),确保每次生成的食物都不在蛇身上。
  3. 拆分检查逻辑为isPositionOnSnake():让函数职责更单一,后续维护或扩展功能也更方便。

这样修改后,食物就再也不会出现在蛇的身体里了,你可以继续测试游戏速度和蛇的增长效果啦!

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

火山引擎 最新活动