Mr Do! Part II

Part I

Prompt

move the enemies in some direction randomly and only if there are no walls between the player and the enemy make the enemy chace the player. make the ball direction to be diagonal up and then bounce in diagonal down and the up and so on. If the player eats all cherry go to level 2 with one more enemy for every new level

To address your requirements, we’ll make the following changes:

  1. Move Enemies Randomly: Enemies will move in a random direction unless there are no walls between the player and the enemy, in which case they will chase the player.
  2. Ball Direction: The ball will move diagonally and bounce between diagonal up and diagonal down.
  3. Level Up: When all cherries are eaten, the game advances to the next level with one additional enemy.

Here’s the updated code:

import pygame
import random
import math

# Initialize Pygame
pygame.init()

# Set up the display
WIDTH, HEIGHT = 800, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Mr. Do!-like Game")

# Colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
WALL_COLOR = (100, 50, 0)
BALL_COLOR = (255, 165, 0)  # Orange

# Grid settings
GRID_SIZE = 40
GRID_WIDTH = WIDTH // GRID_SIZE
GRID_HEIGHT = HEIGHT // GRID_SIZE

# Font
font = pygame.font.Font(None, 36)

# Game variables
player_x = player_y = 1
player_direction = 0  # 0: right, 1: down, 2: left, 3: up
enemies = []
cherries = []
score = 0
game_over = False
level = 1

# Ball variables
ball_x = ball_y = None
ball_direction = None
ball_active = False

def create_labyrinth():
    labyrinth = [[1 for _ in range(GRID_WIDTH)] for _ in range(GRID_HEIGHT)]

    def create_path(x, y):
        labyrinth[y][x] = 0
        directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]
        random.shuffle(directions)
        for dx, dy in directions:
            nx, ny = x + dx*2, y + dy*2
            if 0 <= nx < GRID_WIDTH and 0 <= ny < GRID_HEIGHT and labyrinth[ny][nx] == 1:
                labyrinth[y + dy][x + dx] = 0
                create_path(nx, ny)

    create_path(1, 1)
    return labyrinth

def place_cherries():
    return [(x, y) for y in range(GRID_HEIGHT) for x in range(GRID_WIDTH) 
            if labyrinth[y][x] == 0 and random.random() < 0.1]

def place_enemies():
    enemy_list = []
    while len(enemy_list) < level + 2:
        x, y = random.randint(0, GRID_WIDTH - 1), random.randint(0, GRID_HEIGHT - 1)
        if labyrinth[y][x] == 0 and (x, y) != (player_x, player_y):
            enemy_list.append([x, y])
    return enemy_list

def can_chase_player(enemy_x, enemy_y):
    if enemy_x == player_x:
        if all(labyrinth[y][enemy_x] == 0 for y in range(min(enemy_y, player_y), max(enemy_y, player_y) + 1)):
            return True
    if enemy_y == player_y:
        if all(labyrinth[enemy_y][x] == 0 for x in range(min(enemy_x, player_x), max(enemy_x, player_x) + 1)):
            return True
    return False

def move_enemy(enemy):
    if can_chase_player(enemy[0], enemy[1]):
        return move_towards(enemy, player_x, player_y)
    else:
        possible_moves = [(1, 0), (0, 1), (-1, 0), (0, -1)]
        random.shuffle(possible_moves)
        for dx, dy in possible_moves:
            new_x, new_y = enemy[0] + dx, enemy[1] + dy
            if 0 <= new_x < GRID_WIDTH and 0 <= new_y < GRID_HEIGHT and labyrinth[new_y][new_x] == 0:
                return (new_x, new_y)
        return (enemy[0], enemy[1])

def move_towards(enemy, target_x, target_y):
    dx = target_x - enemy[0]
    dy = target_y - enemy[1]
    if abs(dx) > abs(dy):
        return (enemy[0] + (1 if dx > 0 else -1), enemy[1])
    else:
        return (enemy[0], enemy[1] + (1 if dy > 0 else -1))

def launch_ball():
    global ball_x, ball_y, ball_direction, ball_active
    if not ball_active:
        ball_x, ball_y = player_x, player_y
        ball_direction = 0  # Start moving diagonally up
        ball_active = True

def move_ball():
    global ball_x, ball_y, ball_direction, ball_active, enemies, score
    if ball_active:
        directions = [(1, -1), (1, 1), (-1, 1), (-1, -1)]
        dx, dy = directions[ball_direction]
        new_x, new_y = ball_x + dx, ball_y + dy

        if 0 <= new_x < GRID_WIDTH and 0 <= new_y < GRID_HEIGHT:
            if labyrinth[new_y][new_x] == 1:
                ball_direction = (ball_direction + 2) % 4  # Bounce diagonally
            else:
                ball_x, ball_y = new_x, new_y

                # Check for enemy collision
                for enemy in enemies[:]:
                    if ball_x == enemy[0] and ball_y == enemy[1]:
                        enemies.remove(enemy)
                        score += 50
                        ball_active = False
                        return

                # Check for player collision
                if ball_x == player_x and ball_y == player_y:
                    ball_active = False
        else:
            ball_direction = (ball_direction + 2) % 4  # Reverse direction at screen edge

