Pygame – colisión sprite con grupo de sprite

He creado dos sprites simples en PyGame y uno de ellos es un paraguas, el otro es una gota de lluvia. Las gotas de lluvia se agregan a un grupo de all_sprites llamado all_sprites . El sprite Umbrella tiene su propio grupo llamado Umbrella_sprite

Las gotas de lluvia están “cayendo” desde la parte superior de la pantalla y si una de ellas toca el paraguas / choca con él … se supone que la gota de lluvia se eliminará. PERO en lugar de las gotas de lluvia específicas, todas las demás se ven afectadas por esto.

archivo principal (rain.py)

 #!/usr/bin/python VERSION = "0.1" import os, sys, raindrop from os import path try: import pygame from pygame.locals import * except ImportError, err: print 'Could not load module %s' % (err) sys.exit(2) # main variables WIDTH, HEIGHT, FPS = 300, 300, 30 # initialize game pygame.init() screen = pygame.display.set_mode((WIDTH,HEIGHT)) pygame.display.set_caption("Rain and Rain") # background background = pygame.Surface(screen.get_size()) background = background.convert() background.fill((40,44,52)) # blitting screen.blit(background,(0,0)) pygame.display.flip() # clock for FPS settings clock = pygame.time.Clock() def main(): all_sprites = pygame.sprite.Group() umbrella_sprite = pygame.sprite.Group() # a function to create new drops def newDrop(): nd = raindrop.Raindrop() all_sprites.add(nd) # creating 10 rain drops for x in range(0,9): newDrop() # variable for main loop running = True # init umbrella umb = raindrop.Umbrella() # all_sprites.add(umb) umbrella_sprite.add(umb) # event loop while running: clock.tick(FPS) for event in pygame.event.get(): if event.type == pygame.QUIT: running = False for enemy in all_sprites: gets_hit = pygame.sprite.spritecollideany(umb, all_sprites) if gets_hit: all_sprites.remove(enemy) screen.blit(background,(100,100)) # clear all_sprites.clear(screen,background) umbrella_sprite.clear(screen,background) # update all_sprites.update() umbrella_sprite.update() # draw all_sprites.draw(screen) umbrella_sprite.draw(screen) # flip the table pygame.display.flip() pygame.quit() if __name__ == '__main__': main() 

raindrop.py (Raindrop () & Umbrella ())

 import pygame from pygame.locals import * from os import path from random import randint from rain import HEIGHT, WIDTH img_dir = path.join(path.dirname(__file__), 'img') class Raindrop(pygame.sprite.Sprite): def __init__(self): pygame.sprite.Sprite.__init__(self) self.width = randint(32, 64) self.height = self.width + 33 self.image = pygame.image.load(path.join(img_dir, "raindrop.png")).convert_alpha() self.image = pygame.transform.scale(self.image, (self.width, self.height)) self.speedy = randint(1, 15) self.rect = self.image.get_rect() self.rect.x = randint(0, 290) self.rect.y = -self.height def reset(self): self.rect.y = -self.height def update(self): self.rect.y += self.speedy if self.rect.y >= HEIGHT: self.rect.y = -self.height self.rect.x = randint(0, 290) class Umbrella(pygame.sprite.Sprite): def __init__(self): pygame.sprite.Sprite.__init__(self) self.width = 50 self.height = 50 self.image = pygame.image.load(path.join(img_dir,"umbrella.png")).convert_alpha() self.image = pygame.transform.scale(self.image, (self.width, self.height)) self.speedx = 10 self.rect = self.image.get_rect() self.rect.x = (WIDTH/2) - self.width self.rect.y = (0.7 * HEIGHT) def update(self): keys = pygame.key.get_pressed() if keys[pygame.K_LEFT] and self.rect.x > 0: self.rect.x -= self.speedx elif keys[pygame.K_RIGHT] and self.rect.x < (WIDTH - self.width): self.rect.x += self.speedx 

Este es tu problema:

 for enemy in all_sprites: gets_hit = pygame.sprite.spritecollideany(umb, all_sprites) if gets_hit: all_sprites.remove(enemy) 

Estás recorriendo el grupo, y si algún sprite colisiona, borra todos.

No es necesario recorrer el grupo, las funciones de colisión se encargan de eso. Solo necesita usar la función spritecollide, que compara un sprite con un grupo. Esa función devolverá una lista de colisiones, así como el uso del indicador DOKILL para eliminarlos automáticamente:

  gets_hit = pygame.sprite.spritecollide(umb, all_sprites, True) 

spritecollideany verifica si el sprite colisiona con algún sprite en el grupo y devuelve este sprite, por lo que gets_hit es un valor verdadero siempre que el sprite colisionado en el grupo no se elimine y se if gets_hit: bloque if gets_hit: . Eso significa que el código en el bucle for simplemente continúa eliminando cada sprite del grupo que aparece antes de que se scope y elimine el sprite colisionado. Una solución simple sería comprobar si el sprite hit es el enemigo: if enemy == gets_hit: pero el código aún sería ineficaz, porque spritecollideany tiene que recorrer el grupo all_sprites una y otra vez dentro del bucle for.

Recomiendo usar spritecollide lugar de spritecollideany también, ya que es más eficiente y solo una línea de código.