尝试在pygame中实现碰撞时pygame.sprite.groupcollide()不起作用 [英] pygame.sprite.groupcollide() does not work when trying to implement collision in pygame

查看:158
本文介绍了尝试在pygame中实现碰撞时pygame.sprite.groupcollide()不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在做一个Snake Game项目,我不能使蛇和食物发生碰撞.阅读了一些Pygame文档后,我决定使用 pygame.sprite.groupcollide 进行碰撞.我的游戏中有两种精灵:

I'm working on a Snake Game project, and I can't make the snake and the foods collide. After reading some Pygame documentation, I decided to use pygame.sprite.groupcollide for collisions. I have two types of sprites in my game:

  1. 食物

pygame.sprite.groupcollide 在我以前的游戏(一本Python书中的Alien Invasion游戏)中工作过;但是,由于某种原因,它在我当前的游戏中不起作用.您认为可能是什么原因?这是碰撞部分(snake_game.py)的亮点:

pygame.sprite.groupcollide has worked in my previous game (Alien Invasion game from a Python book); however, for some reason it doesn't work in my current game. What do you think might be the reason? Here is the higlight of the collisions part (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 :

[...]如果任何一个dokill参数为True,则将碰撞的Sprite从其各自的组中删除.

[...] 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 对象.

and a collision is detected and the food is removed from the Group self.foods. However, the self.food attribute still refers to the Food object.

食物在 Group 中,直到检测到碰撞为止.因此,您必须在 Group self.foods 中绘制对象,而不是

The food is in the Group until a collision is detected. Hence you have to draw the objects in the Group self.foods rather than the Sprite object self.food. You don't even need the self.food attribute. It is sufficient if all Food objects are contained in self.foods:

self.food.draw_food()

for food in self.foods.sprites():
    food.draw_food()


请注意,您的代码中实际上并未调用 _check_snake_food_collisions .

这篇关于尝试在pygame中实现碰撞时pygame.sprite.groupcollide()不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