我怎么做才能使食物不会在蛇内产生

时间:2019-01-19 03:29:14

标签: javascript

嘿,有人可以告诉我我该怎么做,以免食物在我的蛇内产生。我尝试过使用for循环来检查蛇的每个索引,以查看它是否与食物的位置匹配,但这仍然行不通。另外,我加快了游戏的速度,并加快了吃食物时添加到蛇上的单位数量,从而加快了结果的速度,并检查了该方法是否有效。

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 = {
	x : Math.floor(Math.random()*((cvsW/unit)-1)+1)*unit,
	y : Math.floor(Math.random()*((cvsH/unit)-1)+1)*unit
}

//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;

	// //check if snake hit wall
	// if(headX < 0 || headY < 0 || headX > (cvsW-unit) || headY > (cvsH-unit)) {
	// 	clearInterval(runGame);
	// }

	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;

	// for(let i = 0; i < snake.length; i++) {
	// 	if(headX == snake[i].x && headY == snake[i].y) {
	// 		clearInterval(game);
	// 	}
	// }

	//create new head
	let newHead = {x: headX, y: headY}

	//if snake eats food -do this
	if(headX == food.x && headY == food.y) {
		//create new food position
		while(!checkSnakeForFood()) {
		 	food = {
				x : Math.floor(Math.random()*((cvsW/unit)-1)+1)*unit,
				y : Math.floor(Math.random()*((cvsH/unit)-1)+1)*unit
			}
		}
		
		//add 3 units to the snake
		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 checkSnakeForFood() {
	for(let i = 0; i < snake.length; i++) {
		if(snake[i].x === food.x && snake[i].y === food.y) return false;
	}
	return true;
}
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Snake Game</title>
	<style>
		body {
			background-color: #333;
		}

		canvas {
			background-color: #4d4d4d;
			margin: auto;
			display: block;
			position: absolute;
			left: 0;
			right: 0;
			top: 0;
			bottom: 0;
			width: 750px;
			height: 500px;		
		}
	</style>
</head>
<body>
	<canvas id="canvas"></canvas>
	<script src="script.js"></script>
</body>
</html>

2 个答案:

答案 0 :(得分:0)

尝试将食物包装成for循环+ if语句:

while foodNotPlaced {
snake.forEach(function(segment) {
    if (food.x != segment.x and food.y != segment.y) {
    ctx.fillStyle = 'red';
    ctx.fillRect(food.x, food.y, unit, unit);
    foodIsPlaced = false;
    }
    else {
    food.x = Math.floor(Math.random()*((cvsW/unit)-1)+1)*unit;
    food.y = Math.floor(Math.random()*((cvsW/unit)-1)+1)*unit;
    foodIsPlaced = true;
});
}

然后在while循环内重新运行,以确保将食物放置在其余代码运行之前

import osmnx as ox, networkx as nx, matplotlib.cm as cm, pandas as pd, numpy as np
place = 'City of Lethbridge, Alberta, Canada'
gdf = ox.gdf_from_place(place)
area = ox.project_gdf(gdf).unary_union.area
G = ox.graph_from_place(place, network_type='drive_service')

# calculate basic and extended network stats, merge them together, and display
stats = ox.basic_stats(G, area=area)
extended_stats = ox.extended_stats(G, ecc=True, bc=True, cc=True)
for key, value in extended_stats.items():
    stats[key] = value
pd.Series(stats)

# unpack dicts into individiual keys:values
stats = ox.basic_stats(G, area=area)
for k, count in stats['streets_per_node_counts'].items():
    stats['int_{}_count'.format(k)] = count
for k, proportion in stats['streets_per_node_proportion'].items():
    stats['int_{}_prop'.format(k)] = proportion

# delete the no longer needed dict elements
del stats['streets_per_node_counts']
del stats['streets_per_node_proportion']

# load as a pandas dataframe
pd.DataFrame(pd.Series(stats)).T

G_projected = ox.project_graph(G)
max_node, max_bc = max(extended_stats['betweenness_centrality'].items(), key=lambda x: x[1])
print(max_node, max_bc)


nc = ['r' if node==max_node else '#336699' for node in G_projected.nodes()]
ns = [50 if node==max_node else 8 for node in G_projected.nodes()]
fig, ax = ox.plot_graph(G_projected, node_size=ns, node_color=nc, node_zorder=2)



G_projected = ox.project_graph(G)
in_degree= in_degree_centrality(G_projected) # computing the in_degree 
max_node_deg, max_in_deg= max(in_degree['in_degree_centrality'])

答案 1 :(得分:0)

问题是checkSnakeForFood()不能按您预期的那样工作,因为在测试食物头碰撞时尚未将newHead添加到蛇体内。

仅检查蛇尾,并且checkSnakeForFood()例程报告当前食物放置(在newHead的正下方)不是碰撞,因此不会执行while循环主体,并且食物不动。这是发生的情况的图:

 0123456789
0+--------- 
1|.........
2|.F######.
3|.......##
    ^^^^^^^
       |
only these segments get
tested for collision

newHeadfood具有相同的位置[2, 2],用F表示。它们正在发生碰撞,因此if (headX == food.x && headY == food.y)是正确的。但是,在下一行调用checkSnakeForFood()时,循环#中仅考虑尾部for (let i = 0; i < snake.length; i++)元素。 checkSnakeForFood()然后返回true,while循环再也不会重新定位食物了。

您可以通过在尝试调用unshift之前,newHead进入checkSnakeForFood()来解决此问题,

  //create new head
  let newHead = {
    x: headX,
    y: headY
  }

  //add head to snake, *before* checking for collision with the food
  snake.unshift(newHead);

  //if snake eats food -do this
  if (headX == food.x && headY == food.y) {
    //create new food position
    while (!checkSnakeForFood()) {  // <-- now this will successfully detect
                                    // that the snake head is touching the food

现在,食物头部碰撞将正确记录,并且食物将重新定位,直到不与蛇尾巴头部碰撞:

     0123456789
    0+--------- 
    1|.........
    2|.F######.
    3|.......##
       ^^^^^^^^
           |
    all segments are correctly
    tested for collision

但是,我建议您进行重构以帮助避免此类错误。您可以使snake对象具有用于碰撞和移动的成员函数以及其directiontail的属性。您的draw函数负担很重,并且比其名称所承担的责任还要大。

分离newHead似乎很容易出错;直接在阵列上操纵头部可以避免很多混乱。

同时,这是更新的代码,可让您再次移动(记住,请单击代码段中的Full page链接以正确玩游戏:

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 = {
  x: Math.floor(Math.random() * ((cvsW / unit) - 1) + 1) * unit,
  y: Math.floor(Math.random() * ((cvsH / unit) - 1) + 1) * unit
}

//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;

  // //check if snake hit wall
  // if(headX < 0 || headY < 0 || headX > (cvsW-unit) || headY > (cvsH-unit)) {
  // 	clearInterval(runGame);
  // }

  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;

  // for(let i = 0; i < snake.length; i++) {
  // 	if(headX == snake[i].x && headY == snake[i].y) {
  // 		clearInterval(game);
  // 	}
  // }

  //create new head
  let newHead = {
    x: headX,
    y: headY
  }

  //add head to snake
  snake.unshift(newHead);

  //if snake eats food -do this
  if (headX == food.x && headY == food.y) {
    //create new food position
    while (!checkSnakeForFood()) {
      food = {
        x: Math.floor(Math.random() * ((cvsW / unit) - 1) + 1) * unit,
        y: Math.floor(Math.random() * ((cvsH / unit) - 1) + 1) * unit
      }
    }

    //add 3 units to the snake
    for (let i = 30; i > 0; i--) {
      snake.unshift(newHead);
    }
  } else {
    //remove tail
    snake.pop();
  }
}

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

function checkSnakeForFood() {
  for (let i = 0; i < snake.length; i++) {
    if (snake[i].x === food.x && snake[i].y === food.y) return false;
  }
  return true;
}
body {
  background-color: #333;
}

canvas {
  background-color: #4d4d4d;
  margin: auto;
  display: block;
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  width: 750px;
  height: 500px;
}
<canvas id="canvas"></canvas>