def draw_game():
    screen.fill(BLACK)

    # Draw labyrinth
    for y in range(GRID_HEIGHT):
        for x in range(GRID_WIDTH):
            if labyrinth[y][x] == 1:
                pygame.draw.rect(screen, WALL_COLOR, (x * GRID_SIZE, y * GRID_SIZE, GRID_SIZE, GRID_SIZE))
                pygame.draw.rect(screen, BLACK, (x * GRID_SIZE + 2, y * GRID_SIZE + 2, GRID_SIZE - 4, GRID_SIZE - 4))

    # Draw player
    pygame.draw.circle(screen, WHITE, (player_x * GRID_SIZE + GRID_SIZE // 2, player_y * GRID_SIZE + GRID_SIZE // 2), GRID_SIZE // 2 - 2)

    # Draw cherries
    for cherry in cherries:
        pygame.draw.circle(screen, RED, (cherry[0] * GRID_SIZE + GRID_SIZE // 2, cherry[1] * GRID_SIZE + GRID_SIZE // 2), GRID_SIZE // 4)

    # Draw enemies
    for enemy in enemies:
        pygame.draw.rect(screen, GREEN, (enemy[0] * GRID_SIZE + 2, enemy[1] * GRID_SIZE + 2, GRID_SIZE - 4, GRID_SIZE - 4))

    # Draw ball
    if ball_active:
        pygame.draw.circle(screen, BALL_COLOR, (ball_x * GRID_SIZE + GRID_SIZE // 2, ball_y * GRID_SIZE + GRID_SIZE // 2), GRID_SIZE // 4)

    # Draw score
    score_text = font.render(f"Score: {score}", True, WHITE)
    screen.blit(score_text, (10, 10))

    if game_over:
        game_over_text = font.render("Game Over! Press R to Restart", True, WHITE)
        screen.blit(game_over_text, (WIDTH // 2 - game_over_text.get_width() // 2, HEIGHT // 2 - game_over_text.get_height() // 2))

    pygame.display.flip()

def reset_game():
    global player_x, player_y, player_direction, enemies, cherries, score, game_over, labyrinth, ball_active, level
    player_x = player_y = 1
    player_direction = 0
    labyrinth = create_labyrinth()
    cherries = place_cherries()
    enemies = place_enemies()
    score = 0
    game_over = False
    ball_active = False

# Initial game setup
reset_game()

# Game loop
running = True
clock = pygame.time.Clock()

while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN:
            if game_over:
                if event.key == pygame.K_r:
                    reset_game()
            else:
                new_x, new_y = player_x, player_y
                if event.key == pygame.K_LEFT:
                    new_x -= 1
                    player_direction = 2
                elif event.key == pygame.K_RIGHT:
                    new_x += 1
                    player_direction = 0
                elif event.key == pygame.K_UP:
                    new_y -= 1
                    player_direction = 3
                elif event.key == pygame.K_DOWN:
                    new_y += 1
                    player_direction = 1
                elif event.key == pygame.K_z:
                    # Destroy wall
                    dx, dy = [(1,

 0), (0, 1), (-1, 0), (0, -1)][player_direction]
                    wall_x, wall_y = player_x + dx, player_y + dy
                    if 0 <= wall_x < GRID_WIDTH and 0 <= wall_y < GRID_HEIGHT:
                        if labyrinth[wall_y][wall_x] == 1:
                            labyrinth[wall_y][wall_x] = 0
                            score += 5
                elif event.key == pygame.K_x:
                    launch_ball()

                if 0 <= new_x < GRID_WIDTH and 0 <= new_y < GRID_HEIGHT and labyrinth[new_y][new_x] == 0:
                    player_x, player_y = new_x, new_y

    if not game_over:
        # Move enemies
        for enemy in enemies:
            new_pos = move_enemy(enemy)
            enemy[0], enemy[1] = new_pos

        # Move ball
        move_ball()

        # Check collisions
        if (player_x, player_y) in cherries:
            cherries.remove((player_x, player_y))
            score += 10

        if [player_x, player_y] in enemies:
            game_over = True

        # Level up
        if not cherries:
            level += 1
            cherries = place_cherries()
            enemies = place_enemies()

    draw_game()
    clock.tick(10)  # Slower speed for grid-based movement

pygame.quit()

Key Changes:

  1. Enemy Movement: Enemies move randomly unless there are no walls between the enemy and the player, in which case they chase the player.
  2. Ball Movement: The ball moves diagonally and bounces between diagonal up and diagonal down directions.
  3. Level Up: When all cherries are eaten, the game advances to the next level with one additional enemy for every new level.

Feel free to test the game and make further modifications as needed!

2. Let’s move constantly

move the player constantly until he reaches a wall or changes direction. Make the ball smaller and make it bounce

3. Move the walls

The walls of the labyrinth is made of blocks, ok? make the player to be able to move a block of the labyrinth with the key “a” if there is not another block where the block would be moved to. So if the player moves with “a” a block towards right, the block moves only if there are no other blocks on the right of the block. The same for the other directions.

To implement the functionality where the player can move blocks of the labyrinth using the “a” key, we’ll need to add logic to handle block pushing in all four directions. The player can push a block only if there’s no other block in the direction the block is being moved.

Here’s how to implement these changes:

  1. Add Block Pushing Logic: Implement the logic to check if the player can push a block in the given direction and move it if possible.
  2. Handle Pushing Direction: Use the player’s current direction to determine which direction to push the block.

Here’s the updated code with these changes:

import pygame
import random
import math

# Initialize Pygame
pygame.init()

# Set up the display
WIDTH, HEIGHT = 800, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Mr. Do!-like Game")

# Colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
WALL_COLOR = (100, 50, 0)
BALL_COLOR = (255, 165, 0)  # Orange

# Grid settings
GRID_SIZE = 40
GRID_WIDTH = WIDTH // GRID_SIZE
GRID_HEIGHT = HEIGHT // GRID_SIZE

# Font
font = pygame.font.Font(None, 36)

# Game variables
player_x = player_y = 1
player_direction = 0  # 0: right, 1: down, 2: left, 3: up
enemies = []
cherries = []
score = 0
game_over = False
level = 1

# Ball variables
ball_x = ball_y = None
ball_direction = None
ball_active = False
BALL_SIZE = GRID_SIZE // 6  # Smaller ball size

def create_labyrinth():
    labyrinth = [[1 for _ in range(GRID_WIDTH)] for _ in range(GRID_HEIGHT)]

    def create_path(x, y):
        labyrinth[y][x] = 0
        directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]
        random.shuffle(directions)
        for dx, dy in directions:
            nx, ny = x + dx*2, y + dy*2
            if 0 <= nx < GRID_WIDTH and 0 <= ny < GRID_HEIGHT and labyrinth[ny][nx] == 1:
                labyrinth[y + dy][x + dx] = 0
                create_path(nx, ny)

    create_path(1, 1)
    return labyrinth

def place_cherries():
    return [(x, y) for y in range(GRID_HEIGHT) for x in range(GRID_WIDTH) 
            if labyrinth[y][x] == 0 and random.random() < 0.1]

def place_enemies():
    enemy_list = []
    while len(enemy_list) < level + 2:
        x, y = random.randint(0, GRID_WIDTH - 1), random.randint(0, GRID_HEIGHT - 1)
        if labyrinth[y][x] == 0 and (x, y) != (player_x, player_y):
            enemy_list.append([x, y])
    return enemy_list

def can_chase_player(enemy_x, enemy_y):
    if enemy_x == player_x:
        if all(labyrinth[y][enemy_x] == 0 for y in range(min(enemy_y, player_y), max(enemy_y, player_y) + 1)):
            return True
    if enemy_y == player_y:
        if all(labyrinth[enemy_y][x] == 0 for x in range(min(enemy_x, player_x), max(enemy_x, player_x) + 1)):
            return True
    return False

def move_enemy(enemy):
    if can_chase_player(enemy[0], enemy[1]):
        return move_towards(enemy, player_x, player_y)
    else:
        possible_moves = [(1, 0), (0, 1), (-1, 0), (0, -1)]
        random.shuffle(possible_moves)
        for dx, dy in possible_moves:
            new_x, new_y = enemy[0] + dx, enemy[1] + dy
            if 0 <= new_x < GRID_WIDTH and 0 <= new_y < GRID_HEIGHT and labyrinth[new_y][new_x] == 0:
                return (new_x, new_y)
        return (enemy[0], enemy[1])

def move_towards(enemy, target_x, target_y):
    dx = target_x - enemy[0]
    dy = target_y - enemy[1]
    if abs(dx) > abs(dy):
        return (enemy[0] + (1 if dx > 0 else -1), enemy[1])
    else:
        return (enemy[0], enemy[1] + (1 if dy > 0 else -1))

def launch_ball():
    global ball_x, ball_y, ball_direction, ball_active
    if not ball_active:
        ball_x, ball_y = player_x, player_y
        ball_direction = 0  # Start moving diagonally up
        ball_active = True

def move_ball():
    global ball_x, ball_y, ball_direction, ball_active, enemies, score
    if ball_active:
        directions = [(1, -1), (1, 1), (-1, 1), (-1, -1)]
        dx, dy = directions[ball_direction]
        new_x, new_y = ball_x + dx, ball_y + dy

        if 0 <= new_x < GRID_WIDTH and 0 <= new_y < GRID_HEIGHT:
            if labyrinth[new_y][new_x] == 1:
                ball_direction = (ball_direction + 2) % 4  # Bounce diagonally
            else:
                ball_x, ball_y = new_x, new_y

                # Check for enemy collision
                for enemy in enemies[:]:
                    if ball_x == enemy[0] and ball_y == enemy[1]:
                        enemies.remove(enemy)
                        score += 50
                        ball_active = False
                        return

                # Check for player collision
                if ball_x == player_x and ball_y == player_y:
                    ball_active = False
        else:
            ball_direction = (ball_direction + 2) % 4  # Reverse direction at screen edge

def move_player():
    global player_x, player_y
    directions = [(1, 0), (0, 1), (-1, 0), (0, -1)]
    dx, dy = directions[player_direction]
    new_x, new_y = player_x + dx, player_y + dy
    if 0 <= new_x < GRID_WIDTH and 0 <= new_y < GRID_HEIGHT and labyrinth[new_y][new_x] == 0:
        player_x, player_y = new_x, new_y

def push_block():
    directions = [(1, 0), (0, 1), (-1, 0), (0, -1)]
    dx, dy = directions[player_direction]
    block_x, block_y = player_x + dx, player_y + dy
    new_block_x, new_block_y = block_x + dx, block_y + dy

    if 0 <= block_x < GRID_WIDTH and 0 <= block_y < GRID_HEIGHT:
        if labyrinth[block_y][block_x] == 1:
            if 0 <= new_block_x < GRID_WIDTH and 0 <= new_block_y < GRID_HEIGHT and labyrinth[new_block_y][new_block_x] == 0:
                labyrinth[block_y][block_x] = 0
                labyrinth[new_block_y][new_block_x] = 1

def draw_game():
    screen.fill(BLACK)

    # Draw labyrinth
    for y in range(GRID_HEIGHT):
        for x in range(GRID_WIDTH):
            if labyrinth[y][x] == 1:
                pygame.draw.rect(screen, WALL_COLOR, (x * GRID_SIZE, y * GRID_SIZE, GRID_SIZE, GRID_SIZE))
                pygame.draw.rect(screen, BLACK, (x * GRID_SIZE + 2, y * GRID_SIZE + 2, GRID_SIZE - 4, GRID_SIZE - 4))

    # Draw player
    pygame.draw.circle(screen, WHITE, (player_x * GRID_SIZE + GRID_SIZE // 2, player_y * GRID_SIZE + GRID_SIZE // 2), GRID_SIZE // 2 - 2)

    # Draw cherries
    for cherry in cherries:
        pygame.draw.circle(screen, RED, (cherry[0] * GRID_SIZE + GRID_SIZE // 2, cherry[1] * GRID_SIZE + GRID_SIZE // 2), GRID_SIZE // 4)

    # Draw enemies
    for enemy in enemies:
        pygame.draw.rect(screen, GREEN, (enemy[0] * GRID_SIZE + 2, enemy[1] * GRID_SIZE + 2, GRID_SIZE - 4, GRID_SIZE - 4))

    # Draw ball
    if ball_active:
        pygame.draw.circle(screen, BALL_COLOR, (ball_x * GRID_SIZE + GRID_SIZE // 2, ball_y * GRID_SIZE + GRID_SIZE // 2), BALL_SIZE)

    # Draw score
    score_text = font.render(f"Score: {score}", True, WHITE)
    screen.blit(score_text, (10, 10))

    if game_over:
        game_over_text = font.render("Game Over! Press R to Restart", True, WHITE)
        screen.blit(game_over_text, (WIDTH // 2 - game_over_text.get_width()

 // 2, HEIGHT // 2 - game_over_text.get_height() // 2))

    pygame.display.flip()

def reset_game():
    global player_x, player_y, player_direction, enemies, cherries, score, game_over, labyrinth, ball_active, level
    player_x = player_y = 1
    player_direction = 0
    labyrinth = create_labyrinth()
    cherries = place_cherries()
    enemies = place_enemies()
    score = 0
    game_over = False
    ball_active = False

# Initial game setup
reset_game()

# Game loop
running = True
clock = pygame.time.Clock()

while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN:
            if game_over:
                if event.key == pygame.K_r:
                    reset_game()
            else:
                if event.key == pygame.K_LEFT:
                    player_direction = 2
                elif event.key == pygame.K_RIGHT:
                    player_direction = 0
                elif event.key == pygame.K_UP:
                    player_direction = 3
                elif event.key == pygame.K_DOWN:
                    player_direction = 1
                elif event.key == pygame.K_a:
                    push_block()
                elif event.key == pygame.K_z:
                    # Destroy wall
                    dx, dy = [(1, 0), (0, 1), (-1, 0), (0, -1)][player_direction]
                    wall_x, wall_y = player_x + dx, player_y + dy
                    if 0 <= wall_x < GRID_WIDTH and 0 <= wall_y < GRID_HEIGHT:
                        if labyrinth[wall_y][wall_x] == 1:
                            labyrinth[wall_y][wall_x] = 0
                            score += 5
                elif event.key == pygame.K_x:
                    launch_ball()

    if not game_over:
        # Move player
        move_player()

        # Move enemies
        for enemy in enemies:
            new_pos = move_enemy(enemy)
            enemy[0], enemy[1] = new_pos

        # Move ball
        move_ball()

        # Check collisions
        if (player_x, player_y) in cherries:
            cherries.remove((player_x, player_y))
            score += 10

        if [player_x, player_y] in enemies:
            game_over = True

        # Level up
        if not cherries:
            level += 1
            cherries = place_cherries()
            enemies = place_enemies()

    draw_game()
    clock.tick(10)  # Slower speed for grid-based movement

pygame.quit()

Key Changes:

  1. Block Pushing Logic: Added the push_block function to handle pushing blocks in the player’s current direction.
  2. Handle Pushing Direction: Integrated block pushing logic with the player’s current direction when the “a” key is pressed.

Feel free to test the game and make further modifications as needed!

4. The bomb

make that the ball can be left where the player is like a bomb. When the enemy gets in the ball, the enemy explode in pieces and is eliminated. The player has 3 bombs max to leave.

To implement the feature where the player can leave the ball as a bomb and eliminate enemies when they step on it, we’ll make the following changes:

  1. Bomb Placement: Allow the player to place a bomb where they currently stand using a key (e.g., “x”). The player can have a maximum of 3 bombs.
  2. Enemy Explosion: Check if an enemy steps on a bomb and eliminate the enemy if they do.
  3. Bomb Management: Track the number of bombs and their positions.

Here’s the updated code with these changes:

import pygame
import random
import math

# Initialize Pygame
pygame.init()

# Set up the display
WIDTH, HEIGHT = 800, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Mr. Do!-like Game")

# Colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
WALL_COLOR = (100, 50, 0)
BALL_COLOR = (255, 165, 0)  # Orange

# Grid settings
GRID_SIZE = 40
GRID_WIDTH = WIDTH // GRID_SIZE
GRID_HEIGHT = HEIGHT // GRID_SIZE

# Font
font = pygame.font.Font(None, 36)

# Game variables
player_x = player_y = 1
player_direction = 0  # 0: right, 1: down, 2: left, 3: up
enemies = []
cherries = []
score = 0
game_over = False
level = 1

# Bomb variables
bombs = []
max_bombs = 3

def create_labyrinth():
    labyrinth = [[1 for _ in range(GRID_WIDTH)] for _ in range(GRID_HEIGHT)]

    def create_path(x, y):
        labyrinth[y][x] = 0
        directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]
        random.shuffle(directions)
        for dx, dy in directions:
            nx, ny = x + dx*2, y + dy*2
            if 0 <= nx < GRID_WIDTH and 0 <= ny < GRID_HEIGHT and labyrinth[ny][nx] == 1:
                labyrinth[y + dy][x + dx] = 0
                create_path(nx, ny)

    create_path(1, 1)
    return labyrinth

def place_cherries():
    return [(x, y) for y in range(GRID_HEIGHT) for x in range(GRID_WIDTH) 
            if labyrinth[y][x] == 0 and random.random() < 0.1]

def place_enemies():
    enemy_list = []
    while len(enemy_list) < level + 2:
        x, y = random.randint(0, GRID_WIDTH - 1), random.randint(0, GRID_HEIGHT - 1)
        if labyrinth[y][x] == 0 and (x, y) != (player_x, player_y):
            enemy_list.append([x, y])
    return enemy_list

def can_chase_player(enemy_x, enemy_y):
    if enemy_x == player_x:
        if all(labyrinth[y][enemy_x] == 0 for y in range(min(enemy_y, player_y), max(enemy_y, player_y) + 1)):
            return True
    if enemy_y == player_y:
        if all(labyrinth[enemy_y][x] == 0 for x in range(min(enemy_x, player_x), max(enemy_x, player_x) + 1)):
            return True
    return False

def move_enemy(enemy):
    if can_chase_player(enemy[0], enemy[1]):
        return move_towards(enemy, player_x, player_y)
    else:
        possible_moves = [(1, 0), (0, 1), (-1, 0), (0, -1)]
        random.shuffle(possible_moves)
        for dx, dy in possible_moves:
            new_x, new_y = enemy[0] + dx, enemy[1] + dy
            if 0 <= new_x < GRID_WIDTH and 0 <= new_y < GRID_HEIGHT and labyrinth[new_y][new_x] == 0:
                return (new_x, new_y)
        return (enemy[0], enemy[1])

def move_towards(enemy, target_x, target_y):
    dx = target_x - enemy[0]
    dy = target_y - enemy[1]
    if abs(dx) > abs(dy):
        return (enemy[0] + (1 if dx > 0 else -1), enemy[1])
    else:
        return (enemy[0], enemy[1] + (1 if dy > 0 else -1))

def place_bomb():
    if len(bombs) < max_bombs:
        bombs.append((player_x, player_y))

def move_player():
    global player_x, player_y
    directions = [(1, 0), (0, 1), (-1, 0), (0, -1)]
    dx, dy = directions[player_direction]
    new_x, new_y = player_x + dx, player_y + dy
    if 0 <= new_x < GRID_WIDTH and 0 <= new_y < GRID_HEIGHT and labyrinth[new_y][new_x] == 0:
        player_x, player_y = new_x, new_y

def push_block():
    directions = [(1, 0), (0, 1), (-1, 0), (0, -1)]
    dx, dy = directions[player_direction]
    block_x, block_y = player_x + dx, player_y + dy
    new_block_x, new_block_y = block_x + dx, block_y + dy

    if 0 <= block_x < GRID_WIDTH and 0 <= block_y < GRID_HEIGHT:
        if labyrinth[block_y][block_x] == 1:
            if 0 <= new_block_x < GRID_WIDTH and 0 <= new_block_y < GRID_HEIGHT and labyrinth[new_block_y][new_block_x] == 0:
                labyrinth[block_y][block_x] = 0
                labyrinth[new_block_y][new_block_x] = 1

def draw_game():
    screen.fill(BLACK)

    # Draw labyrinth
    for y in range(GRID_HEIGHT):
        for x in range(GRID_WIDTH):
            if labyrinth[y][x] == 1:
                pygame.draw.rect(screen, WALL_COLOR, (x * GRID_SIZE, y * GRID_SIZE, GRID_SIZE, GRID_SIZE))
                pygame.draw.rect(screen, BLACK, (x * GRID_SIZE + 2, y * GRID_SIZE + 2, GRID_SIZE - 4, GRID_SIZE - 4))

    # Draw player
    pygame.draw.circle(screen, WHITE, (player_x * GRID_SIZE + GRID_SIZE // 2, player_y * GRID_SIZE + GRID_SIZE // 2), GRID_SIZE // 2 - 2)

    # Draw cherries
    for cherry in cherries:
        pygame.draw.circle(screen, RED, (cherry[0] * GRID_SIZE + GRID_SIZE // 2, cherry[1] * GRID_SIZE + GRID_SIZE // 2), GRID_SIZE // 4)

    # Draw enemies
    for enemy in enemies:
        pygame.draw.rect(screen, GREEN, (enemy[0] * GRID_SIZE + 2, enemy[1] * GRID_SIZE + 2, GRID_SIZE - 4, GRID_SIZE - 4))

    # Draw bombs
    for bomb in bombs:
        pygame.draw.circle(screen, BLUE, (bomb[0] * GRID_SIZE + GRID_SIZE // 2, bomb[1] * GRID_SIZE + GRID_SIZE // 2), GRID_SIZE // 4)

    # Draw score
    score_text = font.render(f"Score: {score}", True, WHITE)
    screen.blit(score_text, (10, 10))

    if game_over:
        game_over_text = font.render("Game Over! Press R to Restart", True, WHITE)
        screen.blit(game_over_text, (WIDTH // 2 - game_over_text.get_width() // 2, HEIGHT // 2 - game_over_text.get_height() // 2))

    pygame.display.flip()

def reset_game():
    global player_x, player_y, player_direction, enemies, cherries, score, game_over, labyrinth, bombs, level
    player_x = player_y = 1
    player_direction = 0
    labyrinth = create_labyrinth()
    cherries = place_cherries()
    enemies = place_enemies()
    score = 0
    game_over = False
    bombs = []

# Initial game setup
reset_game()

# Game loop
running = True
clock = pygame.time.Clock()

while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN:
            if game_over:
                if event.key == pygame.K_r:
                    reset_game()
            else:
                if event.key == pygame.K_LEFT:
                    player_direction = 2
                elif event.key == pygame.K_RIGHT:
                    player_direction = 0
                elif event.key == pygame.K_UP:
                    player_direction = 3
                elif event.key == pygame.K_DOWN:
                    player_direction = 1
                elif event.key == pygame.K_a:
                    push_block()
                elif event.key == pygame.K_z:
                    # Destroy wall
                    dx, dy = [(1, 0), (0, 1), (-1, 0), (0, -1)][player_direction]


                    wall_x, wall_y = player_x + dx, player_y + dy
                    if 0 <= wall_x < GRID_WIDTH and 0 <= wall_y < GRID_HEIGHT:
                        if labyrinth[wall_y][wall_x] == 1:
                            labyrinth[wall_y][wall_x] = 0
                            score += 5
                elif event.key == pygame.K_x:
                    place_bomb()

    if not game_over:
        # Move player
        move_player()

        # Move enemies
        for enemy in enemies:
            new_pos = move_enemy(enemy)
            enemy[0], enemy[1] = new_pos

        # Check bomb collisions with enemies
        for enemy in enemies[:]:
            if (enemy[0], enemy[1]) in bombs:
                enemies.remove(enemy)
                bombs.remove((enemy[0], enemy[1]))
                score += 50

        # Check collisions
        if (player_x, player_y) in cherries:
            cherries.remove((player_x, player_y))
            score += 10

        if [player_x, player_y] in enemies:
            game_over = True

        # Level up
        if not cherries:
            level += 1
            cherries = place_cherries()
            enemies = place_enemies()

    draw_game()
    clock.tick(10)  # Slower speed for grid-based movement

pygame.quit()

Key Changes:

  1. Bomb Placement: Added the place_bomb function to allow the player to place bombs on the current player position if the maximum number of bombs has not been reached.
  2. Bomb Management: Track the positions of bombs and check for collisions between enemies and bombs.
  3. Enemy Explosion: When an enemy steps on a bomb, the enemy is removed, and the bomb is also removed.

Feel free to test the game and make further modifications as needed!

To enhance the game with a ranking system and sound effects, we’ll make the following changes:

  1. Score Saving: Implement a mechanism to save and load scores.
  2. Display Ranking: Show the player’s current rank on the screen next to the score.
  3. Sound Effects: Add sound effects for various actions (destroying walls, pushing walls, killing enemies, being killed by enemies, and finishing a level).

Here’s the updated code with these changes:

import pygame
import random
import math
import os
import json

# Initialize Pygame
pygame.init()

# Set up the display
WIDTH, HEIGHT = 800, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Mr. Do!-like Game")

# Colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
WALL_COLOR = (100, 50, 0)
BALL_COLOR = (255, 165, 0)  # Orange

# Grid settings
GRID_SIZE = 40
GRID_WIDTH = WIDTH // GRID_SIZE
GRID_HEIGHT = HEIGHT // GRID_SIZE

# Font
font = pygame.font.Font(None, 36)

# Game variables
player_x = player_y = 1
player_direction = 0  # 0: right, 1: down, 2: left, 3: up
enemies = []
cherries = []
score = 0
game_over = False
level = 1

# Bomb variables
bombs = []
max_bombs = 3

# Load sounds
destroy_wall_sound = pygame.mixer.Sound('sounds/destroy_wall.wav')
push_wall_sound = pygame.mixer.Sound('sounds/push_wall.wav')
kill_enemy_sound = pygame.mixer.Sound('sounds/kill_enemy.wav')
player_killed_sound = pygame.mixer.Sound('sounds/player_killed.wav')
level_complete_sound = pygame.mixer.Sound('sounds/level_complete.wav')

# Scores
scores_file = 'scores.json'
scores = []

def load_scores():
    global scores
    if os.path.exists(scores_file):
        with open(scores_file, 'r') as f:
            scores = json.load(f)
    else:
        scores = []

def save_scores():
    with open(scores_file, 'w') as f:
        json.dump(scores, f)

def get_rank():
    sorted_scores = sorted(scores, reverse=True)
    rank = sorted_scores.index(score) + 1 if score in sorted_scores else len(sorted_scores) + 1
    return rank

def create_labyrinth():
    labyrinth = [[1 for _ in range(GRID_WIDTH)] for _ in range(GRID_HEIGHT)]

    def create_path(x, y):
        labyrinth[y][x] = 0
        directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]
        random.shuffle(directions)
        for dx, dy in directions:
            nx, ny = x + dx*2, y + dy*2
            if 0 <= nx < GRID_WIDTH and 0 <= ny < GRID_HEIGHT and labyrinth[ny][nx] == 1:
                labyrinth[y + dy][x + dx] = 0
                create_path(nx, ny)

    create_path(1, 1)
    return labyrinth

def place_cherries():
    return [(x, y) for y in range(GRID_HEIGHT) for x in range(GRID_WIDTH) 
            if labyrinth[y][x] == 0 and random.random() < 0.1]

def place_enemies():
    enemy_list = []
    while len(enemy_list) < level + 2:
        x, y = random.randint(0, GRID_WIDTH - 1), random.randint(0, GRID_HEIGHT - 1)
        if labyrinth[y][x] == 0 and (x, y) != (player_x, player_y):
            enemy_list.append([x, y])
    return enemy_list

def can_chase_player(enemy_x, enemy_y):
    if enemy_x == player_x:
        if all(labyrinth[y][enemy_x] == 0 for y in range(min(enemy_y, player_y), max(enemy_y, player_y) + 1)):
            return True
    if enemy_y == player_y:
        if all(labyrinth[enemy_y][x] == 0 for x in range(min(enemy_x, player_x), max(enemy_x, player_x) + 1)):
            return True
    return False

def move_enemy(enemy):
    if can_chase_player(enemy[0], enemy[1]):
        return move_towards(enemy, player_x, player_y)
    else:
        possible_moves = [(1, 0), (0, 1), (-1, 0), (0, -1)]
        random.shuffle(possible_moves)
        for dx, dy in possible_moves:
            new_x, new_y = enemy[0] + dx, enemy[1] + dy
            if 0 <= new_x < GRID_WIDTH and 0 <= new_y < GRID_HEIGHT and labyrinth[new_y][new_x] == 0:
                return (new_x, new_y)
        return (enemy[0], enemy[1])

def move_towards(enemy, target_x, target_y):
    dx = target_x - enemy[0]
    dy = target_y - enemy[1]
    if abs(dx) > abs(dy):
        return (enemy[0] + (1 if dx > 0 else -1), enemy[1])
    else:
        return (enemy[0], enemy[1] + (1 if dy > 0 else -1))

def place_bomb():
    if len(bombs) < max_bombs:
        bombs.append((player_x, player_y))

def move_player():
    global player_x, player_y
    directions = [(1, 0), (0, 1), (-1, 0), (0, -1)]
    dx, dy = directions[player_direction]
    new_x, new_y = player_x + dx, player_y + dy
    if 0 <= new_x < GRID_WIDTH and 0 <= new_y < GRID_HEIGHT and labyrinth[new_y][new_x] == 0:
        player_x, player_y = new_x, new_y

def push_block():
    directions = [(1, 0), (0, 1), (-1, 0), (0, -1)]
    dx, dy = directions[player_direction]
    block_x, block_y = player_x + dx, player_y + dy
    new_block_x, new_block_y = block_x + dx, block_y + dy

    if 0 <= block_x < GRID_WIDTH and 0 <= block_y < GRID_HEIGHT:
        if labyrinth[block_y][block_x] == 1:
            if 0 <= new_block_x < GRID_WIDTH and 0 <= new_block_y < GRID_HEIGHT and labyrinth[new_block_y][new_block_x] == 0:
                labyrinth[block_y][block_x] = 0
                labyrinth[new_block_y][new_block_x] = 1
                push_wall_sound.play()

def draw_game():
    screen.fill(BLACK)

    # Draw labyrinth
    for y in range(GRID_HEIGHT):
        for x in range(GRID_WIDTH):
            if labyrinth[y][x] == 1:
                pygame.draw.rect(screen, WALL_COLOR, (x * GRID_SIZE, y * GRID_SIZE, GRID_SIZE, GRID_SIZE))
                pygame.draw.rect(screen, BLACK, (x * GRID_SIZE + 2, y * GRID_SIZE + 2, GRID_SIZE - 4, GRID_SIZE - 4))

    # Draw player
    pygame.draw.circle(screen, WHITE, (player_x * GRID_SIZE + GRID_SIZE // 2, player_y * GRID_SIZE + GRID_SIZE // 2), GRID_SIZE // 2 - 2)

    # Draw cherries
    for cherry in cherries:
        pygame.draw.circle(screen, RED, (cherry[0] * GRID_SIZE + GRID_SIZE // 2, cherry[1] * GRID_SIZE + GRID_SIZE // 2), GRID_SIZE // 4)

    # Draw enemies
    for enemy in enemies:
        pygame.draw.rect(screen, GREEN, (enemy[0] * GRID_SIZE + 2, enemy[1] * GRID_SIZE + 2, GRID_SIZE - 4, GRID_SIZE - 4))

    # Draw bombs
    for bomb in bombs:
        pygame.draw.circle(screen, BLUE, (bomb[0] * GRID_SIZE + GRID_SIZE // 2, bomb[1] * GRID_SIZE + GRID_SIZE // 2), GRID_SIZE // 4)

    # Draw score and rank
    score_text = font.render(f"Score: {score}", True, WHITE)
    screen.blit(score_text, (10, 10))

    rank_text = font.render(f"Rank: {get_rank()}", True, WHITE)
    screen.blit(rank_text, (10, 50))

    if game_over:
        game_over_text = font.render("Game Over! Press R to Restart", True, WHITE)
        screen.blit(game_over_text, (WIDTH // 2 - game_over_text.get_width() // 2, HEIGHT // 2 - game_over_text.get_height() // 2))

    pygame.display.flip()

def reset_game():
    global player_x, player_y, player_direction, enemies, cherries, score, game_over, labyrinth, bombs, level
    player_x = player_y = 1
    player_direction = 0
    labyrinth = create_labyrinth()
    cherries =

 place_cherries()
    enemies = place_enemies()
    score = 0
    game_over = False
    bombs = []

# Initial game setup
load_scores()
reset_game()

# Game loop
running = True
clock = pygame.time.Clock()

while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN:
            if game_over:
                if event.key == pygame.K_r:
                    reset_game()
            else:
                if event.key == pygame.K_LEFT:
                    player_direction = 2
                elif event.key == pygame.K_RIGHT:
                    player_direction = 0
                elif event.key == pygame.K_UP:
                    player_direction = 3
                elif event.key == pygame.K_DOWN:
                    player_direction = 1
                elif event.key == pygame.K_a:
                    push_block()
                elif event.key == pygame.K_z:
                    # Destroy wall
                    dx, dy = [(1, 0), (0, 1), (-1, 0), (0, -1)][player_direction]
                    wall_x, wall_y = player_x + dx, player_y + dy
                    if 0 <= wall_x < GRID_WIDTH and 0 <= wall_y < GRID_HEIGHT:
                        if labyrinth[wall_y][wall_x] == 1:
                            labyrinth[wall_y][wall_x] = 0
                            score += 5
                            destroy_wall_sound.play()
                elif event.key == pygame.K_x:
                    place_bomb()

    if not game_over:
        # Move player
        move_player()

        # Move enemies
        for enemy in enemies:
            new_pos = move_enemy(enemy)
            enemy[0], enemy[1] = new_pos

        # Check bomb collisions with enemies
        for enemy in enemies[:]:
            if (enemy[0], enemy[1]) in bombs:
                enemies.remove(enemy)
                bombs.remove((enemy[0], enemy[1]))
                score += 50
                kill_enemy_sound.play()

        # Check collisions
        if (player_x, player_y) in cherries:
            cherries.remove((player_x, player_y))
            score += 10

        if [player_x, player_y] in enemies:
            game_over = True
            player_killed_sound.play()
            scores.append(score)
            save_scores()

        # Level up
        if not cherries:
            level += 1
            cherries = place_cherries()
            enemies = place_enemies()
            level_complete_sound.play()

    draw_game()
    clock.tick(10)  # Slower speed for grid-based movement

pygame.quit()

Key Changes:

  1. Score Saving and Loading: Scores are saved in a JSON file and loaded at the start. The player’s rank is calculated based on the scores.
  2. Display Ranking: The player’s rank is displayed next to the score.
  3. Sound Effects: Added sound effects for destroying walls, pushing walls, killing enemies, being killed by enemies, and finishing a level.

Additional Notes:

  • Ensure you have the sound files (destroy_wall.wav, push_wall.wav, kill_enemy.wav, player_killed.wav, and level_complete.wav) in a sounds directory.
  • The scores.json file is used to store the scores persistently.

Feel free to test the game and make further modifications as needed!

To implement the bomb disappearing after 7 seconds and the score diminishing by 1 every 5 seconds, we need to:

  1. Bomb Timer: Track the time each bomb was placed and remove it after 7 seconds.
  2. Score Timer: Decrease the score by 1 every 5 seconds.

Here’s the updated code:

import pygame
import random
import math
import os
import json
import time

# Initialize Pygame
pygame.init()

# Set up the display
WIDTH, HEIGHT = 800, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Mr. Do!-like Game")

# Colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
WALL_COLOR = (100, 50, 0)
BALL_COLOR = (255, 165, 0)  # Orange

# Grid settings
GRID_SIZE = 40
GRID_WIDTH = WIDTH // GRID_SIZE
GRID_HEIGHT = HEIGHT // GRID_SIZE

# Font
font = pygame.font.Font(None, 36)

# Game variables
player_x = player_y = 1
player_direction = 0  # 0: right, 1: down, 2: left, 3: up
enemies = []
cherries = []
score = 0
game_over = False
level = 1

# Bomb variables
bombs = []
max_bombs = 3
bomb_lifetime = 7  # seconds

# Score decrement timer
score_decrement_time = 5  # seconds
last_score_decrement = time.time()

# Load sounds
destroy_wall_sound = pygame.mixer.Sound('sounds/destroy_wall.wav')
push_wall_sound = pygame.mixer.Sound('sounds/push_wall.wav')
kill_enemy_sound = pygame.mixer.Sound('sounds/kill_enemy.wav')
player_killed_sound = pygame.mixer.Sound('sounds/player_killed.wav')
level_complete_sound = pygame.mixer.Sound('sounds/level_complete.wav')

# Scores
scores_file = 'scores.json'
scores = []

def load_scores():
    global scores
    if os.path.exists(scores_file):
        with open(scores_file, 'r') as f:
            scores = json.load(f)
    else:
        scores = []

def save_scores():
    with open(scores_file, 'w') as f:
        json.dump(scores, f)

def get_rank():
    sorted_scores = sorted(scores, reverse=True)
    rank = sorted_scores.index(score) + 1 if score in sorted_scores else len(sorted_scores) + 1
    return rank

def create_labyrinth():
    labyrinth = [[1 for _ in range(GRID_WIDTH)] for _ in range(GRID_HEIGHT)]

    def create_path(x, y):
        labyrinth[y][x] = 0
        directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]
        random.shuffle(directions)
        for dx, dy in directions:
            nx, ny = x + dx*2, y + dy*2
            if 0 <= nx < GRID_WIDTH and 0 <= ny < GRID_HEIGHT and labyrinth[ny][nx] == 1:
                labyrinth[y + dy][x + dx] = 0
                create_path(nx, ny)

    create_path(1, 1)
    return labyrinth

def place_cherries():
    return [(x, y) for y in range(GRID_HEIGHT) for x in range(GRID_WIDTH) 
            if labyrinth[y][x] == 0 and random.random() < 0.1]

def place_enemies():
    enemy_list = []
    while len(enemy_list) < level + 2:
        x, y = random.randint(0, GRID_WIDTH - 1), random.randint(0, GRID_HEIGHT - 1)
        if labyrinth[y][x] == 0 and (x, y) != (player_x, player_y):
            enemy_list.append([x, y])
    return enemy_list

def can_chase_player(enemy_x, enemy_y):
    if enemy_x == player_x:
        if all(labyrinth[y][enemy_x] == 0 for y in range(min(enemy_y, player_y), max(enemy_y, player_y) + 1)):
            return True
    if enemy_y == player_y:
        if all(labyrinth[enemy_y][x] == 0 for x in range(min(enemy_x, player_x), max(enemy_x, player_x) + 1)):
            return True
    return False

def move_enemy(enemy):
    if can_chase_player(enemy[0], enemy[1]):
        return move_towards(enemy, player_x, player_y)
    else:
        possible_moves = [(1, 0), (0, 1), (-1, 0), (0, -1)]
        random.shuffle(possible_moves)
        for dx, dy in possible_moves:
            new_x, new_y = enemy[0] + dx, enemy[1] + dy
            if 0 <= new_x < GRID_WIDTH and 0 <= new_y < GRID_HEIGHT and labyrinth[new_y][new_x] == 0:
                return (new_x, new_y)
        return (enemy[0], enemy[1])

def move_towards(enemy, target_x, target_y):
    dx = target_x - enemy[0]
    dy = target_y - enemy[1]
    if abs(dx) > abs(dy):
        return (enemy[0] + (1 if dx > 0 else -1), enemy[1])
    else:
        return (enemy[0], enemy[1] + (1 if dy > 0 else -1))

def place_bomb():
    if len(bombs) < max_bombs:
        bombs.append({'pos': (player_x, player_y), 'time': time.time()})

def move_player():
    global player_x, player_y
    directions = [(1, 0), (0, 1), (-1, 0), (0, -1)]
    dx, dy = directions[player_direction]
    new_x, new_y = player_x + dx, player_y + dy
    if 0 <= new_x < GRID_WIDTH and 0 <= new_y < GRID_HEIGHT and labyrinth[new_y][new_x] == 0:
        player_x, player_y = new_x, new_y

def push_block():
    directions = [(1, 0), (0, 1), (-1, 0), (0, -1)]
    dx, dy = directions[player_direction]
    block_x, block_y = player_x + dx, player_y + dy
    new_block_x, new_block_y = block_x + dx, block_y + dy

    if 0 <= block_x < GRID_WIDTH and 0 <= block_y < GRID_HEIGHT:
        if labyrinth[block_y][block_x] == 1:
            if 0 <= new_block_x < GRID_WIDTH and 0 <= new_block_y < GRID_HEIGHT and labyrinth[new_block_y][new_block_x] == 0:
                labyrinth[block_y][block_x] = 0
                labyrinth[new_block_y][new_block_x] = 1
                push_wall_sound.play()

def draw_game():
    screen.fill(BLACK)

    # Draw labyrinth
    for y in range(GRID_HEIGHT):
        for x in range(GRID_WIDTH):
            if labyrinth[y][x] == 1:
                pygame.draw.rect(screen, WALL_COLOR, (x * GRID_SIZE, y * GRID_SIZE, GRID_SIZE, GRID_SIZE))
                pygame.draw.rect(screen, BLACK, (x * GRID_SIZE + 2, y * GRID_SIZE + 2, GRID_SIZE - 4, GRID_SIZE - 4))

    # Draw player
    pygame.draw.circle(screen, WHITE, (player_x * GRID_SIZE + GRID_SIZE // 2, player_y * GRID_SIZE + GRID_SIZE // 2), GRID_SIZE // 2 - 2)

    # Draw cherries
    for cherry in cherries:
        pygame.draw.circle(screen, RED, (cherry[0] * GRID_SIZE + GRID_SIZE // 2, cherry[1] * GRID_SIZE + GRID_SIZE // 2), GRID_SIZE // 4)

    # Draw enemies
    for enemy in enemies:
        pygame.draw.rect(screen, GREEN, (enemy[0] * GRID_SIZE + 2, enemy[1] * GRID_SIZE + 2, GRID_SIZE - 4, GRID_SIZE - 4))

    # Draw bombs
    for bomb in bombs:
        pygame.draw.circle(screen, BLUE, (bomb['pos'][0] * GRID_SIZE + GRID_SIZE // 2, bomb['pos'][1] * GRID_SIZE + GRID_SIZE // 2), GRID_SIZE // 4)

    # Draw score and rank
    score_text = font.render(f"Score: {score}", True, WHITE)
    screen.blit(score_text, (10, 10))

    rank_text = font.render(f"Rank: {get_rank()}", True, WHITE)
    screen.blit(rank_text, (10, 50))

    if game_over:
        game_over_text = font.render("Game Over! Press R to Restart", True, WHITE)
        screen.blit(game_over_text, (WIDTH // 2 - game_over_text.get_width() // 2, HEIGHT // 2 - game_over_text.get_height() // 2))

    pygame.display.flip()

def reset_game():
    global player_x, player_y, player_direction, enemies, cherries, score, game_over, labyrinth, bombs, level, last

_score_decrement
    player_x = player_y = 1
    player_direction = 0
    labyrinth = create_labyrinth()
    cherries = place_cherries()
    enemies = place_enemies()
    score = 0
    game_over = False
    bombs = []
    last_score_decrement = time.time()

# Initial game setup
load_scores()
reset_game()

# Game loop
running = True
clock = pygame.time.Clock()

while running:
    current_time = time.time()

    # Check if it's time to decrement the score
    if current_time - last_score_decrement >= score_decrement_time:
        if score > 0:
            score -= 1
        last_score_decrement = current_time

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN:
            if game_over:
                if event.key == pygame.K_r:
                    reset_game()
            else:
                if event.key == pygame.K_LEFT:
                    player_direction = 2
                elif event.key == pygame.K_RIGHT:
                    player_direction = 0
                elif event.key == pygame.K_UP:
                    player_direction = 3
                elif event.key == pygame.K_DOWN:
                    player_direction = 1
                elif event.key == pygame.K_a:
                    push_block()
                elif event.key == pygame.K_z:
                    # Destroy wall
                    dx, dy = [(1, 0), (0, 1), (-1, 0), (0, -1)][player_direction]
                    wall_x, wall_y = player_x + dx, player_y + dy
                    if 0 <= wall_x < GRID_WIDTH and 0 <= wall_y < GRID_HEIGHT:
                        if labyrinth[wall_y][wall_x] == 1:
                            labyrinth[wall_y][wall_x] = 0
                            score += 5
                            destroy_wall_sound.play()
                elif event.key == pygame.K_x:
                    place_bomb()

    if not game_over:
        # Move player
        move_player()

        # Move enemies
        for enemy in enemies:
            new_pos = move_enemy(enemy)
            enemy[0], enemy[1] = new_pos

        # Check bomb timers and remove expired bombs
        bombs = [bomb for bomb in bombs if current_time - bomb['time'] < bomb_lifetime]

        # Check bomb collisions with enemies
        for enemy in enemies[:]:
            for bomb in bombs:
                if (enemy[0], enemy[1]) == bomb['pos']:
                    enemies.remove(enemy)
                    bombs.remove(bomb)
                    score += 50
                    kill_enemy_sound.play()

        # Check collisions
        if (player_x, player_y) in cherries:
            cherries.remove((player_x, player_y))
            score += 10

        if [player_x, player_y] in enemies:
            game_over = True
            player_killed_sound.play()
            scores.append(score)
            save_scores()

        # Level up
        if not cherries:
            level += 1
            cherries = place_cherries()
            enemies = place_enemies()
            level_complete_sound.play()

    draw_game()
    clock.tick(10)  # Slower speed for grid-based movement

pygame.quit()

Key Changes:

  1. Bomb Timer: Added a timer to each bomb to track its lifetime and remove it after 7 seconds.
  2. Score Decrement Timer: Added a global timer to decrement the score by 1 every 5 seconds.

Additional Notes:

  • Ensure you have the sound files (destroy_wall.wav, push_wall.wav, kill_enemy.wav, player_killed.wav, and level_complete.wav) in a sounds directory.
  • The scores.json file is used to store the scores persistently.

Feel free to test the game and make further modifications as needed!


Subscribe to the newsletter for updates
Tkinter templates

Avatar My youtube channel

Twitter: @pythonprogrammi - python_pygame

Claude's Games

Arkanoid
Platform 2d

1. Memory game

Videos

Speech recognition game

Pygame's Platform Game

Other Pygame's posts

Advertisement