pythonpygamepygame-surface

Hello, I am having problem in getting the monster to go back to were it started running after colliding with the soldier


I created a reset function for the monster when it collide with the soldier to go back to where it started running but it just disappeared.

Is there any how I can make the monster go back from the start and run again after the it collided with the soldier. The soldier have tree health, each time the monster collude with the soldier I want to decrement from the soldier's life and make the monster start running again.

import pygame
import os

pygame.init()

SCREEN_WIDTH = 800
SCREEN_HEIGHT = 550

screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))

# Constants
GRAVITY = 1
BULLET_SPEED = 7
MONSTER_SPEED = 3

# Initialize fonts
pygame.font.init()
LOSE_FONT = pygame.font.SysFont('comicsans', 30)

# Load images
background = pygame.image.load(os.path.join('caractors', 'colorful_sky.jpg')).convert()
ground = pygame.image.load(os.path.join('caractors', 'd_land.png')).convert_alpha()
ground = pygame.transform.scale(ground, (SCREEN_WIDTH, ground.get_height()))

# Define classes
class Soldier(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = pygame.image.load(os.path.join('caractors', 'soldier.png')).convert_alpha()
        self.image = pygame.transform.scale(self.image, (95, 125))
        self.rect = self.image.get_rect(bottomleft=(50, 502))
        self.mask = pygame.mask.from_surface(self.image)
        self.gravity = 0
        self.max_bullets = 3
        self.health = 3
        self.max_hit = 3
        self.hits = 0  # Variable to track the number of hits taken


        # Font for displaying health
        self.font = pygame.font.Font(None, 20)  # You can adjust the font size and style as needed
        self.show_health = True  # Flag to indicate whether to show health

    def draw_health(self, screen):
        if self.show_health:
            health_text = self.font.render(f'+: {self.health}', True, (255, 0, 0))  # Red text
            text_rect = health_text.get_rect(center=(self.rect.centerx, self.rect.top - 10))  # Position above monster's head
            screen.blit(health_text, text_rect.topleft)


    def update(self):
        self.gravity += GRAVITY
        self.rect.y += self.gravity
        if self.rect.bottom >= 502:
            self.rect.bottom = 502

    def jump(self):
        if self.rect.bottom >= 502 and self.gravity >= 0:
            self.gravity = -18

    def move_left(self):
        self.rect.x -= 5

    def move_right(self):
        self.rect.x += 5

  
    # ... (your existing methods)

    def reduce_health(self):
        self.hits += 1
        self.health -= 1

class Monster(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = pygame.image.load(os.path.join('caractors', 'monster.png')).convert_alpha()
        self.image = pygame.transform.scale(self.image, (55, 57))
        self.rect = self.image.get_rect(bottomright=(SCREEN_WIDTH, 502))
        self.mask = pygame.mask.from_surface(self.image)
        self.health = 3
        
        # Font for displaying health
        self.font = pygame.font.Font(None, 20)  # You can adjust the font size and style as needed
        self.show_health = True  # Flag to indicate whether to show health

    def draw_health(self, screen):
        if self.show_health:
            health_text = self.font.render(f'+: {self.health}', True, (255, 0, 0))  # Red text
            text_rect = health_text.get_rect(center=(self.rect.centerx, self.rect.top - 10))  # Position above monster's head
            screen.blit(health_text, text_rect.topleft)

    def update(self):
        self.rect.x -= MONSTER_SPEED
        if self.rect.right <= 0:
            self.rect.left = SCREEN_WIDTH

    def reset(self):
        self.rect.left = SCREEN_WIDTH
        self.health += 3

    def reduce_health(self):
        self.health -= 1

class Bullet(pygame.sprite.Sprite):
    def __init__(self, x, y):
        super().__init__()
        self.image = pygame.Surface((5, 5))
        self.image.fill((255, 0, 0))
        self.rect = self.image.get_rect(midleft=(x, y))

    def update(self):
        self.rect.x += BULLET_SPEED

def draw_lose(screen, text):
    lose_text = LOSE_FONT.render(text, 1, (255, 0, 0))
    screen.blit(lose_text, (200, 100))
    pygame.display.flip()
    pygame.time.delay(4000)

def main():
    screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
    pygame.display.set_caption('Runner')

    all_sprites = pygame.sprite.Group()
    soldiers = pygame.sprite.Group()
    monsters = pygame.sprite.Group()
    bullets = pygame.sprite.Group()

    soldier = Soldier()
    monster = Monster()
    all_sprites.add(soldier, monster)
    soldiers.add(soldier)
    monsters.add(monster)

    clock = pygame.time.Clock()
    run = True

    game_over = False  # Flag to indicate game over state

    while run and not game_over:
        clock.tick(60)

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False

            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_SPACE and len(bullets) < soldier.max_bullets:
                    bullet = Bullet(soldier.rect.right - 20, soldier.rect.centery + 20)
                    all_sprites.add(bullet)
                    bullets.add(bullet)

        keys = pygame.key.get_pressed()
        if keys[pygame.K_UP]:
            soldier.jump()
        if keys[pygame.K_LEFT]:
            soldier.move_left()
        if keys[pygame.K_RIGHT]:
            soldier.move_right()

        hits = pygame.sprite.groupcollide(monsters, bullets, False, True)  # Use groupcollide instead of spritecollide
        for monster, bullet_list in hits.items():
            monster.health -= len(bullet_list)
            if monster.health <= 0:
                monster.rect.left = 800
                monster.health = 3

        
        collisions = pygame.sprite.groupcollide(soldiers, monsters, False, True, pygame.sprite.collide_mask)
        for soldier, monster_list in collisions.items():
            # Decrease soldier's lives when colliding with the monste
            soldier.health -= len(monster_list)
            for monster in monster_list:
                monster.reset()  # Reset the monster's position
    
        # if soldier.s_health <= 0:
                #lose = True

        all_sprites.update()

        screen.blit(background, (0, 0))
        screen.blit(ground, (0, SCREEN_HEIGHT - ground.get_height() + 20))
        all_sprites.draw(screen)

        for monster in monsters:
            monster.draw_health(screen)

        for soldier in soldiers:
            soldier.draw_health(screen)

        #if game_over:
           # draw_lose(screen, "YOU LOSE")  # Display "YOU LOSE" message


        pygame.display.flip()


    pygame.quit()

if __name__ == '__main__':
```

Solution

  • In the line

    collisions = pygame.sprite.groupcollide(soldiers, monsters, False, True, pygame.sprite.collide_mask)
    

    the fourth parameter is set to True, which removes the monster from its spritegroups. Set this to False and the monster will appear again.