diff --git a/Test.py b/Test.py deleted file mode 100644 index 5eb902c..0000000 --- a/Test.py +++ /dev/null @@ -1,223 +0,0 @@ -import pygame -from pygame.locals import * -import sys -import os -import time - -pygame.init() - -vec = pygame.math.Vector2 -HEIGHT = 450 -WIDTH = 400 -ACC = 0.5 -FRIC = -0.12 -FPS = 60 -FramePerSec = pygame.time.Clock() - -displaysurface = pygame.display.set_mode((0, 0), pygame.FULLSCREEN) -WIDTH, HEIGHT = displaysurface.get_size() -pygame.display.set_caption("Project Sanic") - -# Initialize font for FPS counter -try: - font = pygame.font.SysFont("Arial", 24) -except: - font = pygame.font.Font(None, 24) # Default font if Arial is not available - - -class Player(pygame.sprite.Sprite): - def __init__(self): - super().__init__() - - # Animation variables - self.animation_frames = [] - self.current_frame = 0 - self.animation_speed = 0.1 - self.last_update = time.time() - self.static_image = None - self.moving = False # Track if player is moving - self.dashing = False - - # Load static image and animation frames - self.load_images() - - # Set initial surface - if self.static_image: - self.surf = self.static_image - elif self.animation_frames: - self.surf = self.animation_frames[0] - else: - # Fallback to a colored rectangle - self.surf = pygame.Surface((30, 30)) - self.surf.fill((128, 255, 40)) - - self.rect = self.surf.get_rect() - self.pos = vec((10, 385)) - self.vel = vec(0, 0) - self.acc = vec(0, 0) - self.jumping = False - - def load_images(self): - try: - # Load static image - if os.path.isfile("assets/player/Sanic Base.png"): - self.static_image = pygame.image.load("assets/player/Sanic Base.png").convert_alpha() - self.static_image = pygame.transform.scale(self.static_image, (160, 160)) - - # Load animation sprite sheet - if os.path.isfile("assets/player/Sanic Annimate.png"): - sprite_sheet = pygame.image.load("assets/player/Sanic Annimate.png").convert_alpha() - - # Extract the 4 frames - frame_width = sprite_sheet.get_height() - - for i in range(4): - # Cut out a region of the sprite sheet - frame = sprite_sheet.subsurface((i * 2207, 0, frame_width, frame_width)) - # Resize the frame - frame = pygame.transform.scale(frame, (160, 160)) - self.animation_frames.append(frame) - - except Exception as e: - print(f"Error loading player images: {e}") - - def update_animation(self): - if self.moving: - # Only animate when moving - if self.animation_frames and time.time() - self.last_update > self.animation_speed: - self.current_frame = (self.current_frame + 1) % len(self.animation_frames) - self.surf = self.animation_frames[self.current_frame] - self.last_update = time.time() - else: - # Use static image when not moving - if self.static_image: - self.surf = self.static_image - - def dash(self, acc): - self.acc.x = 5 * acc - if acc<0: - self.acc.y = 5 * acc - else: - self.acc.y = -5 * acc - - def move(self): - self.acc = vec(0, 1) # Gravity - - # Reset moving flag - self.moving = False - - pressed_keys = pygame.key.get_pressed() - if pressed_keys[K_q]: - self.acc.x = -ACC - self.moving = True # Set moving to True when moving left - if pressed_keys[K_a] : - self.dash(-ACC) - - if pressed_keys[K_d]: - self.acc.x = ACC - self.moving = True # Set moving to True when moving right - if pressed_keys[K_a] : - self.dash(ACC) - - # Also consider the player moving if they have significant horizontal velocity - if abs(self.vel.x) > 0.5: - self.moving = True - - # Jumping logic - if pressed_keys[K_SPACE] and not self.jumping: - self.vel.y = -30 - self.jumping = True - - # Apply friction - self.acc.y += self.vel.y * FRIC - self.acc.x += self.vel.x * FRIC - self.vel += self.acc - self.pos += self.vel + 0.5 * self.acc - - # Prevent the player from moving off-screen horizontally - if self.pos.x > WIDTH - self.rect.width / 2: - self.pos.x = WIDTH - self.rect.width / 2 - self.vel.x = 0 - if self.pos.x < self.rect.width / 2: - self.pos.x = self.rect.width / 2 - self.vel.x = 0 - - self.rect.midbottom = self.pos - - # Update animation frame - self.update_animation() - - def update(self): - hits = pygame.sprite.spritecollide(self, platforms, False) - if hits: - if self.vel.y > 0: - self.pos.y = hits[0].rect.top - self.vel.y = 0 - self.jumping = False - - -class platform(pygame.sprite.Sprite): - def __init__(self, Long, R, G, B): - super().__init__() - self.surf = pygame.Surface((Long, 20)) - self.surf.fill((R, G, B)) - self.rect = self.surf.get_rect(center=(WIDTH / 2, HEIGHT - 10)) - - -PT1 = platform(WIDTH, 255, 0, 0) - -a = 200 -PT2 = platform(a, 0, 0, 255) -PT2.rect.y=(HEIGHT-50) - -P1 = Player() - -platforms = pygame.sprite.Group() -platforms.add(PT1) -platforms.add(PT2) - -all_sprites = pygame.sprite.Group() -all_sprites.add(PT1) -all_sprites.add(PT2) -all_sprites.add(P1) - -while True: - for event in pygame.event.get(): - if event.type == QUIT: - pygame.quit() - sys.exit() - elif event.type == KEYDOWN: - if event.key == K_ESCAPE: - pygame.quit() - sys.exit() - - displaysurface.fill((0, 0, 0)) - - P1.move() - P1.update() - for entity in all_sprites: - displaysurface.blit(entity.surf, entity.rect) - -# Gestion déplacement plateforme PT2 - if PT2.rect.x < 50: - a = 1 - if PT2.rect.x > 1000: - a=-1 - PT2.rect.x += 2*a - -# Le rectangle P1 reste sur la plateforme mouvante - if P1.rect.colliderect(PT2.rect) and P1.pos.y == PT2.rect.y: - P1.pos.x += 2 * a - - - # Display FPS - fps = int(FramePerSec.get_fps()) - fps_text = font.render(f"FPS: {fps}", True, (255, 255, 255)) - displaysurface.blit(fps_text, (10, 10)) - - # Display player coordinates - pos_text = font.render(f"X: {int(P1.pos.x)}, Y: {int(P1.pos.y)}", True, (255, 255, 255)) - displaysurface.blit(pos_text, (10, 40)) - - pygame.display.update() - FramePerSec.tick(FPS) \ No newline at end of file diff --git a/assets/player/dead.jpg b/assets/player/dead.jpg new file mode 100644 index 0000000..2be935e Binary files /dev/null and b/assets/player/dead.jpg differ diff --git a/main.py b/main.py index f4b13b3..7c74ace 100644 --- a/main.py +++ b/main.py @@ -1,361 +1,8 @@ -import re - -import pygame -import sys -from pygame.locals import * -import numpy as np - -from src.Database.LevelDB import LevelDB -from src.Entity.Enemy import Enemy -from src.Menu.LevelSelectMenu import LevelSelectMenu -from src.game import ( - initialize_game, - reset_game_with_checkpoint, - clear_checkpoint_database, -) -from src.constant import GameResources -from src.Menu.Menu import Menu -from src.Menu.Leaderboard import Leaderboard -from src.Camera import Camera -from src.Database.CheckpointDB import CheckpointDB -from src.Map.Editor.LevelEditor import LevelEditor -from src.Menu.LevelEditorSelectionMenu import LevelEditorSelectionMenu +from src.handler import handler def main(): - # Initialize Pygame and game resources - game_resources = GameResources() - displaysurface = game_resources.displaysurface - FramePerSec = game_resources.FramePerSec - font = game_resources.font - FPS = game_resources.FPS - WIDTH = game_resources.WIDTH - HEIGHT = game_resources.HEIGHT - ORIGINAL_WIDTH = game_resources.ORIGINAL_WIDTH - ORIGINAL_HEIGHT = game_resources.ORIGINAL_HEIGHT - fullscreen = game_resources.fullscreen - - # Add camera initialization - camera = Camera(WIDTH, HEIGHT, game_resources) - - # Game states - MENU = 0 - PLAYING = 1 - INFINITE = 2 - LEADERBOARD = 3 - - # Initialize game state and objects - current_state = MENU - main_menu = Menu(game_resources) - level_select_menu = None - level_file = "map/levels/1.json" - current_menu = "main" - leaderboard = Leaderboard(WIDTH, HEIGHT, font) - - clear_checkpoint_database() - projectiles = pygame.sprite.Group() - - pygame.joystick.quit() - pygame.joystick.init() - joysticks = [] - - try: - for i in range(pygame.joystick.get_count()): - joystick = pygame.joystick.Joystick(i) - joystick.init() - joysticks.append(joystick) - except pygame.error: - print("Error while initializing joysticks") - - # Main game loop - running = True - while running: - try: - events = [] - try: - events = pygame.event.get() - except Exception as e: - print(f"Error while getting events: {e}") - pygame.joystick.quit() - pygame.joystick.init() - continue - - for event in events: - if event.type == QUIT: - running = False - pygame.quit() - sys.exit() - elif event.type == KEYDOWN: - if event.key == K_ESCAPE: - if current_state in [PLAYING, INFINITE]: - current_state = MENU - else: - pygame.quit() - sys.exit() - elif event.key == K_F11: - fullscreen = not fullscreen - if fullscreen: - # Store current window size before going fullscreen - ORIGINAL_WIDTH, ORIGINAL_HEIGHT = displaysurface.get_size() - displaysurface = pygame.display.set_mode( - (0, 0), pygame.FULLSCREEN - ) - else: - # Return to windowed mode with previous size - displaysurface = pygame.display.set_mode( - (ORIGINAL_WIDTH, ORIGINAL_HEIGHT), pygame.RESIZABLE - ) - elif ( - event.type == VIDEORESIZE - ): # Fixed indentation - moved out of K_F11 condition - if not fullscreen: - displaysurface = pygame.display.set_mode( - (event.w, event.h), pygame.RESIZABLE - ) - # Update window dimensions - ORIGINAL_WIDTH, ORIGINAL_HEIGHT = event.w, event.h - elif event.type == USEREVENT: - if event.action == "player_death": - db = CheckpointDB() - checkpoint_pos = db.get_checkpoint(level_file) - - if checkpoint_pos: - # Respawn player at checkpoint - P1, platforms, all_sprites, background, checkpoints = ( - reset_game_with_checkpoint(level_file, game_resources) - ) - projectiles.empty() - else: - # No checkpoint found, return to menu - current_state = MENU - if event.dict.get("action") == "create_projectile": - projectile = event.dict.get("projectile") - projectiles.add(projectile) - - # Handle menu events - if current_state == MENU: - if current_menu == "main": - action = main_menu.handle_event(event) - if action == "level_select": - level_select_menu = LevelSelectMenu(game_resources) - current_menu = "level_select" - elif action == "infinite": - current_state = INFINITE - elif action == "leaderboard": - current_state = LEADERBOARD - elif action == "quit": - pygame.quit() - sys.exit() - elif current_menu == "level_select": - action = level_select_menu.handle_event(event) - if action == "back_to_main": - current_menu = "main" - elif ( - isinstance(action, dict) - and action.get("action") == "select_level" - ): - level_file = action.get("level_file") - print(level_file) - ( - P1, - PT1, - platforms, - all_sprites, - background, - checkpoints, - exits, - ) = initialize_game(game_resources, level_file) - projectiles.empty() - current_state = PLAYING - elif action == "open_editor": - editor_select_menu = LevelEditorSelectionMenu( - game_resources - ) - current_state = "editor_select" - - # Handle leaderboard events - elif current_state == LEADERBOARD: - action = leaderboard.handle_event(event) - if action == "menu": - current_state = MENU - - elif current_state == "editor_select": - action = editor_select_menu.handle_event(event) - if action == "back_to_levels": - current_state = MENU - current_menu = "level_select" - elif isinstance(action, dict): - if action["action"] == "edit_level": - level_editor = LevelEditor( - game_resources, action["level_file"] - ) - current_state = "level_editor" - elif action["action"] == "new_level": - level_editor = LevelEditor(game_resources) - current_state = "level_editor" - - elif current_state == "level_editor": - result = level_editor.handle_event(event) - if result == "back_to_levels": - current_state = "editor_select" - except Exception as e: - print(f"Error while processing events: {e}") - continue - - # Clear screen - displaysurface.fill((0, 0, 0)) - - # Draw appropriate screen based on state - if current_state == MENU: - if current_menu == "main": - main_menu.draw(displaysurface) - elif current_menu == "level_select": - level_select_menu.draw(displaysurface) - elif current_state == "editor_select": - editor_select_menu.draw(displaysurface) - elif current_state == "level_editor": - level_editor.draw(displaysurface) - elif current_state == LEADERBOARD: - leaderboard.draw(displaysurface) - - elif current_state == PLAYING: - # Regular game code - P1.move() - P1.update() - P1.attack() - - # Update camera to follow player - camera.update(P1) - - # Clear screen - displaysurface.fill((0, 0, 0)) - - for platform in platforms: - if platform.is_moving and platform.movement_type == "linear": - if ( - platform.movement_points[0]["x"] - - platform.movement_points[1]["x"] - == 0 - ): - dir = 0 - else: - dir = 1 - if ( - P1.rect.colliderect(platform.rect) - and P1.pos.y == platform.rect.y - ): - P1.pos.x += platform.movement_speed * platform.coeff - - platform.move_linear( - dir, - platform.movement_points, - platform.movement_speed, - platform.wait_time, - platform.coeff, - ) - - if platform.is_moving and platform.movement_type == "circular": - if ( - P1.rect.colliderect(platform.rect) - and P1.pos.y == platform.rect.y - and platform.clockwise - ): - P1.pos.x = P1.pos.x + platform.radius * np.cos(platform.angle) - P1.pos.y = P1.pos.y + platform.radius * np.sin(platform.angle) - - if ( - P1.rect.colliderect(platform.rect) - and P1.pos.y == platform.rect.y - and not platform.clockwise - ): - P1.pos.x = P1.pos.x + platform.radius * np.cos(platform.angle) - P1.pos.y = P1.pos.y + platform.radius * np.sin(-platform.angle) - - platform.move_circular( - platform.center, - platform.angular_speed, - platform.radius, - platform.clockwise, - ) - - if background: - parallax_factor = 0.3 - bg_x = camera.camera.x * parallax_factor - bg_y = camera.camera.y * parallax_factor - displaysurface.blit(background, (bg_x, bg_y)) - - # Draw all sprites with camera offset applied - for entity in all_sprites: - # Calculate position adjusted for camera - camera_adjusted_rect = entity.rect.copy() - camera_adjusted_rect.x += camera.camera.x - camera_adjusted_rect.y += camera.camera.y - displaysurface.blit(entity.surf, camera_adjusted_rect) - - for sprite in all_sprites: - if isinstance(sprite, Enemy): - sprite.update(P1) - else: - sprite.update() - - projectiles.update(WIDTH, HEIGHT, P1, camera) - - for projectile in projectiles: - # Calculate position adjusted for camera (comme pour les autres sprites) - camera_adjusted_rect = projectile.rect.copy() - camera_adjusted_rect.x += camera.camera.x - camera_adjusted_rect.y += camera.camera.y - displaysurface.blit(projectile.surf, camera_adjusted_rect) - - if checkpoints is not None: - checkpoints_hit = pygame.sprite.spritecollide(P1, checkpoints, False) - else: - checkpoints_hit = [] - for checkpoint in checkpoints_hit: - checkpoint.activate() - - exits_hit = pygame.sprite.spritecollide(P1, exits, False) if exits else [] - for exit in exits_hit: - current_level_match = re.search(r"(\d+)\.json$", level_file) - if current_level_match: - current_level = int(current_level_match.group(1)) - next_level = current_level + 1 - - # Unlock next level - db = LevelDB() - db.unlock_level(next_level) - db.close() - - # Return to level select menu - current_state = MENU - current_menu = "level_select" - level_select_menu = LevelSelectMenu(game_resources) - - # Display FPS and coordinates (fixed position UI elements) - fps = int(FramePerSec.get_fps()) - fps_text = font.render(f"FPS: {fps}", True, (255, 255, 255)) - displaysurface.blit(fps_text, (10, 10)) - - P1.draw_dash_cooldown_bar(displaysurface) - - pos_text = font.render( - f"X: {int(P1.pos.x)}, Y: {int(P1.pos.y)}", True, (255, 255, 255) - ) - displaysurface.blit(pos_text, (10, 40)) - - P1.draw_dash_cooldown_bar(displaysurface) - P1.draw_lives(displaysurface) - - elif current_state == INFINITE: - # Placeholder for infinite mode - text = font.render("Mode Infini - À implémenter", True, (255, 255, 255)) - displaysurface.blit(text, (WIDTH // 2 - text.get_width() // 2, HEIGHT // 2)) - - elif current_state == LEADERBOARD: - leaderboard.draw(displaysurface) - - pygame.display.update() - FramePerSec.tick(FPS) + handler() if __name__ == "__main__": diff --git a/map/levels/1.json b/map/levels/1.json index a6731e0..b982e6e 100644 --- a/map/levels/1.json +++ b/map/levels/1.json @@ -4,8 +4,7 @@ "height": 800, "background": "assets/map/background/forest_bg.jpg", "gravity": 1.0, - - "ground": [ + "platforms": [ { "id": "main_ground", "x": -1000, @@ -14,14 +13,6 @@ "height": 200, "texture": "assets/map/platform/grass_texture.jpg" }, - { - "id": "pit", - "x": 800, - "y": 780, - "width": 200, - "height": 20, - "is_hole": true - }, { "id": "main_ground_2", "x": 1000, @@ -29,10 +20,7 @@ "width": 1800, "height": 200, "texture": "assets/map/platform/grass_texture.jpg" - } - ], - - "platforms": [ + }, { "id": "platform1", "x": 300, diff --git a/map/levels/2.json b/map/levels/2.json index c8122ab..0e069ab 100644 --- a/map/levels/2.json +++ b/map/levels/2.json @@ -4,8 +4,7 @@ "height": 800, "background": "assets/map/background/forest_bg.jpg", "gravity": 1.0, - - "ground": [ + "platforms": [ { "id": "main_ground", "x": -1000, @@ -14,14 +13,6 @@ "height": 200, "texture": "assets/map/platform/grass_texture.jpg" }, - { - "id": "pit", - "x": 800, - "y": 780, - "width": 200, - "height": 20, - "is_hole": true - }, { "id": "main_ground_2", "x": 1000, @@ -29,10 +20,7 @@ "width": 1800, "height": 200, "texture": "assets/map/platform/grass_texture.jpg" - } - ], - - "platforms": [ + }, { "id": "platform1", "x": 300, diff --git a/map/levels/3.json b/map/levels/3.json index 205816e..a8145d4 100644 --- a/map/levels/3.json +++ b/map/levels/3.json @@ -4,21 +4,11 @@ "height": 800, "background": "assets/map/background/forest_bg.jpg", "gravity": 1.0, - "ground": [ - { - "id": "main_ground", - "x": -1000, - "y": 780, - "width": 1800, - "height": 200, - "texture": "assets/map/platform/grass_texture.jpg" - } - ], "platforms": [ { "id": "platform1", "x": 220, - "y": 280, + "y": 160, "width": 540, "height": 160, "texture": "assets/map/platform/grass_texture.jpg", @@ -27,46 +17,31 @@ { "id": "platform2", "x": 320, - "y": 140, + "y": 120, "width": 200, "height": 20, "texture": "assets/map/platform/grass_texture.jpg", - "is_moving": true, - "movement": { - "type": "linear", - "points": [ - { - "x": 320, - "y": 140 - }, - { - "x": 420, - "y": 140 - } - ], - "speed": 2, - "wait_time": 1.0 - } + "is_moving": false } ], "enemies": [ { "id": "enemy1", "type": "walker", - "x": 380, - "y": 220, + "x": 340, + "y": 180, "health": 1, "damage": 1, "sprite_sheet": "assets/map/enemy/walker_enemy.png", "behavior": "patrol", "patrol_points": [ { - "x": 280, - "y": 220 + "x": 240, + "y": 180 }, { - "x": 480, - "y": 220 + "x": 440, + "y": 180 } ], "speed": 1.5 @@ -75,8 +50,8 @@ "checkpoints": [], "exits": [ { - "x": 680, - "y": 200, + "x": 630, + "y": 40, "width": 50, "height": 80, "next_level": "map/levels/1.json", diff --git a/src/Map/Editor/LevelEditor.py b/src/Map/Editor/LevelEditor.py index 6d75157..ab60b5e 100644 --- a/src/Map/Editor/LevelEditor.py +++ b/src/Map/Editor/LevelEditor.py @@ -216,16 +216,6 @@ class LevelEditor: "height": 800, "background": "assets/map/background/forest_bg.jpg", "gravity": 1.0, - "ground": [ - { - "id": "main_ground", - "x": -1000, - "y": 780, - "width": 1800, - "height": 200, - "texture": "assets/map/platform/grass_texture.jpg", - } - ], "platforms": [], "enemies": [], "checkpoints": [], diff --git a/src/Map/parser.py b/src/Map/parser.py index 1a99019..80292b9 100644 --- a/src/Map/parser.py +++ b/src/Map/parser.py @@ -56,21 +56,6 @@ class MapParser: self.checkpoints.empty() self.exits.empty() - # Create ground elements - if "ground" in map_data: - for ground in map_data["ground"]: - if not ground.get("is_hole", False): - platform = Platform( - ground["width"], - ground["height"], - ground["x"] + ground["width"] / 2, - ground["y"], - (255, 0, 0), - ground["texture"], - ) - self.platforms.add(platform) - self.all_sprites.add(platform) - # Create enemies if "enemies" in map_data: # Create enemies diff --git a/src/handler.py b/src/handler.py new file mode 100644 index 0000000..2810879 --- /dev/null +++ b/src/handler.py @@ -0,0 +1,385 @@ +import re + +import pygame +import sys +from pygame.locals import * +import numpy as np + +from src.Database.LevelDB import LevelDB +from src.Entity.Enemy import Enemy +from src.Menu.LevelSelectMenu import LevelSelectMenu +from src.game import ( + initialize_game, + reset_game_with_checkpoint, + clear_checkpoint_database, +) +from src.constant import GameResources +from src.Menu.Menu import Menu +from src.Menu.Leaderboard import Leaderboard +from src.Camera import Camera +from src.Database.CheckpointDB import CheckpointDB +from src.Map.Editor.LevelEditor import LevelEditor +from src.Menu.LevelEditorSelectionMenu import LevelEditorSelectionMenu + + +def handler(): + # Initialize Pygame and game resources + game_resources = GameResources() + displaysurface = game_resources.displaysurface + FramePerSec = game_resources.FramePerSec + font = game_resources.font + FPS = game_resources.FPS + WIDTH = game_resources.WIDTH + HEIGHT = game_resources.HEIGHT + ORIGINAL_WIDTH = game_resources.ORIGINAL_WIDTH + ORIGINAL_HEIGHT = game_resources.ORIGINAL_HEIGHT + fullscreen = game_resources.fullscreen + + # Add camera initialization + camera = Camera(WIDTH, HEIGHT, game_resources) + + # Game states + MENU = 0 + PLAYING = 1 + INFINITE = 2 + LEADERBOARD = 3 + DEATH_SCREEN = 4 + + # Initialize death screen + death_timer = 0 + death_display_time = 2 + checkpoint_data = None + try: + death_image = pygame.image.load("assets/player/dead.jpg") + print("Image dead.jpg chargée avec succès") + except Exception as e: + print(f"Erreur de chargement de l'image: {e}") + death_image = None + + # Initialize game state and objects + current_state = MENU + main_menu = Menu(game_resources) + level_select_menu = None + level_file = "map/levels/1.json" + current_menu = "main" + leaderboard = Leaderboard(WIDTH, HEIGHT, font) + + clear_checkpoint_database() + projectiles = pygame.sprite.Group() + + pygame.joystick.quit() + pygame.joystick.init() + joysticks = [] + + try: + for i in range(pygame.joystick.get_count()): + joystick = pygame.joystick.Joystick(i) + joystick.init() + joysticks.append(joystick) + except pygame.error: + print("Error while initializing joysticks") + + # Main game loop + running = True + while running: + try: + events = [] + dt = FramePerSec.get_time() / 1000.0 + try: + events = pygame.event.get() + except Exception as e: + print(f"Error while getting events: {e}") + pygame.joystick.quit() + pygame.joystick.init() + continue + + for event in events: + if event.type == QUIT: + running = False + pygame.quit() + sys.exit() + elif event.type == KEYDOWN: + if event.key == K_ESCAPE: + if current_state in [PLAYING, INFINITE]: + current_state = MENU + else: + pygame.quit() + sys.exit() + elif event.key == K_F11: + fullscreen = not fullscreen + if fullscreen: + # Store current window size before going fullscreen + ORIGINAL_WIDTH, ORIGINAL_HEIGHT = displaysurface.get_size() + displaysurface = pygame.display.set_mode( + (0, 0), pygame.FULLSCREEN + ) + else: + # Return to windowed mode with previous size + displaysurface = pygame.display.set_mode( + (ORIGINAL_WIDTH, ORIGINAL_HEIGHT), pygame.RESIZABLE + ) + elif ( + event.type == VIDEORESIZE + ): # Fixed indentation - moved out of K_F11 condition + if not fullscreen: + displaysurface = pygame.display.set_mode( + (event.w, event.h), pygame.RESIZABLE + ) + # Update window dimensions + ORIGINAL_WIDTH, ORIGINAL_HEIGHT = event.w, event.h + elif event.type == USEREVENT: + if event.dict.get("action") == "player_death": + current_state = DEATH_SCREEN + death_timer = 0 + + db = CheckpointDB() + checkpoint_data = db.get_checkpoint(level_file) + + if event.dict.get("action") == "create_projectile": + projectile = event.dict.get("projectile") + projectiles.add(projectile) + + # Handle menu events + if current_state == MENU: + if current_menu == "main": + action = main_menu.handle_event(event) + if action == "level_select": + level_select_menu = LevelSelectMenu(game_resources) + current_menu = "level_select" + elif action == "infinite": + current_state = INFINITE + elif action == "leaderboard": + current_state = LEADERBOARD + elif action == "quit": + pygame.quit() + sys.exit() + elif current_menu == "level_select": + action = level_select_menu.handle_event(event) + if action == "back_to_main": + current_menu = "main" + elif ( + isinstance(action, dict) + and action.get("action") == "select_level" + ): + level_file = action.get("level_file") + print(level_file) + ( + P1, + PT1, + platforms, + all_sprites, + background, + checkpoints, + exits, + ) = initialize_game(game_resources, level_file) + projectiles.empty() + current_state = PLAYING + elif action == "open_editor": + editor_select_menu = LevelEditorSelectionMenu( + game_resources + ) + current_state = "editor_select" + + # Handle leaderboard events + elif current_state == LEADERBOARD: + action = leaderboard.handle_event(event) + if action == "menu": + current_state = MENU + + elif current_state == "editor_select": + action = editor_select_menu.handle_event(event) + if action == "back_to_levels": + current_state = MENU + current_menu = "level_select" + elif isinstance(action, dict): + if action["action"] == "edit_level": + level_editor = LevelEditor( + game_resources, action["level_file"] + ) + current_state = "level_editor" + elif action["action"] == "new_level": + level_editor = LevelEditor(game_resources) + current_state = "level_editor" + + elif current_state == "level_editor": + result = level_editor.handle_event(event) + if result == "back_to_levels": + current_state = "editor_select" + except Exception as e: + print(f"Error while processing events: {e}") + continue + + # Clear screen + displaysurface.fill((0, 0, 0)) + + # Draw appropriate screen based on state + if current_state == MENU: + if current_menu == "main": + main_menu.draw(displaysurface) + elif current_menu == "level_select": + level_select_menu.draw(displaysurface) + elif current_state == "editor_select": + editor_select_menu.draw(displaysurface) + elif current_state == "level_editor": + level_editor.draw(displaysurface) + elif current_state == LEADERBOARD: + leaderboard.draw(displaysurface) + + elif current_state == PLAYING: + # Regular game code + P1.move() + P1.update() + P1.attack() + + # Update camera to follow player + camera.update(P1) + + # Clear screen + displaysurface.fill((0, 0, 0)) + + for platform in platforms: + if platform.is_moving and platform.movement_type == "linear": + if ( + platform.movement_points[0]["x"] + - platform.movement_points[1]["x"] + == 0 + ): + dir = 0 + else: + dir = 1 + if ( + P1.rect.colliderect(platform.rect) + and P1.pos.y == platform.rect.y + ): + P1.pos.x += platform.movement_speed * platform.coeff + + platform.move_linear( + dir, + platform.movement_points, + platform.movement_speed, + platform.wait_time, + platform.coeff, + ) + + if platform.is_moving and platform.movement_type == "circular": + if ( + P1.rect.colliderect(platform.rect) + and P1.pos.y == platform.rect.y + and platform.clockwise + ): + P1.pos.x = P1.pos.x + platform.radius * np.cos(platform.angle) + P1.pos.y = P1.pos.y + platform.radius * np.sin(platform.angle) + + if ( + P1.rect.colliderect(platform.rect) + and P1.pos.y == platform.rect.y + and not platform.clockwise + ): + P1.pos.x = P1.pos.x + platform.radius * np.cos(platform.angle) + P1.pos.y = P1.pos.y + platform.radius * np.sin(-platform.angle) + + platform.move_circular( + platform.center, + platform.angular_speed, + platform.radius, + platform.clockwise, + ) + + if background: + parallax_factor = 0.3 + bg_x = camera.camera.x * parallax_factor + bg_y = camera.camera.y * parallax_factor + displaysurface.blit(background, (bg_x, bg_y)) + + # Draw all sprites with camera offset applied + for entity in all_sprites: + # Calculate position adjusted for camera + camera_adjusted_rect = entity.rect.copy() + camera_adjusted_rect.x += camera.camera.x + camera_adjusted_rect.y += camera.camera.y + displaysurface.blit(entity.surf, camera_adjusted_rect) + + for sprite in all_sprites: + if isinstance(sprite, Enemy): + sprite.update(P1) + else: + sprite.update() + + projectiles.update(WIDTH, HEIGHT, P1, camera) + + for projectile in projectiles: + # Calculate position adjusted for camera (comme pour les autres sprites) + camera_adjusted_rect = projectile.rect.copy() + camera_adjusted_rect.x += camera.camera.x + camera_adjusted_rect.y += camera.camera.y + displaysurface.blit(projectile.surf, camera_adjusted_rect) + + if checkpoints is not None: + checkpoints_hit = pygame.sprite.spritecollide(P1, checkpoints, False) + else: + checkpoints_hit = [] + for checkpoint in checkpoints_hit: + checkpoint.activate() + + exits_hit = pygame.sprite.spritecollide(P1, exits, False) if exits else [] + for exit in exits_hit: + current_level_match = re.search(r"(\d+)\.json$", level_file) + if current_level_match: + current_level = int(current_level_match.group(1)) + next_level = current_level + 1 + + # Unlock next level + db = LevelDB() + db.unlock_level(next_level) + db.close() + + # Return to level select menu + current_state = MENU + current_menu = "level_select" + level_select_menu = LevelSelectMenu(game_resources) + + # Display FPS and coordinates (fixed position UI elements) + fps = int(FramePerSec.get_fps()) + fps_text = font.render(f"FPS: {fps}", True, (255, 255, 255)) + displaysurface.blit(fps_text, (10, 10)) + + P1.draw_dash_cooldown_bar(displaysurface) + + pos_text = font.render( + f"X: {int(P1.pos.x)}, Y: {int(P1.pos.y)}", True, (255, 255, 255) + ) + displaysurface.blit(pos_text, (10, 40)) + + P1.draw_dash_cooldown_bar(displaysurface) + P1.draw_lives(displaysurface) + + elif current_state == INFINITE: + # Placeholder for infinite mode + text = font.render("Mode Infini - À implémenter", True, (255, 255, 255)) + displaysurface.blit(text, (WIDTH // 2 - text.get_width() // 2, HEIGHT // 2)) + + elif current_state == LEADERBOARD: + leaderboard.draw(displaysurface) + + elif current_state == DEATH_SCREEN: + displaysurface.fill((0, 0, 0)) # Fond rouge foncé + + if death_image: + scaled_image = pygame.transform.scale(death_image, (WIDTH, HEIGHT)) + image_rect = scaled_image.get_rect(center=(WIDTH // 2, HEIGHT // 2)) + displaysurface.blit(scaled_image, image_rect) + + # Gestion du timer + death_timer += dt + if death_timer >= death_display_time: + if checkpoint_data: + P1, platforms, all_sprites, background, checkpoints = ( + reset_game_with_checkpoint(level_file, game_resources) + ) + projectiles.empty() + current_state = PLAYING + else: + current_state = MENU + + pygame.display.update() + FramePerSec.tick(FPS)