pygame.sprite.groupcollide() 尝试在 pygame 中实施碰撞时不起作用
pygame.sprite.groupcollide() does not work when trying to implement collision in pygame
我正在做一个贪吃蛇游戏项目,我不能让蛇和食物发生碰撞。在阅读了一些 Pygame 文档之后,我决定使用 pygame.sprite.groupcollide
来处理碰撞。我的游戏中有两种精灵:
- 蛇
- 食物
pygame.sprite.groupcollide
在我以前的游戏中有效(来自 Python 一本书的外星人入侵游戏);但是,出于某种原因,它在我当前的游戏中不起作用。您认为可能是什么原因?这是碰撞部分的亮点(snake_game.py):
def _check_snake_food_collisions(self):
'''Check the collisions between the snake and foods.'''
collisions = pygame.sprite.groupcollide(self.foods, self.snake_parts, True, False)
这是我的代码:
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.foods = pygame.sprite.Group()
self.food = Food(self) # Will do some refactoring here as well.
self.foods.add(self.food) # Will move this part elsewhere.
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.'''
collisions = pygame.sprite.groupcollide(self.foods, self.snake_parts, True, False)
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()
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)
food.py
import pygame
from random import randint
from pygame.sprite import Sprite
class Food(Sprite):
'''A class to manage the foods.'''
def __init__(self, sg):
'''Initialize the food rect, food color, and other assets.'''
super().__init__()
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.settings.food_width)
self.rect.y = randint(0, self.settings.screen_height -
self.settings.food_height)
def draw_food(self):
'''Draw the food 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
阅读pygame.sprite.groupcollide
的文档:
[...] If either dokill argument is True, the colliding Sprites will be removed from their respective Group.
当你做的时候
collisions = pygame.sprite.groupcollide(self.foods, self.snake_parts, True, False)
并检测到碰撞,食物从 Group self.foods
中移除。
但是,self.food
属性仍然引用 Food
对象。
食物在 组 中,直到检测到碰撞。因此,您必须绘制 Group self.foods
中的对象,而不是 Sprite 对象 self.food
中的对象。您甚至不需要 self.food
属性。如果所有 Food
个对象都包含在 self.foods
:
中就足够了
self.food.draw_food()
for food in self.foods.sprites():
food.draw_food()
请注意,您的代码实际上并未调用 _check_snake_food_collisions
。
我正在做一个贪吃蛇游戏项目,我不能让蛇和食物发生碰撞。在阅读了一些 Pygame 文档之后,我决定使用 pygame.sprite.groupcollide
来处理碰撞。我的游戏中有两种精灵:
- 蛇
- 食物
pygame.sprite.groupcollide
在我以前的游戏中有效(来自 Python 一本书的外星人入侵游戏);但是,出于某种原因,它在我当前的游戏中不起作用。您认为可能是什么原因?这是碰撞部分的亮点(snake_game.py):
def _check_snake_food_collisions(self):
'''Check the collisions between the snake and foods.'''
collisions = pygame.sprite.groupcollide(self.foods, self.snake_parts, True, False)
这是我的代码:
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.foods = pygame.sprite.Group()
self.food = Food(self) # Will do some refactoring here as well.
self.foods.add(self.food) # Will move this part elsewhere.
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.'''
collisions = pygame.sprite.groupcollide(self.foods, self.snake_parts, True, False)
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()
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)
food.py
import pygame
from random import randint
from pygame.sprite import Sprite
class Food(Sprite):
'''A class to manage the foods.'''
def __init__(self, sg):
'''Initialize the food rect, food color, and other assets.'''
super().__init__()
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.settings.food_width)
self.rect.y = randint(0, self.settings.screen_height -
self.settings.food_height)
def draw_food(self):
'''Draw the food 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
阅读pygame.sprite.groupcollide
的文档:
[...] If either dokill argument is True, the colliding Sprites will be removed from their respective Group.
当你做的时候
collisions = pygame.sprite.groupcollide(self.foods, self.snake_parts, True, False)
并检测到碰撞,食物从 Group self.foods
中移除。
但是,self.food
属性仍然引用 Food
对象。
食物在 组 中,直到检测到碰撞。因此,您必须绘制 Group self.foods
中的对象,而不是 Sprite 对象 self.food
中的对象。您甚至不需要 self.food
属性。如果所有 Food
个对象都包含在 self.foods
:
self.food.draw_food()
for food in self.foods.sprites():
food.draw_food()
请注意,您的代码实际上并未调用 _check_snake_food_collisions
。