Sprite movement not working when using Sprite groups

Viewed 22

The point of the game is that the enemies move towards you and if the hammer collides with them then they disappear. But for some reason the enemies either don't move or don't disappear when hit. Here is the code for checking collisions:

if len(enemy_group) <= 0:
    enemy = Enemy(random.randint(0, 1000), random.randint(0, 700))
    enemy_group.add(enemy)

for enemy in enemy_group:
    enemy.move(player.x, player.y)
    if pygame.sprite.spritecollide(hammer, enemy_group, True):
        move_away, move_back = False, True

enemy_group.draw(screen)

This code does remove the enemies if they are hit, but they aren't moving towards the player. If instead I do this:

if len(enemy_group) <= 0:
    enemy = Enemy(random.randint(0, 1000), random.randint(0, 700))
    enemy_group.add(enemy)

for enemy in enemy_group:
    enemy.move(player.x, player.y)
    enemy.draw(screen)
    if pygame.sprite.spritecollide(hammer, enemy_group, True):
        move_away, move_back = False, True

Then the enemies move towards the player, but they don't disappear when hit. I can't get them to do both.

In case it is needed, here are both the hammer and enemy classes:

class Hammer:
    def __init__(self, x, y, image):
        self.image = image
        self.x = x
        self.y = y
        self.rect = self.image.get_rect(center = (self.x, self.y))
        self.rot = 0

    def draw(self, screen):
        screen.blit(self.rot_image, (self.rect))

    def get_movement_hammer(self, x, y):
        dirx, diry = x - self.x, y - self.y
        direc = dirx, diry
        
        length = math.hypot(*direc)

        if length == 0.0:
            dirx, diry = 0, -1
                
        else: 
            dirx, diry = dirx/length, diry/length

        return dirx, diry

    def move_hammer(self, dirx, diry, xspeed, yspeed):
        self.rot_speed = 15
        self.rot = (self.rot + self.rot_speed) % 360
        self.rot_image = pygame.transform.rotozoom(self.image, self.rot, 1)
        self.rect = self.rot_image.get_rect(center = (self.x, self.y))
        
        self.x += (dirx * xspeed)      
        self.y += (diry * yspeed)


class Enemy(pygame.sprite.Sprite):
    def __init__(self, x, y):
        pygame.sprite.Sprite.__init__(self)

        self.x = x
        self.y = y
        self.image = enemy_image
        self.rect = self.image.get_rect(center = (self.x, self.y))

    def move(self, px, py):
        dirx, diry = px - self.x, py - self.y
        direc = dirx, diry
        
        length = math.hypot(*direc)

        if length == 0.0:
            dirx, diry = 0, -1
                
        else: 
            dirx, diry = dirx/length, diry/length

        self.x += dirx * 2
        self.y += diry * 2

    def draw(self, screen):
        screen.blit(self.image, (self.x, self.y))

1 Answers

Read the documentation pygame.sprite.Group.draw():

Draws the contained Sprites to the Surface argument. This uses the Sprite.image attribute for the source surface, and Sprite.rect for the position.

The rect attribute is also used for collision detection (e.g. pygame.sprite.spritecollide). Therefore, you will need to update the enemy's rect attribute after moving it:

class Enemy(pygame.sprite.Sprite):
    # [...]

     def move(self, px, py):
        dirx, diry = px - self.x, py - self.y
        direc = dirx, diry
        
        length = math.hypot(*direc)

        if length == 0.0:
            dirx, diry = 0, -1
                
        else: 
            dirx, diry = dirx/length, diry/length

        self.x += dirx * 2
        self.y += diry * 2

        self.rect.center = round(self.x), round(self.y)  # <---

    # [...]
Related