""" ------------------------------------------------ Project: Platformer Game Standard: 2.7 (91896) School: Tauranga Boys' College Author: Luke Jones Date: 16/06/2025 Python: 3.11.9 ------------------------------------------------ """ import pygame from pygame import mixer import sys import os import random import csv import button # Initial Setup pygame.init() mixer.init() clock = pygame.time.Clock() # Constant Variables SCREEN_WIDTH = 800 SCREEN_HEIGHT = int(SCREEN_WIDTH * 0.8) ROWS = 16 COLS = 150 TILE_SIZE = SCREEN_HEIGHT // ROWS TILE_TYPES = 22 SCROLL_THRESH = 200 GRAVITY = 0.75 MAX_LEVELS = 6 FPS = 120 # Variables level = 0 screen_scroll = 0 bg_scroll = 0 start_game = False start_intro = False score = 0 moving_left = False moving_right = False shoot = False grenade = False grenade_thrown = False key_collected = False dead_enemies = [] completion_fade = False # Colour Variables BG = (144, 201, 120) RED = (255, 0, 0) WHITE = (255, 255, 255) GREEN = (144, 201, 120) BLACK = (0, 0, 0) PINK = (235, 65, 54) BLUE = (0, 0, 255) # Display Setup screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) pygame.display.set_caption("1-3 // HALLS OF SACRED REMAINS") # Game font font = pygame.font.SysFont("Futura", 30) # Function to draw text on the screen def draw_text(text, font, text_col, x, y): img = font.render(text, True, text_col) screen.blit(img, (x, y)) # Function to draw the background of the game, and have each background image scroll at different speeds def draw_bg(): screen.fill(BG) width = sky_img.get_width() for x in range(5): screen.blit(sky_img, ((x * width) - bg_scroll * 0.5, 0)) screen.blit(mountain_img, ((x * width) - bg_scroll * 0.6, SCREEN_HEIGHT - mountain_img.get_height() - 250)) screen.blit(pine1_img, ((x * width) - bg_scroll * 0.7, SCREEN_HEIGHT - pine1_img.get_height() - 120)) screen.blit(pine2_img, ((x * width) - bg_scroll * 0.8, SCREEN_HEIGHT - pine2_img.get_height())) # Function to reset levels in the game, after the player has died or reached the next level def reset_level(): enemy_group.empty() bullet_group.empty() grenade_group.empty() explosion_group.empty() item_box_group.empty() decoration_group.empty() water_group.empty() exit_group.empty() key_group.empty() # Create empty tile list data = [] for row in range(ROWS): r = [-1] * COLS data.append(r) return data # Creating the file for the high score to be saved HIGH_SCORE_FILE = "high_score.txt" # Function to load the high score into the game from the high score file def load_high_score(): """Load the high score from a file, if it exists. Return 0 if there is an error or the file doesn't exist.""" if os.path.exists(HIGH_SCORE_FILE): with open(HIGH_SCORE_FILE, 'r') as file: try: return int(file.read().strip()) except ValueError: return 0 return 0 # Function to save the high score to a file def save_high_score(high_score): """Save the current high score to a file.""" with open(HIGH_SCORE_FILE, 'w') as file: file.write(str(high_score)) # Function to check if the score exceeds the current high score, and to save the new high score to a file if so. def high_score_check(score): global high_score if score > high_score: high_score = score save_high_score(high_score) high_score = load_high_score() # Load mixer/music and sound effects for the game pygame.mixer.music.load("audio/music2.mp3") pygame.mixer.music.play(-1, 0.0, 2500) jump_fx = pygame.mixer.Sound("audio/jump.wav") jump_fx.set_volume(0.25) shot_fx = pygame.mixer.Sound("audio/shot.wav") shot_fx.set_volume(0.25) grenade_fx = pygame.mixer.Sound("audio/grenade.wav") grenade_fx.set_volume(0.25) # Loading the background images for the game pine1_img = pygame.image.load("img/Background/pine1.png").convert_alpha() pine2_img = pygame.image.load("img/Background/pine2.png").convert_alpha() mountain_img = pygame.image.load("img/Background/mountain.png").convert_alpha() sky_img = pygame.image.load("img/Background/sky_cloud.png").convert_alpha() # Loading the button images for the game start_img = pygame.image.load("img/start_btn.png").convert_alpha() exit_img = pygame.image.load("img/exit_btn.png").convert_alpha() restart_img = pygame.image.load("img/restart_btn.png").convert_alpha() # Loading all the map images img_list = [] for x in range(TILE_TYPES): img = pygame.image.load(f"img/Tile/{x}.png") img = pygame.transform.scale(img, (TILE_SIZE, TILE_SIZE)) img_list.append(img) # Loading images for the item boxes/grenades and bullets, and putting the item box images into a list bullet_img = pygame.image.load("img/icons/bullet.png").convert_alpha() grenade_img = pygame.image.load("img/icons/grenade.png").convert_alpha() health_box_img = pygame.image.load("img/icons/health_box.png").convert_alpha() ammo_box_img = pygame.image.load("img/icons/ammo_box.png").convert_alpha() grenade_box_img = pygame.image.load("img/icons/grenade_box.png").convert_alpha() item_boxes = { "Health" : health_box_img, "Ammo" : ammo_box_img, "Grenade" : grenade_box_img } # Soldier class for the enemies and the player character class Soldier(pygame.sprite.Sprite): def __init__(self, char_type, x, y, scale, speed, ammo, grenades): pygame.sprite.Sprite.__init__(self) self.alive = True self.char_type = char_type self.speed = speed self.ammo = ammo self.start_ammo = ammo self.shoot_cooldown = 0 self.grenades = grenades self.health = 100 self.max_health = self.health self.direction = 1 self.vel_y = 0 self.jump = False self.in_air = True self.flip = False self.animation_list = [] self.frame_index = 0 self.action = 0 self.update_time = pygame.time.get_ticks() # Variables specifically for the enemy AI self.move_counter = 0 self.vision = pygame.Rect(0, 0 , 150, 20) self.idling = False self.idling_counter = 0 # Loading all the images for the player/enemies and setting up the player/enemy animations animation_types = ["Idle", "Run", "Jump", "Death"] for animation in animation_types: temp_list = [] num_of_frames = len(os.listdir(f"img/{self.char_type}/{animation}")) for i in range(num_of_frames): img = pygame.image.load(f"img/{self.char_type}/{animation}/{i}.png") img = pygame.transform.scale(img, (int(img.get_width() * scale), int(img.get_height() * scale))) temp_list.append(img) self.animation_list.append(temp_list) self.image = self.animation_list[self.action][self.frame_index] self.rect = self.image.get_rect() self.rect.center = (x, y) self.width = self.image.get_width() self.height = self.image.get_height() # Function to update the player/enemies def update(self): self.update_animation() self.check_alive() if self.shoot_cooldown > 0: self.shoot_cooldown -= 1 # Function to add movement for the player, and for checking collision def move(self, moving_left, moving_right): screen_scroll = 0 dx = 0 dy = 0 can_jump = True # Checks if the player is moving left, and allows them to move left if moving_left: dx = -self.speed self.flip = True self.direction = -1 # Checks if the player is moving right, and allows them to move right if moving_right: dx = self.speed self.flip = False self.direction = 1 # Allows the player to jump if self.jump == True and self.in_air == False and can_jump: self.vel_y = -17 self.jump = False self.in_air = True can_jump = False jump_fx.play() # Apply gravity when the player is jumping/falling self.vel_y += GRAVITY dy += self.vel_y * 0.5 # Check for collision for both player and enemies for tile in world.obstacle_list: # Check for collision in the x direction if tile[1].colliderect(self.rect.x + dx, self.rect.y, self.width, self.height - 1): dx = 0 # If an enemy hits a wall, the code below makes it turn around if self.char_type == "enemy": self.direction *= -1 self.move_counter = 0 # Check for collision in the y direction if tile[1].colliderect(self.rect.x, self.rect.y + dy, self.width, self.height): # Check if the player is below the ground, such as jumping if self.vel_y < 0: self.vel_y = 0 dy = tile[1].bottom - self.rect.top # Check if the player is above the ground, such as falling elif self.vel_y >= 0: self.vel_y = 0 self.in_air = False can_jump = True dy = tile[1].top - self.rect.bottom # Check for collision with water if pygame.sprite.spritecollide(self, water_group, False): self.health = 0 # Check for collision with exit level_complete = False if pygame.sprite.spritecollide(self, exit_group, False) and key_collected: level_complete = True # Check if fallen off the map if self.rect.bottom > SCREEN_HEIGHT: self.health = 0 # Check if player is colliding with the edge of the map if self.char_type == "player": if self.rect.left + dx < 0 or self.rect.right + dx > SCREEN_WIDTH: dx = 0 # Update rect position self.rect.x += dx self.rect.y += dy # Update the world scroll based on the player position if self.char_type == "player": if (self.rect.right > SCREEN_WIDTH - SCROLL_THRESH and bg_scroll < (world.level_length * TILE_SIZE) - SCREEN_WIDTH) or (self.rect.left < SCROLL_THRESH and bg_scroll > abs(dx)): self.rect.x -= dx screen_scroll = -dx return screen_scroll, level_complete # Function to allow the player/enemy to shoot def shoot(self): if self.shoot_cooldown == 0 and self.ammo > 0: self.shoot_cooldown = 20 bullet = Bullet(self.rect.centerx + (0.75 * self.rect.size[0] * self.direction), self.rect.centery, self.direction) bullet_group.add(bullet) self.ammo -= 1 shot_fx.play() # The AI for the enemies, for movement and shooting def ai(self): if self.alive and player.alive: # Randomly causes the enemy to start idling if self.idling == False and random.randint(1, 200) == 1: self.update_action(0) self.idling = True self.idling_counter = 50 # Check if the player has collided with the enemies vision, and shoot if so if self.vision.colliderect(player.rect): self.update_action(0) self.shoot() self.vision.center = (self.rect.centerx + 75 * self.direction, self.rect.centery) else: if self.idling == False: if self.direction == 1: ai_moving_right = True else: ai_moving_right = False ai_moving_left = not ai_moving_right self.move(ai_moving_left, ai_moving_right) self.update_action(1) self.move_counter += 1 self.vision.center = (self.rect.centerx + 75 * self.direction, self.rect.centery) # Flips the enemies direction to prevent them walking off a tile if self.move_counter > TILE_SIZE: self.direction *= -1 self.move_counter *= -1 else: self.idling_counter -= 1 if self.idling_counter <= 0: self.idling = False self.rect.x += screen_scroll # Function to update the animation for the player def update_animation(self): ANIMATION_COOLDOWN = 100 self.image = self.animation_list[self.action][self.frame_index] if pygame.time.get_ticks() - self.update_time > ANIMATION_COOLDOWN: self.update_time = pygame.time.get_ticks() self.frame_index += 1 if self.frame_index >= len(self.animation_list[self.action]): if self.action == 3: self.frame_index = len(self.animation_list[self.action]) - 1 else: self.frame_index = 0 def update_action(self, new_action): if new_action != self.action: self.action = new_action self.frame_index = 0 self.update_time = pygame.time.get_ticks() # Check if the player/enemies are alive def check_alive(self): if self.health <= 0: self.health = 0 self.speed = 0 self.alive = False self.update_action(3) # Function to draw the player/enemies def draw(self): screen.blit(pygame.transform.flip(self.image, self.flip, False), self.rect) class World(): def __init__(self): self.obstacle_list = [] def process_data(self, data): self.level_length = len(data[0]) # Iterate through each value in level data file for y, row in enumerate(data): for x, tile in enumerate(row): if tile >= 0: img = img_list[tile] img_rect = img.get_rect() img_rect.x = x * TILE_SIZE img_rect.y = y * TILE_SIZE tile_data = (img, img_rect) if tile >= 0 and tile <= 8: # Create map tiles self.obstacle_list.append(tile_data) elif tile >= 9 and tile <= 10: # Create the water for the map water = Water(img, x * TILE_SIZE, y * TILE_SIZE) water_group.add(water) elif tile >= 11 and tile <= 14: # Create decoration for the map decoration = Decoration(img, x * TILE_SIZE, y * TILE_SIZE) decoration_group.add(decoration) elif tile == 15: # Create player player = Soldier("player", x * TILE_SIZE, y * TILE_SIZE, 1.65, 4, 20, 5) health_bar = HealthBar(10, 10, player.health, player.health) elif tile == 16: # Create enemies enemy = Soldier("enemy", x * TILE_SIZE, y * TILE_SIZE, 1.65, 1, 20, 0) enemy_group.add(enemy) elif tile == 17: # Create ammo boxes item_box = ItemBox("Ammo", x * TILE_SIZE, y * TILE_SIZE) item_box_group.add(item_box) elif tile == 18: # Create grenade boxes item_box = ItemBox("Grenade", x * TILE_SIZE, y * TILE_SIZE) item_box_group.add(item_box) elif tile == 19: # Create health boxes item_box = ItemBox("Health", x * TILE_SIZE, y * TILE_SIZE) item_box_group.add(item_box) elif tile == 20: # Create the level exit exit = Exit(img, x * TILE_SIZE, y * TILE_SIZE) exit_group.add(exit) elif tile == 21: # Create the key for the exit key = Key(img, x * TILE_SIZE, y * TILE_SIZE) key_group.add(key) return player, health_bar # Function to draw all the tiles for the level onto the screen def draw(self): for tile in self.obstacle_list: tile[1][0] += screen_scroll screen.blit(tile[0], tile[1]) # Class for the map decoration class Decoration(pygame.sprite.Sprite): def __init__(self, img, x, y): pygame.sprite.Sprite.__init__(self) self.image = img self.rect = self.image.get_rect() self.rect.midtop = (x + TILE_SIZE // 2, y + (TILE_SIZE - self.image.get_height())) # Function to update the map decoration and make it move with the screen scroll def update(self): self.rect.x += screen_scroll # Class for the map water class Water(pygame.sprite.Sprite): def __init__(self, img, x, y): pygame.sprite.Sprite.__init__(self) self.image = img self.rect = self.image.get_rect() self.rect.midtop = (x + TILE_SIZE // 2, y + (TILE_SIZE - self.image.get_height())) # Function to update the map water and make it move with the screen scroll def update(self): self.rect.x += screen_scroll # Class for the map exit class Exit(pygame.sprite.Sprite): def __init__(self, img, x, y): pygame.sprite.Sprite.__init__(self) self.image = img self.rect = self.image.get_rect() self.rect.midtop = (x + TILE_SIZE // 2, y + (TILE_SIZE - self.image.get_height())) # Function to update the map exit and make it move with the screen scroll def update(self): self.rect.x += screen_scroll # Class for the map item boxes class ItemBox(pygame.sprite.Sprite): def __init__(self, item_type, x, y): pygame.sprite.Sprite.__init__(self) self.item_type = item_type self.image = item_boxes[self.item_type] self.rect = self.image.get_rect() self.rect.midtop = (x + TILE_SIZE // 2, y + (TILE_SIZE - self.image.get_height())) # Function to update the map exit and make it move with the screen scroll and check if the player has collided with item boxes def update(self): self.rect.x += screen_scroll # Check if player has picked up item box if pygame.sprite.collide_rect(self, player): # Check what type of item box the player collided with if self.item_type == "Health": player.health += 25 if player.health > player.max_health: player.health = player.max_health elif self.item_type == "Ammo": player.ammo += 25 elif self.item_type == "Grenade": player.grenades += 3 self.kill() # Class for the exit key class Key(pygame.sprite.Sprite): def __init__(self, img, x, y): pygame.sprite.Sprite.__init__(self) self.image = img self.rect = self.image.get_rect() self.rect.midtop = (x + TILE_SIZE // 2, y + (TILE_SIZE - self.image.get_height())) # Function to update the map exit and make it move with the screen scroll def update(self): global key_collected self.rect.x += screen_scroll # Check if player has picked up key if pygame.sprite.collide_rect(self, player): key_collected = True self.kill() # Class for the player healthbar class HealthBar(): def __init__(self, x, y, health, max_health): self.x = x self.y = y self.health = health self.max_health = max_health # Function to draw the player health bar onto the screen def draw(self, health): # update with new health self.health = health ratio = self.health / self.max_health pygame.draw.rect(screen, BLACK, (self.x - 2, self.y - 2, 154, 24)) pygame.draw.rect(screen, RED, (self.x, self.y, 150, 20)) pygame.draw.rect(screen, GREEN, (self.x, self.y, 150 * ratio, 20)) # Class for enemy/player bullets class Bullet(pygame.sprite.Sprite): def __init__(self, x, y, direction): pygame.sprite.Sprite.__init__(self) self.speed = 10 self.image = bullet_img self.rect = self.image.get_rect() self.rect.center = (x, y) self.direction = direction # Function to update the bullets with screen scroll and to check for collision def update(self): self.rect.x += (self.direction * self.speed) + screen_scroll if self.rect.right < 0 or self.rect.left > SCREEN_WIDTH: self.kill() # Check for collision with map for tile in world.obstacle_list: if tile[1].colliderect(self.rect): self.kill() # Check if player collides with a bullet if pygame.sprite.spritecollide(player, bullet_group, False): if player.alive: player.health -= 5 self.kill() # Check if enemy collides with bullet, and increases score if enemy dies for enemy in enemy_group: global score if pygame.sprite.spritecollide(enemy, bullet_group, False): if enemy.alive: enemy.health -= 25 self.kill() # Increase score if enemy is dead if enemy.health <= 0: if enemy in dead_enemies: pass else: score += 50 high_score_check(score) dead_enemies.append(enemy) # Class for player grenades class Grenade(pygame.sprite.Sprite): def __init__(self, x, y, direction): pygame.sprite.Sprite.__init__(self) self.timer = 100 self.vel_y = -11 self.speed = 7 self.image = grenade_img self.rect = self.image.get_rect() self.rect.center = (x, y) self.direction = direction self.width = self.image.get_width() self.height = self.image.get_height() # Function to update the grenades and check for collision def update(self): self.vel_y += GRAVITY dx = self.direction * self.speed dy = self.vel_y # Check for collision with level for tile in world.obstacle_list: # Check for collision with walls if tile[1].colliderect(self.rect.x + dx, self.rect.y, self.width, self.height): self.direction *= -1 dx = self.direction * self.speed # Check for collision in y direction if tile[1].colliderect(self.rect.x, self.rect.y + dy, self.width, self.height): self.speed = 0 # Check if below the ground, i.e. thrown up if self.vel_y < 0: self.vel_y = 0 dy = tile[1].bottom - self.rect.top # Check if above the ground, i.e. falling elif self.vel_y >= 0: self.vel_y = 0 dy = tile[1].top - self.rect.bottom self.rect.x += dx + screen_scroll self.rect.y += dy self.timer -= 1 # Create explosion when grenade timer is over if self.timer <= 0: self.kill() grenade_fx.play() explosion = Explosion(self.rect.x, self.rect.y, 0.5) explosion_group.add(explosion) # Do damage to any players or enemies nearby if abs(self.rect.centerx - player.rect.centerx) < TILE_SIZE * 2 and \ abs(self.rect.centery - player.rect.centery) < TILE_SIZE * 2: player.health -= 50 for enemy in enemy_group: global score if abs(self.rect.centerx - enemy.rect.centerx) < TILE_SIZE * 2 and \ abs(self.rect.centery - enemy.rect.centery) < TILE_SIZE * 2: enemy.health -= 50 # Increase score if enemy is dead if enemy.health <= 0: if enemy in dead_enemies: pass else: score += 50 high_score_check(score) dead_enemies.append(enemy) # Explosion class for the grenades class Explosion(pygame.sprite.Sprite): def __init__(self, x, y, scale): pygame.sprite.Sprite.__init__(self) self.images = [] for num in range(1, 6): img = pygame.image.load(f"img/explosion/exp{num}.png") img = pygame.transform.scale(img, (int(img.get_width() * 2), int(img.get_height() * 2))) self.images.append(img) self.frame_index = 0 self.image = self.images[self.frame_index] self.rect = self.image.get_rect() self.rect.center = (x, y) self.counter = 0 # Function to update the explosion with screen scroll, and handles the animation for the explosion def update(self): self.rect.x += screen_scroll EXPLOSION_SPEED = 4 self.counter += 1 if self.counter >= EXPLOSION_SPEED: self.counter = 0 self.frame_index += 1 # if the animation is complete then delete explosion if self.frame_index >= len(self.images): self.kill() else: self.image = self.images[self.frame_index] # Class for the screenfade class ScreenFade(): def __init__(self, direction, colour, speed): self.direction = direction self.colour = colour self.speed = speed self.fade_counter = 0 # Function to update the screen fade and handles what type the screen fade is def fade(self): fade_complete = False self.fade_counter += self.speed if self.direction == 1: pygame.draw.rect(screen, self.colour, (0 - self.fade_counter, 0, SCREEN_WIDTH // 2, SCREEN_HEIGHT)) pygame.draw.rect(screen, self.colour, (SCREEN_WIDTH // 2 + self.fade_counter, 0, SCREEN_WIDTH, SCREEN_HEIGHT)) pygame.draw.rect(screen, self.colour, (0, 0 - self.fade_counter, SCREEN_WIDTH, SCREEN_HEIGHT // 2)) pygame.draw.rect(screen, self.colour, (0, SCREEN_HEIGHT // 2 + self.fade_counter, SCREEN_WIDTH, SCREEN_HEIGHT)) if self.direction == 2: # vertical screen fade down pygame.draw.rect(screen, self.colour, (0, 0, SCREEN_WIDTH, 0 + self.fade_counter)) if self.fade_counter >= SCREEN_WIDTH: fade_complete = True return fade_complete # Create screen fades intro_fade = ScreenFade(1, BLACK, 6) death_fade = ScreenFade(2, PINK, 8) complete_fade = ScreenFade(2, GREEN, 8) # Create buttons start_button = button.Button(SCREEN_WIDTH // 2 - 130, SCREEN_HEIGHT // 2 - 150, start_img, 1) exit_button = button.Button(SCREEN_WIDTH // 2 - 110, SCREEN_HEIGHT // 2 + 50, exit_img, 1) restart_button = button.Button(SCREEN_WIDTH // 2 - 100, SCREEN_HEIGHT // 2 - 50, restart_img, 2) # Create sprite groups enemy_group = pygame.sprite.Group() bullet_group = pygame.sprite.Group() grenade_group = pygame.sprite.Group() explosion_group = pygame.sprite.Group() item_box_group = pygame.sprite.Group() decoration_group = pygame.sprite.Group() water_group = pygame.sprite.Group() exit_group = pygame.sprite.Group() key_group = pygame.sprite.Group() # Create empty tile list world_data = [] for row in range(ROWS): r = [-1] * COLS world_data.append(r) # Load in level data and create world with open(f"level{level}_data.csv", newline="") as csvfile: reader = csv.reader(csvfile, delimiter=",") for x, row in enumerate(reader): for y, tile in enumerate(row): world_data[x][y] = int(tile) world = World() player, health_bar = world.process_data(world_data) # Main game loop run = True while run: clock.tick(FPS) game_time = pygame.time.get_ticks() # Draw exit/start buttons and keybind information if the game has not started yet if start_game == False: screen.fill(BG) draw_text("KEYBINDS: ", font, BLUE, 10, 10 ) draw_text("A/D --> Movement", font, WHITE, 10, 40) draw_text("Q --> Grenade Throw", font, WHITE, 10, 70) draw_text("RIGHT CLICK --> Shoot", font, WHITE, 10, 100) draw_text("SPACE --> Jump", font, WHITE, 10, 130) if exit_button.draw(screen): run = False if start_button.draw(screen): start_game = True start_intro = True else: draw_bg() world.draw() # Draw the UI for the game health_bar.draw(player.health) draw_text("AMMO: ", font, WHITE, 10, 35) for x in range(player.ammo): screen.blit(bullet_img, (90 + (x * 10), 40)) draw_text("GRENADES: ", font, WHITE, 10, 60) for x in range(player.grenades): screen.blit(grenade_img, (135 + (x * 15), 60)) draw_text(f"SCORE: {score}", font, WHITE, 10, 85) draw_text(f"HIGH SCORE: {high_score}", font, WHITE, 10, 110) # Draw and update the groups decoration_group.update() decoration_group.draw(screen) bullet_group.update() bullet_group.draw(screen) grenade_group.update() grenade_group.draw(screen) item_box_group.update() item_box_group.draw(screen) exit_group.update() exit_group.draw(screen) key_group.update() key_group.draw(screen) player.draw() player.update() for enemy in enemy_group: enemy.ai() enemy.update() enemy.draw() explosion_group.update() explosion_group.draw(screen) water_group.update() water_group.draw(screen) # Show level intro fade if start_intro: if intro_fade.fade(): start_intro = False intro_fade.fade_counter = 0 # Show game completion fade if completion_fade: if complete_fade.fade(): draw_text("You have completed the game!", font, WHITE, 250, 130) # If restart button is clicked, reset the game completely if restart_button.draw(screen): completion_fade = False complete_fade.fade_counter = 0 score = 0 level = 0 key_collected = False start_intro = True bg_scroll = 0 world_data = reset_level() with open(f"level{level}_data.csv", newline="") as csvfile: reader = csv.reader(csvfile, delimiter=",") for x, row in enumerate(reader): for y, tile in enumerate(row): world_data[x][y] = int(tile) world = World() player, health_bar = world.process_data(world_data) # Player actions and checking if the level is complete if player.alive: if shoot: player.shoot() elif grenade and grenade_thrown == False and player.grenades > 0: grenade = Grenade(player.rect.centerx + (0.5 * player.rect.size[0] * player.direction),\ player.rect.top, player.direction) grenade_group.add(grenade) grenade_thrown = True grenade_throw_time = pygame.time.get_ticks() player.grenades -= 1 if player.in_air: player.update_action(2) elif moving_left or moving_right: player.update_action(1) else: player.update_action(0) screen_scroll, level_complete = player.move(moving_left, moving_right) bg_scroll -= screen_scroll if level_complete: if level == MAX_LEVELS: # Checking if game is complete world_data = reset_level() completion_fade = True level += 1 else: # If game is not complete, proceed to next level level += 1 start_intro = True score += 100 high_score_check(score) key_collected = False bg_scroll = 0 world_data = reset_level() with open(f"level{level}_data.csv", newline="") as csvfile: reader = csv.reader(csvfile, delimiter=",") for x, row in enumerate(reader): for y, tile in enumerate(row): world_data[x][y] = int(tile) world = World() player, health_bar = world.process_data(world_data) else: # The player is dead screen_scroll = 0 # Run the death screen fade if death_fade.fade(): # If restart button is clicked, reset the level and take 50 score away if restart_button.draw(screen): death_fade.fade_counter = 0 score -= 50 key_collected = False start_intro = True bg_scroll = 0 world_data = reset_level() with open(f"level{level}_data.csv", newline="") as csvfile: reader = csv.reader(csvfile, delimiter=",") for x, row in enumerate(reader): for y, tile in enumerate(row): world_data[x][y] = int(tile) world = World() player, health_bar = world.process_data(world_data) # Getting all the events for event in pygame.event.get(): if event.type == pygame.QUIT: # Game is quit run = False if event.type == pygame.MOUSEBUTTONDOWN: if event.button == 3: # Player shoots shoot = True if event.type == pygame.MOUSEBUTTONUP: if event.button == 3: # Player stops shooting shoot = False if event.type == pygame.KEYDOWN: if event.key == pygame.K_a: # Player moves left moving_left = True if event.key == pygame.K_d: # Player moves right moving_right = True if event.key == pygame.K_SPACE and player.alive: # Player jumps player.jump = True if event.key == pygame.K_ESCAPE: # Game is quit run = False if event.key == pygame.K_q: # Player throws grenade grenade = True if event.type == pygame.KEYUP: if event.key == pygame.K_a: # Player stops moving left moving_left = False if event.key == pygame.K_d: # Player stops moving right moving_right = False if event.key == pygame.K_q: # Player stops throwing grenade grenade = False if game_time - grenade_throw_time > 1500: grenade_throw_time = 0 grenade_thrown = False pygame.display.update() # Updates the game display # Quit out of the game pygame.quit() sys.exit()