class Game: SPLASH = 0 START = 1 PLAYING = 2 PAUSED = 3 LEVEL_COMPLETED = 4 GAME_OVER = 5 VICTORY = 6 def __init__(self): self.window = pygame.display.set_mode( [constants.WIDTH, constants.HEIGHT]) pygame.display.set_caption(constants.TITLE) self.clock = pygame.time.Clock() self.done = False self.reset() def start(self): self.level = Level(constants.LEVELS[self.current_level]) self.level.reset() self.hero.respawn(self.level) def advance(self): self.current_level += 1 self.start() self.stage = Game.START def reset(self): self.hero = Character(hero_images) self.current_level = 0 self.start() self.stage = Game.SPLASH def display_splash(self, surface): line1 = FONT_LG.render(constants.TITLE, True, DARK_BLUE) line2 = FONT_SM.render("Press any key to start.", True, WHITE) x1 = constants.WIDTH / 2 - line1.get_width() / 2 y1 = constants.HEIGHT / 3 - line1.get_height() / 2 x2 = constants.WIDTH / 2 - line2.get_width() / 2 y2 = y1 + line1.get_height() + 16 surface.blit(line1, (x1, y1)) surface.blit(line2, (x2, y2)) def display_message(self, surface, primary_text, secondary_text): line1 = FONT_MD.render(primary_text, 1, WHITE) line2 = FONT_SM.render(secondary_text, 1, WHITE) x1 = constants.WIDTH / 2 - line1.get_width() / 2 y1 = constants.HEIGHT / 3 - line1.get_height() / 2 x2 = constants.WIDTH / 2 - line2.get_width() / 2 y2 = y1 + line1.get_height() + 16 surface.blit(line1, (x1, y1)) surface.blit(line2, (x2, y2)) def display_stats(self, surface): hearts_text = FONT_SM.render("Hearts: " + str(self.hero.hearts), True, WHITE) lives_text = FONT_SM.render("Lives: " + str(self.hero.lives), True, WHITE) score_text = FONT_SM.render("Score: " + str(self.hero.score), True, WHITE) surface.blit(score_text, (constants.WIDTH - score_text.get_width() - 32, 32)) surface.blit(hearts_text, (32, 32)) surface.blit(lives_text, (32, 64)) def process_events(self): for event in pygame.event.get(): if event.type == pygame.QUIT: self.done = True elif event.type == pygame.KEYDOWN: if self.stage == Game.SPLASH or self.stage == Game.START: self.stage = Game.PLAYING play_music() elif self.stage == Game.PLAYING: if event.key == JUMP: self.hero.jump(self.level.blocks) elif self.stage == Game.PAUSED: pass elif self.stage == Game.LEVEL_COMPLETED: self.advance() elif self.stage == Game.VICTORY or self.stage == Game.GAME_OVER: if event.key == pygame.K_r: self.reset() pressed = pygame.key.get_pressed() if self.stage == Game.PLAYING: if pressed[LEFT]: self.hero.move_left() elif pressed[RIGHT]: self.hero.move_right() else: self.hero.stop() def update(self): if self.stage == Game.PLAYING: self.hero.update(self.level) self.level.enemies.update(self.level, self.hero) if self.level.completed: if self.current_level < len(constants.LEVELS) - 1: self.stage = Game.LEVEL_COMPLETED else: self.stage = Game.VICTORY pygame.mixer.music.stop() elif self.hero.lives == 0: self.stage = Game.GAME_OVER pygame.mixer.music.stop() elif self.hero.hearts == 0: self.level.reset() self.hero.respawn(self.level) def calculate_offset(self): x = -1 * self.hero.rect.centerx + constants.WIDTH / 2 if self.hero.rect.centerx < constants.WIDTH / 2: x = 0 elif self.hero.rect.centerx > self.level.width - constants.WIDTH / 2: x = -1 * self.level.width + constants.WIDTH return x, 0 def draw(self): offset_x, offset_y = self.calculate_offset() self.level.active_layer.fill(TRANSPARENT) self.level.active_sprites.draw(self.level.active_layer) if self.hero.invincibility % 3 < 2: self.level.active_layer.blit(self.hero.image, [self.hero.rect.x, self.hero.rect.y]) self.window.blit(self.level.background_layer, [offset_x / 3, offset_y]) self.window.blit(self.level.scenery_layer, [offset_x / 2, offset_y]) self.window.blit(self.level.inactive_layer, [offset_x, offset_y]) self.window.blit(self.level.active_layer, [offset_x, offset_y]) self.display_stats(self.window) if self.stage == Game.SPLASH: self.display_splash(self.window) elif self.stage == Game.START: self.display_message(self.window, "Ready?!!!", "Press any key to start.") elif self.stage == Game.PAUSED: pass elif self.stage == Game.LEVEL_COMPLETED: self.display_message(self.window, "Level Complete", "Press any key to continue.") elif self.stage == Game.VICTORY: self.display_message(self.window, "You Win!", "Press 'R' to restart.") elif self.stage == Game.GAME_OVER: self.display_message(self.window, "Game Over", "Press 'R' to restart.") pygame.display.flip() def loop(self): while not self.done: self.process_events() self.update() self.draw() self.clock.tick(constants.FPS)
class Game: def __init__(self): self.canvas = pygame.display.set_mode((960, 580)) self.initial_position = pygame.Vector2(0, 0) self.hero = None self.current_level = 0 self.clock = None self.blocks = None self.enemies = None self.running = False self.tiles_groups = {} self.tiles_images = {} def load_hero(self): # Load Character hero_scale = SCALE_REFERENCE["character.png"] idle_imgs = load_image_folder(os.path.join(CHARACTER_PATH, 'idle'), scale=hero_scale) base_imgs = load_image(os.path.join(CHARACTER_PATH, 'idle', '0.png'), scale=hero_scale) attack_imgs = [ load_image_folder(os.path.join(CHARACTER_PATH, 'attack', '1'), scale=hero_scale), load_image_folder(os.path.join(CHARACTER_PATH, 'attack', '2'), scale=hero_scale), load_image_folder(os.path.join(CHARACTER_PATH, 'attack', '3'), scale=hero_scale) ] run_imgs = load_image_folder(os.path.join(CHARACTER_PATH, 'run'), scale=hero_scale) jump_imgs = load_image_folder(os.path.join(CHARACTER_PATH, 'jump'), scale=hero_scale) fall_imgs = load_image_folder(os.path.join(CHARACTER_PATH, 'fall'), scale=hero_scale) hero_images = { 'idle': idle_imgs, 'base': base_imgs, 'attack': attack_imgs, 'run': run_imgs, 'jump': jump_imgs, 'fall': fall_imgs } self.hero = Character(self.initial_position, hero_images) def load_level(self): # Load Map TODO will change when the levels are ready tiles_list = [ p for p in os.listdir(TILES_PATH) if p != "character.png" ] self.tiles_images = { tile: load_image(os.path.join(TILES_PATH, tile), scale=SCALE_REFERENCE[tile]) for tile in tiles_list } self.tiles_groups = { tile: pygame.sprite.Group() for tile in tiles_list } with open(os.path.join(LEVELS_PATH, f"{self.current_level}.json"), "r") as json_file: level_data = json.load(json_file) for pos in level_data: for tile in level_data[pos]["tiles"]: if tile["tile"] == "character.png": self.initial_position = pygame.Vector2( level_data[pos]["x"] * 64, level_data[pos]["y"] * 64) continue pos_vec = pygame.Vector2(level_data[pos]["x"] * 64, level_data[pos]["y"] * 64) self.tiles_groups[tile["tile"]].add( OBJECT_REFERENCE[tile["tile"]]( pos_vec, self.tiles_images[tile["tile"]])) def start(self): pygame.init() # clock - FPS self.clock = pygame.time.Clock() # mainloop self.running = True # load main menu self.load_level() self.load_hero() def update(self): while self.running: for event in pygame.event.get(): if event.type == QUIT: self.running = False elif event.type == KEYDOWN: if event.key == K_ESCAPE: self.running = False elif event.key == K_x: self.hero.attack() elif event.key == K_UP: self.hero.jump() pressed = pygame.key.get_pressed() if pressed[K_LEFT]: self.hero.move(left=True) elif pressed[K_RIGHT]: self.hero.move() else: self.hero.stop_moving() self.canvas.fill((0, 0, 0)) for name, group in self.tiles_groups.items(): group.draw(self.canvas) for b_sprite in group.sprites(): b_sprite.draw_line_limit(self.canvas, color=(255, 0, 0)) self.hero.update(self.canvas, group) pygame.display.flip() self.clock.tick(15) pygame.quit() def main(self): self.start() self.update()
# mainloop running = True while running: for event in pygame.event.get(): if event.type == pygame.QUIT: running = False elif event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE: running = False elif event.key == pygame.K_x: char.attack() elif event.key == pygame.K_z: char.jump() pressed = pygame.key.get_pressed() if pressed[pygame.K_LEFT]: char.move(left=True) elif pressed[pygame.K_RIGHT]: char.move() else: char.stop() screen.fill((0, 0, 0)) char.update(screen) pygame.display.flip() clock.tick(15)