python - 从蛇游戏中的随机食物中排除蛇的坐标
问题描述
我正在做一个蛇游戏项目。当你开始游戏时,屏幕上的随机位置会弹出一个食物;然而,食物也有可能会从蛇身上弹出。我该如何解决这个问题?这是我的代码:
蛇游戏.py
import pygame
import sys
from random import randint
from settings import Settings
from snake import Snake
from food import Food
class SnakeGame:
'''The main class of the game.'''
def __init__(self):
'''Initialize the game assets, screen, etc.'''
pygame.init()
self.settings = Settings()
self.screen = pygame.display.set_mode((self.settings.screen_width,
self.settings.screen_height))
pygame.display.set_caption("Snake Game")
self.snake_parts = pygame.sprite.Group() #Will do some refactoring here.
self.snake_part = Snake(self) # Will move this part elsewhere.
self.snake_parts.add(self.snake_part)
self.food = Food(self)
def run_game(self):
'''The main loop of the game.'''
while True:
self._check_events()
self._update_snake_parts()
self._update_screen()
def _check_events(self):
'''Check all the events.'''
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
self._check_keydown_events(event)
elif event.type == pygame.KEYUP:
self._check_keyup_events(event)
def _check_keydown_events(self, event):
'''Check keydown events.'''
if event.key == pygame.K_UP or event.key == pygame.K_w:
self.snake_part.m_up = True
elif event.key == pygame.K_DOWN or event.key == pygame.K_s:
self.snake_part.m_down = True
elif event.key == pygame.K_LEFT or event.key == pygame.K_a:
self.snake_part.m_left = True
elif event.key == pygame.K_RIGHT or event.key == pygame.K_d:
self.snake_part.m_right = True
elif event.key == pygame.K_q:
sys.exit()
def _check_keyup_events(self, event):
'''Check keyup events.'''
if event.key == pygame.K_UP or event.key == pygame.K_w:
self.snake_part.m_up = False
elif event.key == pygame.K_DOWN or event.key == pygame.K_s:
self.snake_part.m_down = False
elif event.key == pygame.K_LEFT or event.key == pygame.K_a:
self.snake_part.m_left = False
elif event.key == pygame.K_RIGHT or event.key == pygame.K_d:
self.snake_part.m_right = False
def _check_snake_food_collisions(self):
'''Check the collisions between the snake and foods.'''
pass
def _update_snake_parts(self):
'''Update all the parts of the snake.'''
self.snake_parts.update()
def _update_screen(self):
'''Update the screen.'''
self.screen.fill(self.settings.bg_color)
# Draw snake parts to the screen.
for snake_part in self.snake_parts.sprites():
snake_part.draw_part()
# Draw foods to the screen.
self.food.draw_food()
pygame.display.flip()
if __name__ == '__main__':
sg = SnakeGame()
sg.run_game()
食物.py
import pygame
from random import randint
class Food:
'''A class to manage the foods.'''
def __init__(self, sg):
'''Initialize the food rect, food color, and other assets.'''
self.screen = sg.screen
self.settings = sg.settings
self.color = self.settings.food_color
self.rect = pygame.Rect(0, 0, self.settings.food_width,
self.settings.food_height)
# Initialize the food at a random position.
self.spawn_food()
def spawn_food(self):
'''Position the food at a random position.'''
self.rect.x = randint(0, self.settings.screen_width)
self.rect.y = randint(0, self.settings.screen_height)
def draw_food(self):
'''Draw the food to the screen.'''
pygame.draw.rect(self.screen, self.color, self.rect)
蛇.py
import pygame
import sys
from pygame.sprite import Sprite
class Snake(Sprite):
'''A class to manage the snake.'''
def __init__(self, sg):
'''Initialize the snake's location, size, etc.'''
super().__init__()
self.screen = sg.screen
self.settings = sg.settings
self.color = self.settings.snake_color
self.screen_rect = self.screen.get_rect()
# Create the snake's rect object and position it.
self.rect = pygame.Rect(0,0, self.settings.snake_width,
self.settings.snake_height)
self.rect.center = self.screen_rect.center
# Get the precise coordinates of the snake.
self.x = float(self.rect.x)
self.y = float(self.rect.y)
# Set movement flags.
self.m_right = False
self.m_left = False
self.m_up = False
self.m_down = False
def update(self):
'''Update the position of the snake.'''
if self.m_right and self.rect.right < self.screen_rect.right:
self.x += self.settings.snake_speed
if self.m_left and self.rect.left > self.screen_rect.left:
self.x -= self.settings.snake_speed
if self.m_down and self.rect.bottom < self.screen_rect.bottom:
self.y += self.settings.snake_speed
if self.m_up and self.rect.top > self.screen_rect.top:
self.y -= self.settings.snake_speed
self.rect.x = self.x
self.rect.y = self.y
def draw_part(self):
'''Draw the snake to the screen.'''
pygame.draw.rect(self.screen, self.color, self.rect)
设置.py
class Settings:
'''Class for game settings.'''
def __init__(self):
'''Initialize the game settings.'''
# Screen settings
self.screen_width = 1200
self.screen_height = 800
self.bg_color = (119, 181, 254) # Blue color
# Snake settings
self.snake_width = 20
self.snake_height = 20
self.snake_color = (255, 255, 0) # Yellow color
self.snake_speed = 1
# Food settings
self.food_width = 10
self.food_height = 10
self.food_color = (139, 69, 19) # Brown color
我试过下面的伪代码来解决这个问题:
if food_coordinate_x == snake_coordinate_x:
do something which fixes this issue (I have no idea how to fix this)
提前致谢!
解决方案
一种通用的方法是只为食物绘制位置,直到您满意为止:
food_coordinate_x = sample_new_food()
while food_coordinate_x == snake_coordinate_x:
food_coordinate_x = sample_new_food()
在您的具体情况下,这可能看起来像这样:
def spawn_food(self, blocked_positions):
"""
blocked_positions: list of (x, y) pairs of blocked positions on the grid
ie the snake body
"""
while True:
self.rect.x = randint(0, self.settings.screen_width)
self.rect.y = randint(0, self.settings.screen_height)
valid = True
for xb, yb in blocked_positions:
if xb == self.rect.x and yb == self.rect.y:
valid = False
break
if valid:
break
另一种可能性是仅从空白空间中采样。这当然取决于你的实现,但我想在某些时候你的世界有一个网格,这个世界的某些部分被蛇占据了。
import numpy as np
# Dummy data
world = np.zeros((10, 10), dtype=int)
snake = np.array([[5, 5], # x and y positions of the cells occupied by the snake
[5, 6], # ordered from head to tail
[5, 7],
[4, 7],
[4, 8],
[4, 9],
[5, 9],
[6, 9],
[7, 9]])
world[snake[:, 0], snake[:, 1]] = 1
# array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0, 0, 1, 1, 1],
# [0, 0, 0, 0, 0, 1, 1, 1, 0, 1],
# [0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
# [0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
# [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])
empty_space = np.array(np.nonzero(world == 0)).T
# Sample new food coordinate from the empty space
food_coordinate = empty_space[np.random.randint(low=0, high=len(empty_space)), :]
这样的程序可以很容易地扩展到更多的障碍物,比如现有的食物,以进一步缩小采样的空白空间。而在游戏结束时,蛇几乎占据了整个屏幕,在这种方法中,您不需要长时间采样,但仍然只需一次。
推荐阅读
- php - 如何在 spatie 权限包中列出所有具有权限的角色?
- ios - 我如何将所有联系人的电话号码编译到一个单元格中 - 使用 CNContact
- python - 如何在 Django 框架的 HTML 页面中显示图像?
- asterisk - 如何添加事件监听器来调用挂断 PHP AGI?
- java - UsernamePasswordAuthenticationFilter 跳过成功处理程序
- c++ - 如何使用递归在 .txt 中编写多行?
- javascript - 如何在反应循环中设置动态复选框的状态?
- java - 无法在 Java 中找到确切日期匹配的 Mongodb 文档
- c - 计算总数 文件中的关键字
- c++ - 如何使用 asn1c 生成的代码解码 MAP Invoke 消息