Your first problem is that you use a for...else
loop; and the else
part will be executed if you don't break
the for loop in case of a collision, and thus re-adding the sprite.
The second problem with your code is that while groupcollide
will correctly remove the sprites from their groups, they will be readded since they are still stored in the list you're iterating over with your for
loop (iterating over a sprite group will create a new list every time).
So you can either fix your code with something like this:
for mob in mobs.sprites():
if not mob.groups():
# mob was already removed by a previous iteration of this loop
continue
temp_sprites.add(mob)
mobs.remove(mob)
collision = pygame.sprite.groupcollide(temp_sprites, mobs, True, True)
for col in collision:
# score is just for the game
score += col.size
break
else:
mobs.add(mob)
all_sprites.add(mob)
temp_sprites.remove(mob)
but I would suggest to handle the collision in the update
method of the sprite instead.
def update(self):
# whatever
if pygame.sprite.spritecollide(self, self.mobs, True, collide_rect_not_self):
self.kill()
where self.mobs
is a reference to the mobs
group and collide_rect_not_self
is a simple wrapper around pygame.sprite.collide_rect
:
def collide_rect_not_self(a, b):
if a != b:
return pygame.sprite.collide_rect(a, b)
Here's a full example:
import random
import pygame
def collide_rect_not_self(a, b):
if a != b:
return pygame.sprite.collide_rect(a, b)
class Actor(pygame.sprite.Sprite):
def __init__(self, pos, mobs, static, *grps):
super().__init__(mobs, *grps)
self.image = pygame.Surface((40, 40))
self.rect = self.image.get_rect(center=pos)
self.pos = pygame.Vector2(*pos)
self.vel = pygame.Vector2(random.randint(0, 10), random.randint(0, 10)) if not static else pygame.Vector2(0, 0)
self.mobs = mobs
def update(self):
self.pos += self.vel
if not pygame.display.get_surface().get_rect().contains(self.rect):
self.vel *= -1
self.rect.clamp_ip(pygame.display.get_surface().get_rect())
self.pos = self.rect.center
self.rect.center = self.pos
if pygame.sprite.spritecollide(self, self.mobs, True, collide_rect_not_self):
self.kill()
def main():
pygame.init()
clock = pygame.time.Clock()
screen = pygame.display.set_mode((800, 600))
mobs = pygame.sprite.Group()
all_sprites = pygame.sprite.Group()
while True:
for event in pygame.event.get():
pos = pygame.mouse.get_pos()
if event.type == pygame.QUIT:
return
if event.type == pygame.MOUSEBUTTONDOWN:
Actor(event.pos, mobs, event.button == 1, all_sprites)
screen.fill((255, 255, 255))
all_sprites.update()
all_sprites.draw(screen)
clock.tick(30)
pygame.display.flip()
main()
Use the left mouse button to place a static rect and the other mouse buttons to place a moving one.
