#-------------------------------------------------------------------------- # Name : Platformer # Standard: US 91896 2.7 # School: Tauranga Boys College # Author: Keegan Paton # Date: 29/04/2024 # Python: 3.19.13 #-------------------------------------------------------------------------- import pygame from pygame import mixer import os import random import csv import button pygame.mixer.pre_init(44100, -16, 2, 512) mixer.init() pygame.init() SCREEN_WIDTH = 800 SCREEN_HEIGHT = int(SCREEN_WIDTH * 0.8) screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) pygame.display.set_caption('Zombie Shooter') # Set FPS clock = pygame.time.Clock() FPS = 60 # Define game variables GRAVITY = 0.75 SCROLL_THRESH = 200 ROWS = 16 COLS = 150 TILE_SIZE = SCREEN_HEIGHT // ROWS TILE_TYPES = 23 MAX_LEVELS = 3 screen_scroll = 0 bg_scroll = 0 level = 1 start_game = False start_intro = False score = 0 end_score = 0 # Define player action variables moving_left = False moving_right = False shoot = False grenade = False grenade_thrown = False # Load music and sounds pygame.mixer.music.load('audio/music.wav') pygame.mixer.music.set_volume(1) pygame.mixer.music.play(-1, 0.0, 5000) jump_fx = pygame.mixer.Sound('audio/jump.wav') jump_fx.set_volume(1) shot_fx = pygame.mixer.Sound('audio/shot.wav') shot_fx.set_volume(1) grenade_fx = pygame.mixer.Sound('audio/grenade.wav') grenade_fx.set_volume(1) health_fx = pygame.mixer.Sound('audio/health.wav') health_fx.set_volume(1) # Load images # Button images start_image = pygame.image.load('img/start_btn.png').convert_alpha() exit_image = pygame.image.load('img/exit_btn.png').convert_alpha() restart_image = pygame.image.load('img/restart_btn.png').convert_alpha() # Background sky_image = pygame.image.load('img/background/clouds.png').convert_alpha() buildings_image = pygame.image.load('img/background/buildings.png').convert_alpha() # Store tiles in a list image_list = [] for x in range(TILE_TYPES): image = pygame.image.load(f'img/tile/{x}.png') image = pygame.transform.scale(image, (TILE_SIZE, TILE_SIZE)) image_list.append(image) bullet_image = pygame.image.load('img/icons/bullet.png').convert_alpha() knife_image = pygame.image.load('img/icons/knife.png').convert_alpha() grenade_image = pygame.image.load('img/icons/grenade.png').convert_alpha() health_box_image = pygame.image.load('img/icons/health_box.png').convert_alpha() ammo_box_image = pygame.image.load('img/icons/ammo_box.png').convert_alpha() grenade_box_image = pygame.image.load('img/icons/grenade_box.png').convert_alpha() item_boxes = { 'Health' : health_box_image, 'Ammo' : ammo_box_image, 'Grenade' : grenade_box_image } # Define colours BG = (255, 165, 0) RED = (255, 0, 0) WHITE = (255, 255, 255) GREEN = (0, 255, 0) BLACK = (0, 0, 0) PINK = (235, 65, 54) # Define font font = pygame.font.SysFont('Verdana', 30) font_score = pygame.font.SysFont('Verdana', 25) def draw_text(text, font, text_col, x, y): image = font.render(text, True, text_col) screen.blit(image, (x, y)) def draw_bg(): width = sky_image.get_width() for x in range(4): screen.blit(sky_image, ((x * width) - bg_scroll * 0.5, 0)) # Calculates how many times the buildings image should repeat horizontally num_buildings = (COLS * TILE_SIZE) // buildings_image.get_width() + 1 for x in range(num_buildings): buildings_x = (x * buildings_image.get_width()) - bg_scroll * 0.6 # Ensures the buildings image is not drawn outside the screen if buildings_x + buildings_image.get_width() >= 0 and buildings_x <= SCREEN_WIDTH: screen.blit(buildings_image, (buildings_x, SCREEN_HEIGHT - buildings_image.get_height() - 20)) # Function to reset level def reset_level(): zombie_group.empty() bullet_group.empty() grenade_group.empty() explosion_group.empty() item_box_group.empty() decoration_group.empty() lava_group.empty() exit_group.empty() coin_group.empty() crowbar_group.empty() # Create empty tile list data = [] for row in range(ROWS): r = [-1] * COLS data.append(r) return data # Creates a class for all game entities class Entities(pygame.sprite.Sprite): def __init__(self, character_type, x, y, scale, speed, ammo, grenades): pygame.sprite.Sprite.__init__(self) self.alive = True self.character_type = character_type self.speed = speed self.ammo = ammo self.start_ammo = ammo self.shoot_cooldown = 0 self.grenades = grenades self.health = 1000 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() # AI variables self.move_counter = 0 self.vision = pygame.Rect(0, 0, 150, 20) self.idling = False self.idling_counter = 0 # Load all images for players animation_types = ['Idle', 'Run', 'Jump', 'Shoot', 'Death'] for animation in animation_types: # Reset temporary list of images temp_list = [] # Count number of files in folder number_of_frames = len(os.listdir(f'img/{self.character_type}/{animation}')) for i in range(number_of_frames): player = pygame.image.load(f'img/{self.character_type}/{animation}/{i}.png').convert_alpha() image = pygame.transform.scale(player, (int(player.get_width() * scale), int(player.get_height() * scale))) temp_list.append(image) 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() # Adjust the size of the rect by a scaling factor scaling_factor = 0.5 self.original_rect = self.rect.copy() self.rect.width = int(self.rect.width * scaling_factor) self.rect.height = int(self.rect.height * scaling_factor) self.rect.center = self.original_rect.center def update(self): self.update_animation() self.check_alive() # Update cooldown if self.shoot_cooldown > 0: self.shoot_cooldown -= 1 def move(self, moving_left, moving_right): # Reset movement variables screen_scroll = 0 dx = 0 dy = 0 # Assign movement variables when moving left or right if moving_left: dx = -self.speed self.flip = True self.direction = -1 if moving_right: dx = self.speed self.flip = False self.direction = 1 # Jump if self.jump and not self.in_air: self.vel_y = -12 self.jump = False self.in_air = True # Add gravity self.vel_y += GRAVITY if self.vel_y > 10: self.vel_y dy += self.vel_y # Check for collision for tile in world.obstacle_list: # Check collision in x direction if tile[1].colliderect(self.rect.x + dx, self.rect.y, self.rect.width, self.rect.height): dx = 0 # If the AI hits a wall make it turn around if self.character_type == 'zombie': self.direction *= -1 self.move_counter = 0 # Check for collision in y direction if tile[1].colliderect(self.rect.x, self.rect.y + dy, self.rect.width, self.rect.height): # Check if below the ground (ie, jumping) if self.vel_y < 0: self.vel_y = 0 dy = tile[1].bottom - self.rect.top # Check if above the ground (ie, falling) elif self.vel_y >= 0: self.vel_y = 0 self.in_air = False dy = tile[1].top - self.rect.bottom # Check for collision with lava if pygame.sprite.spritecollide(self, lava_group, False): self.health = 1000 # Check for collision with exit level_complete = False if pygame.sprite.spritecollide(self, exit_group, False): level_complete = True # Check if fallen off the map if self.rect.bottom > SCREEN_HEIGHT: self.health = 1000 # Check if going off the edges of the screen if self.character_type == 'player': if self.rect.left + dx < 0 or self.rect.right + dx > SCREEN_WIDTH: dx = 0 # Update rectangle position self.rect.x += dx self.rect.y += dy # Update scroll based on player position if self.character_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 def shoot_animation(self): self.update_action(3) 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) # Reduces ammo self.ammo -= 1 shot_fx.play() def ai(self): if self.alive and player.alive: if self.idling == False and random.randint(1, 200) == 1: self.update_action(0) # 0 = idle self.idling = True self.idling_counter = 50 # Check if AI is close to player if self.vision.colliderect(player.rect): # Stop running and face the player self.update_action(0) # 0 == idle # Throw knives self.shoot() 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) # 1 = run self.move_counter += 1 # Update AI vision as the enemy moves self.vision.center = (self.rect.centerx + 75 * self.direction, self.rect.centery) 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 # Scroll self.rect.x += screen_scroll def attack(self): knife = Knife(self.rect.centerx + (0.6 * self.rect.size[0] * self.direction), self.rect.centery, self.direction) knife_group.add(knife) def update_animation(self): # Update animation ANIMATION_COOLDOWN = 100 # Update image depending on current frame self.image = self.animation_list[self.action][self.frame_index] # Check if enough time has passed since last update if pygame.time.get_ticks() - self.update_time > ANIMATION_COOLDOWN: self.update_time = pygame.time.get_ticks() self.frame_index += 1 # If the animation runs out reset if self.frame_index >= len(self.animation_list[self.action]): if self.action == 4: self.frame_index = len(self.animation_list[self.action]) - 1 else: self.frame_index = 0 def update_action(self, new_action): # Check if new action is different to last one if new_action != self.action: self.action = new_action # Update the animation settings self.frame_index = 0 self.update_time = pygame.time.get_ticks() def check_alive(self): if self.health <= 0: self.health = 0 self.speed = 0 self.alive = False self.update_action(4) def draw(self): # Calculate offset to center the sprite within the scaled rect offset_x = (self.original_rect.width - self.rect.width) // 2 offset_y = (self.original_rect.height - self.rect.height) // 1 if self.flip: screen.blit(pygame.transform.flip(self.image, self.flip, False), (self.rect.x - offset_x, self.rect.y - offset_y)) else: screen.blit(self.image, (self.rect.x - offset_x, self.rect.y - offset_y)) 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: image = image_list[tile] image_rect = image.get_rect() image_rect.x = x * TILE_SIZE image_rect.y = y * TILE_SIZE tile_data = (image, image_rect) if tile >= 0 and tile <= 8:# Create tiles self.obstacle_list.append(tile_data) elif tile >= 9 and tile <= 10:# Create lava lava = Lava(image, x * TILE_SIZE, y * TILE_SIZE) lava_group.add(lava) elif tile >= 11 and tile <= 14:# Create decorations decoration = Decoration(image, x * TILE_SIZE, y * TILE_SIZE) decoration_group.add(decoration) elif tile == 15:# Create player player = Entities('player', x * TILE_SIZE, y * TILE_SIZE, 0.9, 5, 20, 5) health_bar = HealthBar(10, 10, player.health, player.health) elif tile == 16:# Create enemies zombie = Entities('zombie', x * TILE_SIZE, y * TILE_SIZE, 1, 2, 20, 0) zombie_group.add(zombie) elif tile == 17:# Create ammo box item_box = ItemBox('Ammo', x * TILE_SIZE, y * TILE_SIZE) item_box_group.add(item_box) elif tile == 18:# Create grenade box item_box = ItemBox('Grenade', x * TILE_SIZE, y * TILE_SIZE) item_box_group.add(item_box) elif tile == 19:# Create health box item_box = ItemBox('Health', x * TILE_SIZE, y * TILE_SIZE) item_box_group.add(item_box) elif tile == 20:# Create exit exit = Exit(image, x * TILE_SIZE, y * TILE_SIZE) exit_group.add(exit) elif tile == 21:# Create crowbar crowbar = Crowbar(x * TILE_SIZE, y * TILE_SIZE) crowbar_group.add(crowbar) elif tile == 22:# Create coins coins = Coin(x * TILE_SIZE, y * TILE_SIZE) coin_group.add(coins) return player, health_bar def draw(self): for tile in self.obstacle_list: tile[1][0] += screen_scroll screen.blit(tile[0], tile[1]) # Class for lava class Lava(pygame.sprite.Sprite): def __init__(self, image, x, y): pygame.sprite.Sprite.__init__(self) self.image = image self.rect = self.image.get_rect() self.rect.midtop = (x + TILE_SIZE // 2, y + (TILE_SIZE - self.image.get_height())) def update(self): self.rect.x += screen_scroll # Class for exit class Exit(pygame.sprite.Sprite): def __init__(self, image, x, y): pygame.sprite.Sprite.__init__(self) self.image = image self.rect = self.image.get_rect() self.rect.midtop = (x + TILE_SIZE // 2, y + (TILE_SIZE - self.image.get_height())) def update(self): self.rect.x += screen_scroll class Coin(pygame.sprite.Sprite): def __init__(self, x, y): pygame.sprite.Sprite.__init__(self) self.image = pygame.image.load('img/icons/coin.png') self.image = pygame.transform.scale(image, (TILE_SIZE // 2, TILE_SIZE // 2)) self.rect = self.image.get_rect() self.rect.center = (x, y) def update(self): self.rect.x += screen_scroll class Crowbar(pygame.sprite.Sprite): def __init__(self, x, y): pygame.sprite.Sprite.__init__(self) self.image = pygame.image.load('img/icons/crowbar.png') self.image = pygame.transform.scale(self.image, (70, 60)) self.rect = self.image.get_rect() self.rect.center = (x, y) def update(self): self.rect.x += screen_scroll # Class for decorations class Decoration(pygame.sprite.Sprite): def __init__(self, image, x, y): pygame.sprite.Sprite.__init__(self) self.image = image self.rect = self.image.get_rect() self.rect.midtop = (x + TILE_SIZE // 2, y + (TILE_SIZE - self.image.get_height())) def update(self): self.rect.x += screen_scroll # Class for collectible items 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())) def update(self): # Scroll self.rect.x += screen_scroll # Check if player picks up box if pygame.sprite.collide_rect(self, player): # Check what box it was 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 += 15 elif self.item_type == 'Grenade': player. grenades += 3 # Delete the item boxes self.kill() class HealthBar(): def __init__(self, x, y, health, max_health): self.x = x self.y = y self.health = health self.max_health = max_health def draw(self, health): # Update with new health self.health = health # Calculate health ratio 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 bullets class Bullet(pygame.sprite.Sprite): def __init__(self, x, y, direction): pygame.sprite.Sprite.__init__(self) self.speed = 10 self.image = bullet_image self.rect = self.image.get_rect() self.rect.center = (x, y - 18) self.direction = direction def update(self): # Move the bullet self.rect.x += (self.direction * self.speed) + screen_scroll # Check if bullet has left screen if self.rect.right < 0 or self.rect.left > SCREEN_WIDTH: self.kill() # Check for collision with level for tile in world.obstacle_list: if tile[1].colliderect(self.rect): self.kill() # Check collision with characters if pygame.sprite.spritecollide(player, bullet_group, False): if player.alive: player.health -= 5 self.kill() for zombie in zombie_group: if pygame.sprite.spritecollide(zombie, bullet_group, False): if zombie.alive: zombie.health -= 25 self.kill() # Class for 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_image self.rect = self.image.get_rect() self.rect.center = (x, y) self.width = self.image.get_width() self.height = self.image.get_height() self.direction = direction 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 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 (ie, thrown up) if self.vel_y < 0: self.vel_y = 0 dy = tile[1].bottom - self.rect.top # Check if above the ground (ie, falling) elif self.vel_y >= 0: self.vel_y = 0 dy = tile[1].top - self.rect.bottom # Update grenade position self.rect.x += dx + screen_scroll self.rect.y += dy # Countdown timer for grenades self.timer -= 1 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 nearby entities 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 zombie in zombie_group: if abs(self.rect.centerx - zombie.rect.centerx) < TILE_SIZE * 2 and \ abs(self.rect.centery - zombie.rect.centery) < TILE_SIZE * 2: zombie.health -= 50 # Class for explosions 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').convert_alpha() img = pygame.transform.scale(img, (int(img.get_width() * scale), int(img.get_height() * scale))) 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 def update(self): # Scroll self.rect.x += screen_scroll EXPLOSION_SPEED = 4 # Update explosion animation self.counter += 1 if self.counter >= EXPLOSION_SPEED: self.counter = 0 self.frame_index += 1 # Check if animation is complete so explosion can be deleted if self.frame_index >= len(self.images): self.kill() else: self.image = self.images[self.frame_index] # Class for screen animations class ScreenFade(): def __init__(self, direction, colour, speed): self.direction = direction self.colour = colour self.speed = speed self.fade_counter = 0 def fade(self): fade_complete = False self.fade_counter += self.speed if self.direction == 1: # Whole screen fade 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, 4) death_fade = ScreenFade(2, PINK, 4) # Class for knives class Knife(pygame.sprite.Sprite): def __init__(self, x, y, direction): pygame.sprite.Sprite.__init__(self) self.speed = 10 self.image = knife_image self.rect = self.image.get_rect() self.rect.center = (x, y) self.direction = direction def update(self): # Move the knife self.rect.x += (self.direction * self.speed) # Check if knife has left screen if self.rect.right < 0 or self.rect.left > SCREEN_WIDTH: self.kill() # Create buttons start_button = button.Button(SCREEN_WIDTH // 2 - 130, SCREEN_HEIGHT // 2 - 150, start_image, 1) exit_button = button.Button(SCREEN_WIDTH // 2 - 130, SCREEN_HEIGHT // 2 - 0, exit_image, 1) restart_button = button.Button(SCREEN_WIDTH // 2 - 130, SCREEN_HEIGHT // 2 - 50, restart_image, 1) # Create sprite groups zombie_group = pygame.sprite.Group() bullet_group = pygame.sprite.Group() knife_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() lava_group = pygame.sprite.Group() exit_group = pygame.sprite.Group() coin_group = pygame.sprite.Group() crowbar_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 Editor/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) has_crowbar = False run = True while run: clock.tick(FPS) if start_game == False: # Draw main menu screen.fill(BG) # Add buttons if start_button.draw(screen): start_game = True start_intro = True if exit_button.draw(screen): run = False else: # Draw background draw_bg() # Draw world map world.draw() # Show player health health_bar.draw(player.health) # Show ammo draw_text('AMMO: ', font, WHITE, 10, 35) for x in range(player.ammo): screen.blit(bullet_image, (120 + (x * 10), 53)) # Show grenades draw_text('GRENADES: ', font, WHITE, 10, 65) for x in range(player.grenades): screen.blit(grenade_image, (200 + (x * 15), 80)) # Check if a coin has been collected if pygame.sprite.spritecollide(player, coin_group, True): score += 1 # Coin score/high score counter draw_text('SCORE: ' + str(score), font_score, WHITE, TILE_SIZE - 28, 95) draw_text('HIGH SCORE: ' + str(end_score), font_score, WHITE, TILE_SIZE - 28, 120) # Check if a crowbar has been collected if pygame.sprite.spritecollide(player, crowbar_group, True): has_crowbar = True player.update() player.draw() for zombie in zombie_group: zombie.ai() zombie.update() zombie.draw() # Update and draw groups bullet_group.update() grenade_group.update() explosion_group.update() item_box_group.update() decoration_group.update() lava_group.update() exit_group.update() coin_group.update() crowbar_group.update() bullet_group.draw(screen) grenade_group.draw(screen) explosion_group.draw(screen) item_box_group.draw(screen) decoration_group.draw(screen) lava_group.draw(screen) exit_group.draw(screen) coin_group.draw(screen) crowbar_group.draw(screen) # Show intro if start_intro == True: if intro_fade.fade(): start_intro = False intro_fade.fade_counter = 0 # Update player actions if player.alive: # Shoot bullets if shoot: player.update_action(3) # 3 = shoot player.shoot() # Throw grenades elif grenade and not grenade_thrown 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) # Reduce grenades player.grenades -= 1 grenade_thrown = True elif player.in_air: player.update_action(2) # 2 = jump elif moving_left or moving_right: player.update_action(1) # 1 = run else: player.update_action(0) # 0 = idle screen_scroll, level_complete = player.move(moving_left, moving_right) bg_scroll -= screen_scroll # Check if player has completed the level if level_complete: if has_crowbar: start_intro = True level += 1 bg_scroll = 0 world_data = reset_level() end_score = score if level <= MAX_LEVELS: # Load in level data and create world with open(f'Level Editor/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) has_crowbar = False else: if level > 3: run = False else: if level > 3: run = False screen_scroll = 0 if death_fade.fade(): if restart_button.draw(screen): death_fade.fade_counter = 0 start_intro = True bg_scroll = 0 world_data = reset_level() score = end_score has_crowbar = False # Load in level data and create world with open(f'Level Editor/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) for event in pygame.event.get(): # Quit game if event.type == pygame.QUIT: run = False # Keyboard/Mouse presses if event.type == pygame.KEYDOWN: if event.key == pygame.K_a: moving_left = True if event.key == pygame.K_d: moving_right = True if event.key == pygame.K_w: grenade = True if event.key == pygame.K_SPACE and player.alive: player.jump = True jump_fx.play() if event.key == pygame.K_ESCAPE: run = False if event.type == pygame.MOUSEBUTTONDOWN: if event.button == 3: # Check if the player has bullets remaining if player.ammo > 0: shoot = True player.shoot_animation() # Keyboard/Mouse button released if event.type == pygame.KEYUP: if event.key == pygame.K_a: moving_left = False if event.key == pygame.K_d: moving_right = False if event.key == pygame.K_w: grenade = False grenade_thrown = False if event.type == pygame.MOUSEBUTTONUP: if event.button == 3: shoot = False pygame.display.update() pygame.quit()