""" ----------------------------------------- Project: CyberQuest Standard: 91896 (2.7) School: Tauranga Boys Collage Auther: Gilbert Jepsen Date: May 2024 Python: 3.11.9 ----------------------------------------- """ # Imports import pygame import sys import pickle import os from os import path # Constants screen_size = (1201, 1000) color = (255, 255, 255) tile_size = 50 gravity = 0.75 player_speed = 5 jump_velocity = -15 FPS = 60 SPRITE_FPS = 30 # Function to load level data def load_level_data(level_name): level_dir = "Gilbert/Code/Versions" 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)) 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, tile_size)) 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)) 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.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 def update(self, level_data): 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.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 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): 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 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 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): if self.vel_x > 0: self.rect.right = sprite.rect.left elif self.vel_x < 0: self.rect.left = sprite.rect.right 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 def update(self, *args): 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 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) 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, *args): 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 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 # 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: screen.blit(Acid_img, (col * tile_size, row * tile_size)) elif tile_id == 102: screen.blit(Acid2_img, (col * tile_size, row * tile_size)) 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 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 running = True level_name = 'Version-Sprite-Data_data' # Load level data level_data = load_level_data(level_name) if level_data: print("Level data loaded successfully:", level_data) else: print("Failed to load level data.") # Main loop running = True sprite_update_time = 0 sprite_update_interval = 1 / SPRITE_FPS while running: delta_time = clock.tick(FPS) / 1000.0 for event in pygame.event.get(): if event.type == pygame.QUIT: running = False screen.fill(color) screen.blit(background_image, (0, 0)) # Draw tiles draw_tiles(level_data) # Update player separately with level_data 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() # Draw all sprites all_sprites.draw(screen) # 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)) # Update the display pygame.display.update() pygame.quit() sys.exit()