import pygame import sys import pickle import os from os import path import re # Constants screen_size = (1201, 1000) color = (255, 255, 255) tile_size = 50 gravity = 0.75 player_speed = 5 jump_velocity = -15 coin_count = 0 initial_coin_count = 0 has_key = False FPS = 60 SPRITE_FPS = 30 death_animation_speed = 5 # Function to load level data def load_level_data(level_name): level_dir = "Gilbert/Levels" level_path = os.path.join(level_dir, level_name) if os.path.exists(level_path): with open(level_path, 'rb') as file: loaded_data = pickle.load(file) return loaded_data else: print("Level data file not found:", level_path) return None # Initialize pygame pygame.init() clock = pygame.time.Clock() screen = pygame.display.set_mode(screen_size) pygame.display.set_caption('CyberQuest platformer') # Load images background_image = pygame.image.load('Gilbert/Images/Background.png') background_image = pygame.transform.scale(background_image, screen_size) player_image = pygame.image.load('Gilbert/Player_Images/Idle__000.png') player_image = pygame.transform.scale(player_image, (50, 70)) death_images = [pygame.image.load(f'Gilbert/Player_Images/Dead__{i:03}.png') for i in range(10)] death_images = [pygame.transform.scale(image, (75, 50)) for image in death_images] # Adjusted size for death images block_img = pygame.image.load('Gilbert/Images/Block.png') block_img = pygame.transform.scale(block_img, (tile_size, tile_size)) block2_img = pygame.image.load('Gilbert/Images/Block2.png') block2_img = pygame.transform.scale(block2_img, (tile_size, tile_size)) block3_img = pygame.image.load('Gilbert/Images/Block3.png') block3_img = pygame.transform.scale(block3_img, (tile_size, tile_size)) block4_img = pygame.image.load('Gilbert/Images/Block4.png') block4_img = pygame.transform.scale(block4_img, (tile_size, tile_size)) block5_img = pygame.image.load('Gilbert/Images/Block5.png') block5_img = pygame.transform.scale(block5_img, (tile_size, tile_size)) block6_img = pygame.image.load('Gilbert/Images/Block6.png') block6_img = pygame.transform.scale(block6_img, (tile_size, tile_size)) block7_img = pygame.image.load('Gilbert/Images/Block7.png') block7_img = pygame.transform.scale(block7_img, (tile_size, tile_size)) block8_img = pygame.image.load('Gilbert/Images/Block8.png') block8_img = pygame.transform.scale(block8_img, (tile_size, tile_size)) block9_img = pygame.image.load('Gilbert/Images/Block9.png') block9_img = pygame.transform.scale(block9_img, (tile_size, tile_size)) block10_img = pygame.image.load('Gilbert/Images/Block10.png') block10_img = pygame.transform.scale(block10_img, (tile_size, tile_size)) block11_img = pygame.image.load('Gilbert/Images/Block11.png') block11_img = pygame.transform.scale(block11_img, (tile_size, tile_size)) block12_img = pygame.image.load('Gilbert/Images/Block12.png') block12_img = pygame.transform.scale(block12_img, (tile_size, tile_size)) block13_img = pygame.image.load('Gilbert/Images/Block13.png') block13_img = pygame.transform.scale(block13_img, (tile_size, tile_size)) block14_img = pygame.image.load('Gilbert/Images/Block14.png') block14_img = pygame.transform.scale(block14_img, (tile_size, tile_size)) block15_img = pygame.image.load('Gilbert/Images/Block15.png') block15_img = pygame.transform.scale(block15_img, (tile_size, tile_size)) Acid_img = pygame.image.load('Gilbert/Images/Acid.png') Acid_img = pygame.transform.scale(Acid_img, (tile_size, 40)) Acid2_img = pygame.image.load('Gilbert/Images/Acid2.png') Acid2_img = pygame.transform.scale(Acid2_img, (tile_size, tile_size)) zombie_img = pygame.image.load('Gilbert/Images/Zombie.png') zombie_img = pygame.transform.scale(zombie_img, (tile_size, tile_size)) moving_tile_img = pygame.image.load('Gilbert/Images/Moving_Tile.png') moving_tile_img = pygame.transform.scale(moving_tile_img, (tile_size, tile_size)) door_locked_img = pygame.image.load('Gilbert/Images/DoorLocked.png') door_locked_img = pygame.transform.scale(door_locked_img, (tile_size, 75)) # Door size 50x75 door_unlocked_img = pygame.image.load('Gilbert/Images/DoorUnlocked.png') door_unlocked_img = pygame.transform.scale(door_unlocked_img, (tile_size, 75)) # Door size 50x75 door_open_img = pygame.image.load('Gilbert/Images/DoorOpen.png') door_open_img = pygame.transform.scale(door_open_img, (tile_size, 75)) # Door size 50x75 # Load animated images gold_coin_images = [pygame.image.load(f'Gilbert/Images/Gold_{i}.png') for i in range(1, 31)] key_images = [pygame.transform.scale(pygame.image.load(f'Gilbert/Images/Key_{i}.png'), (tile_size, tile_size)) for i in range(27)] spawn_point_img = pygame.image.load('Gilbert/Images/Spawnpoint.png') spawn_point_img = pygame.transform.scale(spawn_point_img, (tile_size, tile_size)) # Load sound effects coin_sound = pygame.mixer.Sound('Gilbert/Audio/Coin_Sound_Effect.mp3') key_sound = pygame.mixer.Sound('Gilbert/Audio/Key_sound_effect.wav') # Load UI images ui_img = pygame.image.load('Gilbert/Images/Game_UI.png') ui_img = pygame.transform.scale(ui_img, (120, 40)) ui_button_img = pygame.image.load('Gilbert/Images/Game_UI.png') ui_button_img = pygame.transform.scale(ui_button_img, (200, 80)) # Larger buttons for better visibility main_ui_img = pygame.image.load('Gilbert/Images/UI.png') main_ui_img = pygame.transform.scale(main_ui_img, (600, 300)) # Font for coin count and key status text font = pygame.font.SysFont('Futura', 24) death_font = pygame.font.SysFont('Futura', 48, bold=True) class Player(pygame.sprite.Sprite): def __init__(self): super().__init__() self.idle_images = [pygame.image.load(f'Gilbert/Player_Images/Idle__{i:03}.png') for i in range(10)] self.idle_images = [pygame.transform.scale(image, (50, 70)) for image in self.idle_images] self.run_images = [pygame.image.load(f'Gilbert/Player_Images/Run__{i:03}.png') for i in range(10)] self.run_images = [pygame.transform.scale(image, (50, 70)) for image in self.run_images] self.jump_images = [pygame.image.load(f'Gilbert/Player_Images/Jump__{i:03}.png') for i in range(10)] self.jump_images = [pygame.transform.scale(image, (50, 70)) for image in self.jump_images] self.death_images = [pygame.image.load(f'Gilbert/Player_Images/Dead__{i:03}.png') for i in range(10)] self.death_images = [pygame.transform.scale(image, (75, 50)) for image in self.death_images] self.image = self.idle_images[0] self.rect = self.image.get_rect() self.rect.center = (100, screen_size[1] - 130) self.speed = player_speed self.vel_x = 0 self.vel_y = 0 self.jumped = False self.last_direction = 'right' self.frame_index = 0 self.frame_counter = 0 self.on_moving_platform = None self.platform_vel_x = 0 self.platform_vel_y = 0 self.rel_x = 0 self.rel_y = 0 self.alive = True self.dying = False self.death_animation_complete = False self.death_y = 0 # Initial position for the death animation self.death_x = 0 # Initial x position for the death animation def die(self): self.alive = False self.dying = True self.frame_index = 0 self.frame_counter = 0 self.death_y = self.rect.bottom # Capture the current bottom position self.death_x = self.rect.left # Capture the current left position def update_death_animation(self): self.frame_counter += 1 if self.frame_counter % death_animation_speed == 0: self.frame_index += 1 if self.frame_index >= len(self.death_images): self.frame_index = len(self.death_images) - 1 self.death_animation_complete = True self.image = self.death_images[self.frame_index] # Adjust the rect.bottom to the original bottom position and rect.left to the original left position self.rect = self.image.get_rect() self.rect.bottom = self.death_y self.rect.left = self.death_x def update(self, level_data): if not self.alive: if self.dying: self.update_death_animation() return keys = pygame.key.get_pressed() if (keys[pygame.K_SPACE] or keys[pygame.K_UP]) and self.on_ground(level_data) and not self.jumped and self.vel_y == 0: self.vel_y = jump_velocity self.jumped = True self.frame_index = 0 if keys[pygame.K_LEFT]: self.vel_x = -self.speed self.last_direction = 'left' elif keys[pygame.K_RIGHT]: self.vel_x = self.speed self.last_direction = 'right' else: self.vel_x = 0 # Move player with the moving platform if standing on it if self.on_moving_platform: self.rect.x = self.on_moving_platform.rect.x + self.rel_x self.rect.y = self.on_moving_platform.rect.y + self.rel_y self.rect.x += self.vel_x self.check_collision_x(level_data) self.rect.x = max(0, min(self.rect.x, screen_size[0] - self.rect.width)) self.vel_y += gravity self.rect.y += self.vel_y self.check_collision_y(level_data) self.rect.y = max(0, min(self.rect.y, screen_size[1] - self.rect.height)) self.update_animation(keys) def update_animation(self, keys): self.frame_counter += 1 idle_animation_speed = 10 run_animation_speed = 2 if self.dying: if self.frame_counter % death_animation_speed == 0: self.frame_index += 1 if self.frame_index >= len(self.death_images): self.frame_index = len(self.death_images) - 1 self.death_animation_complete = True self.image = self.death_images[self.frame_index] self.rect.bottom = self.death_y # Adjust position to ensure death animation on the ground self.rect.left = self.death_x # Ensure the x position remains consistent return if self.jumped: if self.last_direction == 'left': self.image = pygame.transform.flip(self.jump_images[self.frame_index], True, False) else: self.image = self.jump_images[self.frame_index] self.frame_index += 1 if self.frame_index >= len(self.jump_images): self.frame_index = len(self.jump_images) - 1 elif keys[pygame.K_LEFT]: if self.frame_counter % run_animation_speed == 0: self.frame_index += 1 if self.frame_index >= len(self.run_images): self.frame_index = 0 self.image = pygame.transform.flip(self.run_images[self.frame_index], True, False) self.last_direction = 'left' elif keys[pygame.K_RIGHT]: if self.frame_counter % run_animation_speed == 0: self.frame_index += 1 if self.frame_index >= len(self.run_images): self.frame_index = 0 self.image = self.run_images[self.frame_index] self.last_direction = 'right' else: if self.frame_counter % idle_animation_speed == 0: self.frame_index += 1 if self.frame_index >= len(self.idle_images): self.frame_index = 0 if self.last_direction == 'left': self.image = pygame.transform.flip(self.idle_images[self.frame_index], True, False) else: self.image = self.idle_images[self.frame_index] def check_collision_y(self, level_data): world_data = level_data[0] all_sprites = level_data[1] self.on_moving_platform = None # Reset platform reference for row in range(len(world_data)): for col in range(len(world_data[0])): tile = world_data[row][col] if tile != 0: tile_rect = pygame.Rect(col * tile_size, row * tile_size, tile_size, tile_size) if self.rect.colliderect(tile_rect): if self.vel_y > 0 and self.rect.bottom > tile_rect.top and self.rect.bottom < tile_rect.bottom: self.rect.bottom = tile_rect.top self.vel_y = 0 self.jumped = False elif self.vel_y < 0 and self.rect.top < tile_rect.bottom and self.rect.top > tile_rect.top: self.rect.top = tile_rect.bottom self.vel_y = 0 # Check collision with moving platforms for sprite in all_sprites: if isinstance(sprite, MovingTile): if self.rect.colliderect(sprite.rect): if self.vel_y > 0 and self.rect.bottom > sprite.rect.top and self.rect.bottom < sprite.rect.bottom: self.rect.bottom = sprite.rect.top self.vel_y = 0 self.jumped = False self.on_moving_platform = sprite self.rel_x = self.rect.x - sprite.rect.x self.rel_y = self.rect.y - sprite.rect.y elif self.vel_y < 0 and self.rect.top < sprite.rect.bottom and self.rect.top > sprite.rect.top: self.rect.top = sprite.rect.bottom self.vel_y = 0 # Check collision with zombies for sprite in all_sprites: if isinstance(sprite, Zombie): if self.rect.colliderect(sprite.rect): self.die() # Check collision with acid for sprite in all_sprites: if isinstance(sprite, Acid): if self.rect.colliderect(sprite.rect): self.die() # Check collision with the top of the screen if self.rect.top <= 0: self.rect.top = 0 self.vel_y = 0 def check_collision_x(self, level_data): world_data = level_data[0] all_sprites = level_data[1] for row in range(len(world_data)): for col in range(len(world_data[0])): tile = world_data[row][col] if tile != 0: tile_rect = pygame.Rect(col * tile_size, row * tile_size, tile_size, tile_size) if self.rect.colliderect(tile_rect): if self.vel_x > 0: self.rect.right = tile_rect.left elif self.vel_x < 0: self.rect.left = tile_rect.right # Check collision with moving platforms for sprite in all_sprites: if isinstance(sprite, MovingTile): if self.rect.colliderect(sprite.rect): if self.vel_x > 0: self.rect.right = sprite.rect.left elif self.vel_x < 0: self.rect.left = sprite.rect.right # Check collision with zombies for sprite in all_sprites: if isinstance(sprite, Zombie): if self.rect.colliderect(sprite.rect): self.die() def on_ground(self, level_data): world_data = level_data[0] all_sprites = level_data[1] for col in range(len(world_data[0])): tile = world_data[self.rect.bottom // tile_size][col] if tile != 0: return True # Check if on top of moving platforms for sprite in all_sprites: if isinstance(sprite, MovingTile): if self.rect.colliderect(sprite.rect): if self.rect.bottom == sprite.rect.top: self.on_moving_platform = sprite self.rel_x = self.rect.x - sprite.rect.x self.rel_y = self.rect.y - sprite.rect.y return True return False class Zombie(pygame.sprite.Sprite): def __init__(self, x, y, speed, delay, waypoints): super().__init__() self.tile_size = 50 self.idle_images = [pygame.image.load(f'Gilbert/Images/Idle ({i}).png') for i in range(1, 16)] self.idle_images = [pygame.transform.scale(image, (self.tile_size, self.tile_size)) for image in self.idle_images] self.walk_images = [pygame.image.load(f'Gilbert/Images/Walk ({i}).png') for i in range(1, 11)] self.walk_images = [pygame.transform.scale(image, (self.tile_size, self.tile_size)) for image in self.walk_images] self.image = self.idle_images[0] self.rect = self.image.get_rect(topleft=(x, y)) self.start_x = x self.start_y = y self.speed = int(speed) self.delay = int(delay) self.waypoints = waypoints self.waypoint_index = 0 self.wait_time = 0 self.moving = True self.returning = False self.return_delay = False self.frame_index = 0 self.frame_counter = 0 self.last_direction = 'right' self.idle_animation_speed = 10 # Adjust speed as needed, making it faster than before def update(self, delta_time): if not player.alive or level_complete: return if not self.moving: self.wait_time += 1 if self.wait_time > self.delay * SPRITE_FPS: self.wait_time = 0 self.moving = True self.update_idle_animation() elif self.return_delay: self.wait_time += 1 if self.wait_time > self.delay * SPRITE_FPS: self.wait_time = 0 self.return_delay = False self.moving = True self.update_idle_animation() elif self.returning: self.move_to_target(self.start_x, self.start_y) if self.rect.x == self.start_x and self.rect.y == self.start_y: self.returning = False self.return_delay = True self.update_walk_animation() else: if self.waypoints: waypoint = self.waypoints[self.waypoint_index] target_x, target_y = waypoint[1] * self.tile_size, waypoint[0] * self.tile_size self.move_to_target(target_x, target_y) if self.rect.x == target_x and self.rect.y == target_y: self.moving = False self.wait_time = 0 # Reset the wait time for delay before next movement self.waypoint_index += 1 if self.waypoint_index >= len(self.waypoints): self.waypoint_index = 0 self.returning = True self.update_walk_animation() def move_to_target(self, target_x, target_y): dx = target_x - self.rect.x dy = target_y - self.rect.y dist = (dx**2 + dy**2)**0.5 if dist > self.speed: self.rect.x += int(self.speed * (dx / dist)) self.rect.y += int(self.speed * (dy / dist)) if dx > 0: self.last_direction = 'right' else: self.last_direction = 'left' else: self.rect.x, self.rect.y = target_x, target_y def update_idle_animation(self): self.frame_counter += 1 if self.frame_counter % self.idle_animation_speed == 0: self.frame_index += 1 if self.frame_index >= len(self.idle_images): self.frame_index = 0 if self.last_direction == 'left': self.image = pygame.transform.flip(self.idle_images[self.frame_index], True, False) else: self.image = self.idle_images[self.frame_index] def update_walk_animation(self): self.frame_counter += 1 walk_animation_speed = max(1, 10 - self.speed) # Adjust speed based on sprite speed, making sure it's at least 1 if self.frame_counter % walk_animation_speed == 0: self.frame_index += 1 if self.frame_index >= len(self.walk_images): self.frame_index = 0 if self.last_direction == 'left': self.image = pygame.transform.flip(self.walk_images[self.frame_index], True, False) else: self.image = self.walk_images[self.frame_index] class MovingTile(pygame.sprite.Sprite): def __init__(self, x, y, speed, delay, waypoints): super().__init__() self.image = moving_tile_img self.rect = self.image.get_rect(topleft=(x, y)) self.start_x = x self.start_y = y self.speed = int(speed) self.delay = int(delay) self.waypoints = waypoints self.waypoint_index = 0 self.wait_time = 0 self.moving = True self.returning = False self.return_delay = False self.vel_x = 0 self.vel_y = 0 self.previous_position = self.rect.topleft def update(self, delta_time): if not player.alive or level_complete: return self.previous_position = self.rect.topleft if not self.moving: self.wait_time += 1 if self.wait_time > self.delay * SPRITE_FPS: self.wait_time = 0 self.moving = True elif self.return_delay: self.wait_time += 1 if self.wait_time > self.delay * SPRITE_FPS: self.wait_time = 0 self.return_delay = False self.moving = True elif self.returning: self.move_to_target(self.start_x, self.start_y) if self.rect.x == self.start_x and self.rect.y == self.start_y: self.returning = False self.return_delay = True else: if self.waypoints: waypoint = self.waypoints[self.waypoint_index] target_x, target_y = waypoint[1] * tile_size, waypoint[0] * tile_size self.move_to_target(target_x, target_y) if self.rect.x == target_x and self.rect.y == target_y: self.moving = False self.wait_time = 0 # Reset the wait time for delay before next movement self.waypoint_index += 1 if self.waypoint_index >= len(self.waypoints): self.waypoint_index = 0 self.returning = True self.vel_x = self.rect.x - self.previous_position[0] self.vel_y = self.rect.y - self.previous_position[1] def move_to_target(self, target_x, target_y): dx = target_x - self.rect.x dy = target_y - self.rect.y dist = (dx**2 + dy**2)**0.5 if dist > self.speed: self.rect.x += int(self.speed * (dx / dist)) self.rect.y += int(self.speed * (dy / dist)) else: self.rect.x, self.rect.y = target_x, target_y class GoldCoin(pygame.sprite.Sprite): def __init__(self, x, y): super().__init__() self.images = gold_coin_images self.frame_index = 0 self.frame_counter = 0 self.animation_speed = 2 self.image = self.images[self.frame_index] self.rect = self.image.get_rect(center=(x + tile_size // 2, y + tile_size // 2)) def update(self, delta_time): if not player.alive or level_complete: return self.frame_counter += 1 if self.frame_counter % self.animation_speed == 0: self.frame_index = (self.frame_index + 1) % len(self.images) self.image = self.images[self.frame_index] self.rect = self.image.get_rect(center=self.rect.center) class Key(pygame.sprite.Sprite): def __init__(self, x, y): super().__init__() self.images = key_images self.frame_index = 0 self.frame_counter = 0 self.animation_speed = 2 self.image = self.images[self.frame_index] self.rect = self.image.get_rect(topleft=(x, y)) def update(self, delta_time): if not player.alive or level_complete: return self.frame_counter += 1 if self.frame_counter % self.animation_speed == 0: self.frame_index = (self.frame_index + 1) % len(self.images) self.image = self.images[self.frame_index] class Door(pygame.sprite.Sprite): def __init__(self, x, y): super().__init__() self.images = { "locked": door_locked_img, "unlocked": door_unlocked_img, "open": door_open_img } self.state = "locked" self.image = self.images[self.state] self.rect = self.image.get_rect(topleft=(x, y - 25)) # Positioning door to extend above the tile self.unlocking = False self.opening = False self.animation_timer = 0 self.animation_speed = 1.0 # Adjust the animation speed as needed self.animation_stage = 0 # Added to track the animation stage def unlock_and_open(self): self.unlocking = True self.animation_stage = 0 self.animation_timer = 0 def update(self, delta_time): if self.unlocking: self.animation_timer += delta_time if self.animation_stage == 0 and self.animation_timer >= self.animation_speed: self.state = "unlocked" self.image = self.images[self.state] self.animation_timer = 0 self.animation_stage = 1 elif self.animation_stage == 1 and self.animation_timer >= self.animation_speed: self.state = "open" self.image = self.images[self.state] self.unlocking = False global door_opening_complete door_opening_complete = True class Acid(pygame.sprite.Sprite): def __init__(self, x, y, image, offset=0): super().__init__() self.image = image self.rect = self.image.get_rect(topleft=(x, y + offset)) # Adjust y position by offset # Create the player instance player = Player() all_sprites = pygame.sprite.Group() all_sprites.add(player) # Function to draw tiles based on level data def draw_tiles(level_data): world_data = level_data[0] sprite_data = level_data[1] for row in range(len(world_data)): for col in range(len(world_data[0])): tile_id = world_data[row][col] if tile_id == 0: continue elif tile_id == 1: screen.blit(block_img, (col * tile_size, row * tile_size)) elif tile_id == 2: screen.blit(block2_img, (col * tile_size, row * tile_size)) elif tile_id == 3: screen.blit(block3_img, (col * tile_size, row * tile_size)) elif tile_id == 4: screen.blit(block4_img, (col * tile_size, row * tile_size)) elif tile_id == 5: screen.blit(block5_img, (col * tile_size, row * tile_size)) elif tile_id == 6: screen.blit(block6_img, (col * tile_size, row * tile_size)) elif tile_id == 7: screen.blit(block7_img, (col * tile_size, row * tile_size)) elif tile_id == 8: screen.blit(block8_img, (col * tile_size, row * tile_size)) elif tile_id == 9: screen.blit(block9_img, (col * tile_size, row * tile_size)) elif tile_id == 10: screen.blit(block10_img, (col * tile_size, row * tile_size)) elif tile_id == 11: screen.blit(block11_img, (col * tile_size, row * tile_size)) elif tile_id == 12: screen.blit(block12_img, (col * tile_size, row * tile_size)) elif tile_id == 13: screen.blit(block13_img, (col * tile_size, row * tile_size)) elif tile_id == 14: screen.blit(block14_img, (col * tile_size, row * tile_size)) elif tile_id == 15: screen.blit(block15_img, (col * tile_size, row * tile_size)) elif tile_id == 101: acid = Acid(col * tile_size, row * tile_size, Acid_img, tile_size - 40) # Adjust position with offset all_sprites.add(acid) world_data[row][col] = 0 # Clear the tile after adding the sprite elif tile_id == 102: acid2 = Acid(col * tile_size, row * tile_size, Acid2_img) all_sprites.add(acid2) world_data[row][col] = 0 # Clear the tile after adding the sprite elif tile_id == 103: if (row, col) not in sprite_data: continue data = sprite_data[(row, col)] zombie = Zombie(col * tile_size, row * tile_size, data['speed'], data['delay'], data['waypoints']) all_sprites.add(zombie) world_data[row][col] = 0 # Clear the tile after adding the sprite elif tile_id == 104: if (row, col) not in sprite_data: continue data = sprite_data[(row, col)] moving_tile = MovingTile(col * tile_size, row * tile_size, data['speed'], data['delay'], data['waypoints']) all_sprites.add(moving_tile) world_data[row][col] = 0 # Clear the tile after adding the sprite elif tile_id == 105: coin = GoldCoin(col * tile_size, row * tile_size) all_sprites.add(coin) world_data[row][col] = 0 # Clear the tile after adding the sprite elif tile_id == 106: key = Key(col * tile_size, row * tile_size) all_sprites.add(key) world_data[row][col] = 0 # Clear the tile after adding the sprite elif tile_id == 107: door = Door(col * tile_size, row * tile_size) all_sprites.add(door) world_data[row][col] = 0 # Clear the tile after adding the sprite # Function to set the player's initial position based on the spawn point def set_player_spawn(spawn_point): if spawn_point: player.rect.topleft = (spawn_point[1] * tile_size, spawn_point[0] * tile_size) # Function to check for player collision with coins and update coin count def check_coin_collision(player_rect): global coin_count for sprite in all_sprites: if isinstance(sprite, GoldCoin) and player_rect.colliderect(sprite.rect): coin_sound.play() sprite.kill() # Remove the coin from the sprite group coin_count += 1 # Function to check for player collision with keys and update key status def check_key_collision(player_rect): global has_key for sprite in all_sprites: if isinstance(sprite, Key) and player_rect.colliderect(sprite.rect): key_sound.play() sprite.kill() has_key = True # Function to check for player collision with doors and update game state def check_door_collision(player_rect): global game_running, level_complete, player_idle, door_unlocking, door_opening_complete for sprite in all_sprites: if isinstance(sprite, Door) and player_rect.colliderect(sprite.rect) and has_key: sprite.unlock_and_open() player_idle = True door_unlocking = True game_running = False level_complete = True player.alive = False # Function to draw the coin count UI def draw_coin_count(): screen.blit(ui_img, (5, 3)) coin_text = font.render(f"COINS: {coin_count}", True, (255, 255, 255)) screen.blit(coin_text, (20, 15)) # Function to draw the key status UI def draw_key_status(): screen.blit(ui_img, (125, 3)) key_text = font.render(f"KEY: {'YES' if has_key else 'NONE'}", True, (255, 255, 255)) screen.blit(key_text, (139, 15)) # Function to draw the death UI def draw_death_ui(): screen.blit(main_ui_img, ((screen_size[0] - 600) // 2, (screen_size[1] - 300) // 2)) death_text = death_font.render("YOU DIED", True, (255, 0, 0)) death_text_rect = death_text.get_rect(center=(screen_size[0] // 2, (screen_size[1] // 2) - 50)) screen.blit(death_text, death_text_rect) button_offset_y = 30 screen.blit(ui_button_img, (screen_size[0] // 2 - 220, screen_size[1] // 2 + button_offset_y)) screen.blit(ui_button_img, (screen_size[0] // 2 + 20, screen_size[1] // 2 + button_offset_y)) menu_text = font.render("MENU", True, (255, 255, 255)) menu_text_rect = menu_text.get_rect(center=(screen_size[0] // 2 - 120, screen_size[1] // 2 + button_offset_y + 40)) screen.blit(menu_text, menu_text_rect) retry_text = font.render("RETRY", True, (255, 255, 255)) retry_text_rect = retry_text.get_rect(center=(screen_size[0] // 2 + 120, screen_size[1] // 2 + button_offset_y + 40)) screen.blit(retry_text, retry_text_rect) # Function to draw the level complete UI def draw_level_complete_ui(): screen.blit(main_ui_img, ((screen_size[0] - 600) // 2, (screen_size[1] - 300) // 2)) level_complete_text = death_font.render("LEVEL COMPLETE", True, (0, 255, 0)) level_complete_text_rect = level_complete_text.get_rect(center=(screen_size[0] // 2, (screen_size[1] // 2) - 50)) screen.blit(level_complete_text, level_complete_text_rect) button_offset_y = 30 screen.blit(ui_button_img, (screen_size[0] // 2 - 220, screen_size[1] // 2 + button_offset_y)) screen.blit(ui_button_img, (screen_size[0] // 2 + 20, screen_size[1] // 2 + button_offset_y)) menu_text = font.render("MENU", True, (255, 255, 255)) menu_text_rect = menu_text.get_rect(center=(screen_size[0] // 2 - 120, screen_size[1] // 2 + button_offset_y + 40)) screen.blit(menu_text, menu_text_rect) next_text = font.render("NEXT", True, (255, 255, 255)) next_text_rect = next_text.get_rect(center=(screen_size[0] // 2 + 120, screen_size[1] // 2 + button_offset_y + 40)) screen.blit(next_text, next_text_rect) # Function to draw the victory UI def draw_victory_ui(): screen.blit(main_ui_img, ((screen_size[0] - 600) // 2, (screen_size[1] - 300) // 2)) victory_text = death_font.render("VICTORY", True, (255, 215, 0)) # Gold color victory_text_rect = victory_text.get_rect(center=(screen_size[0] // 2, (screen_size[1] // 2) - 50)) screen.blit(victory_text, victory_text_rect) button_offset_y = 30 screen.blit(ui_button_img, (screen_size[0] // 2 - 220, screen_size[1] // 2 + button_offset_y)) screen.blit(ui_button_img, (screen_size[0] // 2 + 20, screen_size[1] // 2 + button_offset_y)) menu_text = font.render("MENU", True, (255, 255, 255)) menu_text_rect = menu_text.get_rect(center=(screen_size[0] // 2 - 120, screen_size[1] // 2 + button_offset_y + 40)) screen.blit(menu_text, menu_text_rect) restart_text = font.render("RESTART", True, (255, 255, 255)) restart_text_rect = restart_text.get_rect(center=(screen_size[0] // 2 + 120, screen_size[1] // 2 + button_offset_y + 40)) screen.blit(restart_text, restart_text_rect) # Function to reset the level def reset_level(): global coin_count, has_key, player, ui_active, ui_timer, game_running, level_complete, player_idle, door_unlocking, door_opening_complete, initial_coin_count, level_data, all_sprites coin_count = initial_coin_count has_key = False player = Player() all_sprites.empty() all_sprites.add(player) level_data = load_level_data(level_name) if level_data: set_player_spawn(level_data[2]) draw_tiles(level_data) ui_active = False ui_timer = 0 game_running = True level_complete = False player_idle = False door_unlocking = False door_opening_complete = False # Function to load the next level if it exists def load_next_level(): global level_name, coin_count, initial_coin_count, level_data, all_sprites, ui_active, level_complete, victory current_level_match = re.search(r'\d+', level_name) # Find the numeric part of the level name if current_level_match: current_level_index = int(current_level_match.group()) next_level_index = current_level_index + 1 next_level_name = f'level{next_level_index}_data' if os.path.exists(f'Gilbert/Levels/{next_level_name}'): level_name = next_level_name initial_coin_count = coin_count reset_level() else: level_complete = False victory = True ui_active = False else: print("Invalid level name format.") running = True game_running = True level_name = 'level1_data' level_complete = False player_idle = False door_unlocking = False door_opening_complete = False victory = False # Load level data level_data = load_level_data(level_name) if level_data: initial_coin_count = coin_count set_player_spawn(level_data[2]) # Set player's spawn point else: print("Failed to load level data.") # Initialize game variables game_running = True level_complete = False player_idle = False door_unlocking = False door_opening_complete = False ui_active = False ui_timer = 0 sprite_update_time = 0 # Initialize sprite_update_time sprite_update_interval = 1 / SPRITE_FPS # Update interval for sprites level_complete_ui_timer = 0 death_ui_timer = 0 # Main loop while running: delta_time = clock.tick(FPS) / 1000.0 # Convert to seconds for event in pygame.event.get(): if event.type == pygame.QUIT: running = False elif event.type == pygame.MOUSEBUTTONDOWN and ui_active: mouse_pos = pygame.mouse.get_pos() if screen_size[0] // 2 - 220 <= mouse_pos[0] <= screen_size[0] // 2 - 20 and screen_size[1] // 2 + 30 <= mouse_pos[1] <= screen_size[1] // 2 + 110: # Placeholder for menu button pass elif screen_size[0] // 2 + 20 <= mouse_pos[0] <= screen_size[0] // 2 + 220 and screen_size[1] // 2 + 30 <= mouse_pos[1] <= screen_size[1] // 2 + 110: if victory: # Restart from the first level level_name = 'level1_data' coin_count = 0 initial_coin_count = 0 reset_level() else: if level_complete: load_next_level() else: reset_level() # Clear the screen with a background color or image screen.fill(color) screen.blit(background_image, (0, 0)) # Draw tiles draw_tiles(level_data) if game_running: # Normal gameplay state player.update((level_data[0], all_sprites)) sprite_update_time += delta_time if sprite_update_time >= sprite_update_interval: sprite_update_time -= sprite_update_interval for sprite in all_sprites: if sprite is not player: sprite.update(delta_time) # Check for coin collisions check_coin_collision(player.rect) # Check for key collisions check_key_collision(player.rect) # Check for door collisions check_door_collision(player.rect) # Draw all sprites except player for sprite in all_sprites: if sprite is not player: screen.blit(sprite.image, sprite.rect) # Draw player screen.blit(player.image, player.rect) # Draw coin count UI draw_coin_count() # Draw key status UI draw_key_status() if level_complete and not victory: # Level complete state for sprite in all_sprites: if isinstance(sprite, Door): sprite.update(delta_time) screen.blit(sprite.image, sprite.rect) ui_timer += delta_time if door_opening_complete and not ui_active: if ui_timer >= 1: draw_level_complete_ui() ui_active = True if ui_active: draw_level_complete_ui() if player.dying: # Player death state player.update_death_animation() if player.death_animation_complete and not ui_active: ui_timer += delta_time if ui_timer >= 1: draw_death_ui() ui_active = True if ui_active: draw_death_ui() if player_idle: player.image = player.idle_images[0] if victory: draw_victory_ui() # Draw grid lines for x in range(0, screen.get_width(), tile_size): pygame.draw.line(screen, (0, 0, 0), (x, 0), (x, screen.get_height())) for y in range(0, screen.get_height(), tile_size): pygame.draw.line(screen, (0, 0, 0), (0, y), (screen.get_width(), y)) pygame.display.update() pygame.quit() sys.exit()