# Phase 1: Hollow Knight-style Pygame Game with Wall Climb, Gliding, Soul Powers, Hazards, Themed Rooms, Shrines, NPCs, Menus import pygame import sys import random pygame.init() WIDTH, HEIGHT = 800, 600 screen = pygame.display.set_mode((WIDTH, HEIGHT)) clock = pygame.time.Clock() FONT = pygame.font.SysFont(None, 28) WHITE = (255, 255, 255) BLACK = (0, 0, 0) BLUE = (50, 100, 200) RED = (200, 50, 50) SOUL_BLUE = (0, 100, 255) GRAY = (100, 100, 100) GREEN = (0, 255, 0) GRAVITY = 0.5 GROUND_Y = 550 # Game states MENU, SETTINGS, GAME = "menu", "settings", "game" game_state = MENU class Button: def __init__(self, text, x, y, callback): self.text = FONT.render(text, True, WHITE) self.rect = self.text.get_rect(center=(x, y)) self.callback = callback def draw(self): pygame.draw.rect(screen, BLACK, self.rect.inflate(20, 10)) screen.blit(self.text, self.rect) def handle_event(self, event): if event.type == pygame.MOUSEBUTTONDOWN and self.rect.collidepoint(event.pos): self.callback() class Player: def __init__(self): self.rect = pygame.Rect(100, GROUND_Y - 60, 40, 60) self.vel = [0, 0] self.health = 5 self.soul = 100 self.on_ground = False self.can_double_jump = True self.facing = 1 self.wall_climbing = False self.gliding = False def move(self, keys, walls): self.vel[0] = 0 if keys[pygame.K_LEFT]: self.vel[0] = -5 self.facing = -1 if keys[pygame.K_RIGHT]: self.vel[0] = 5 self.facing = 1 if keys[pygame.K_UP]: if self.on_ground: self.vel[1] = -10 self.can_double_jump = True elif self.can_double_jump: self.vel[1] = -10 self.can_double_jump = False elif self.wall_climbing: self.vel[1] = -10 self.wall_climbing = False for wall in walls: if self.rect.colliderect(wall) and keys[pygame.K_UP]: self.wall_climbing = True self.vel[1] = -3 if keys[pygame.K_s]: self.gliding = True else: self.gliding = False self.vel[1] += GRAVITY if self.gliding: self.vel[1] = min(self.vel[1], 1) self.rect.x += self.vel[0] self.rect.y += self.vel[1] def collide(self, platforms): self.on_ground = False for plat in platforms: if self.rect.colliderect(plat): if self.vel[1] >= 0: self.rect.bottom = plat.top self.vel[1] = 0 self.on_ground = True def draw(self): pygame.draw.rect(screen, BLUE, self.rect) if self.gliding: pygame.draw.circle(screen, SOUL_BLUE, self.rect.center, 5) class Room: def __init__(self, bg_color, has_shrine=False, has_npc=False, hazards=None): self.bg_color = bg_color self.platforms = [ pygame.Rect(0, GROUND_Y, WIDTH, 50), pygame.Rect(random.randint(100, 600), 450, 100, 20), pygame.Rect(random.randint(100, 600), 300, 100, 20), ] self.walls = [pygame.Rect(random.randint(50, 750), 200, 20, 200)] self.hazards = hazards or [pygame.Rect(random.randint(100, 700), GROUND_Y - 20, 40, 20)] self.has_shrine = has_shrine self.has_npc = has_npc def draw(self): screen.fill(self.bg_color) for plat in self.platforms: pygame.draw.rect(screen, BLACK, plat) for wall in self.walls: pygame.draw.rect(screen, GRAY, wall) for hz in self.hazards: pygame.draw.rect(screen, RED, hz) if self.has_shrine: pygame.draw.rect(screen, SOUL_BLUE, (700, 500, 40, 40)) if self.has_npc: pygame.draw.rect(screen, GREEN, (100, 500, 40, 60)) player = Player() rooms = [ Room((200, 220, 255), has_npc=True), Room((180, 180, 180)), Room((100, 100, 255), has_shrine=True) ] current_room = 0 # Menu buttons start_button = Button("Start Game", WIDTH // 2, HEIGHT // 2 - 40, lambda: start_game()) settings_button = Button("Settings", WIDTH // 2, HEIGHT // 2 + 20, lambda: set_state(SETTINGS)) def start_game(): global game_state game_state = GAME def set_state(state): global game_state game_state = state def draw_menu(): screen.fill((30, 30, 30)) start_button.draw() settings_button.draw() def draw_settings(): screen.fill((50, 50, 50)) msg = FONT.render("Settings - press ESC to return", True, WHITE) screen.blit(msg, (WIDTH // 2 - msg.get_width() // 2, HEIGHT // 2)) while True: dt = clock.tick(60) keys = pygame.key.get_pressed() for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() if game_state == MENU: start_button.handle_event(event) settings_button.handle_event(event) if game_state == SETTINGS and event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE: game_state = MENU if game_state == MENU: draw_menu() elif game_state == SETTINGS: draw_settings() elif game_state == GAME: room = rooms[current_room] room.draw() player.move(keys, room.walls) player.collide(room.platforms) for hz in room.hazards: if player.rect.colliderect(hz): player.health -= 1 player.rect.x -= 30 if room.has_shrine and player.rect.colliderect(pygame.Rect(700, 500, 40, 40)): player.soul = 100 player.draw() pygame.draw.rect(screen, RED, (10, 10, player.health * 20, 20)) pygame.draw.rect(screen, SOUL_BLUE, (10, 40, player.soul, 10)) if player.rect.right > WIDTH: current_room = (current_room + 1) % len(rooms) player.rect.left = 0 if player.rect.left < 0: current_room = (current_room - 1) % len(rooms) player.rect.right = WIDTH pygame.display.flip()