首页 > 解决方案 > 从蛇游戏中的随机食物中排除蛇的坐标

问题描述

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

蛇游戏.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)

提前致谢!

标签: pythonrandompygame

解决方案


一种通用的方法是只为食物绘制位置,直到您满意为止:

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

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


推荐阅读