python - 从贪吃蛇游戏中的随机食物坐标中排除蛇的坐标

标签 python random pygame

我正在开发一个贪吃蛇游戏项目。当你开始游戏时,屏幕上的随机位置会弹出食物;然而,食物也有可能会突然出现在蛇身上。我该如何解决这个问题? 这是我的代码:

snake_game.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()

food.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)

snake.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)

settings.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)), :]

这样的程序可以很容易地扩展到更多的障碍物,例如现有的食物,以进一步缩小采样的空白空间。在最终游戏中,当蛇几乎占据整个屏幕时,在这种方法中,您不需要采样很长时间,但仍然只需采样一次。

关于python - 从贪吃蛇游戏中的随机食物坐标中排除蛇的坐标,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63871023/

相关文章:

java - 如何打印字符串中的随机字符?

python - 如何生成整数的随机正态分布

python - Pygame,OpenGL : Project 3D rgb values to 2D surface

python - Pygame:如何正确使用 get_rect()

python - Pygame 程序并不总是在按下红叉后退出

python - 有 OrderedDict 理解吗?

Python/Pyspark - 计算 NULL、空和 NaN

javascript - 随机化数组以激活函数

python - 函数默认仅返回第一个输出值

python - 如何计算 python 列表中的可能性