diff --git a/.gitignore b/.gitignore index a96374f..6c30992 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ .idea .idea/* -checkpoint.db \ No newline at end of file +checkpoint.db +checkpoint.db-journal \ No newline at end of file diff --git a/main.py b/main.py index 50ba76f..311f729 100644 --- a/main.py +++ b/main.py @@ -3,7 +3,12 @@ import sys from pygame.locals import * from src.Entity.Enemy import Enemy -from src.game import initialize_game, reset_game, reset_game_with_checkpoint +from src.game import ( + initialize_game, + reset_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 @@ -38,8 +43,10 @@ def main(): menu = Menu(game_resources) leaderboard = Leaderboard(WIDTH, HEIGHT, font) + clear_checkpoint_database() + # Initialize game components - P1, PT1, platforms, all_sprites, background, checkpoints = initialize_game( + P1, PT1, platforms, all_sprites, background, checkpoints, exits = initialize_game( game_resources, "map_test.json" ) projectiles = pygame.sprite.Group() diff --git a/map_test.json b/map_test.json index 0f8390e..dc2fa9f 100644 --- a/map_test.json +++ b/map_test.json @@ -173,12 +173,14 @@ "y": 700 }, - "exit": { - "x": 2300, - "y": 700, - "width": 50, - "height": 80, - "next_level": "Level 2", - "sprite": "assets/map/exit/door.png" - } + "exits": [ + { + "x": 2300, + "y": 700, + "width": 50, + "height": 80, + "next_level": "Level 2", + "sprite": "assets/map/exit/door.png" + } + ] } \ No newline at end of file diff --git a/src/Database/CheckpointDB.py b/src/Database/CheckpointDB.py index a0b2825..93dc6be 100644 --- a/src/Database/CheckpointDB.py +++ b/src/Database/CheckpointDB.py @@ -68,3 +68,12 @@ class CheckpointDB: """Close database connection""" if self.conn: self.conn.close() + + def clear_all(self): + """ + Clear all checkpoints from the database + """ + try: + self.cursor.execute("DELETE FROM checkpoints") + except Exception as e: + print(f"Error clearing checkpoint database: {e}") diff --git a/src/Entity/Exit.py b/src/Entity/Exit.py new file mode 100644 index 0000000..0fd66f5 --- /dev/null +++ b/src/Entity/Exit.py @@ -0,0 +1,62 @@ +import pygame +from src.Entity.Entity import Entity + + +class Exit(Entity): + """ + Class representing a level exit/goal point that triggers level completion when touched. + Inherits from Entity base class. + """ + + def __init__(self, x, y, width, height, next_level, sprite_path=None): + """ + Initialize the exit object. + + Args: + x (int): X-coordinate position + y (int): Y-coordinate position + width (int): Width of the exit + height (int): Height of the exit + next_level (str): ID or name of the level to load when exiting + sprite_path (str, optional): Path to the sprite image for the exit + """ + super().__init__(pos=(x, y), size=(width, height), color=(0, 255, 0)) + self.next_level = next_level # Store the next level to load + self.active = True # Flag to prevent multiple triggers + self.player = None # Will store the player reference + + # Load sprite if provided + if sprite_path: + try: + self.image = pygame.image.load(sprite_path).convert_alpha() + self.image = pygame.transform.scale(self.image, (width, height)) + self.surf = self.image + except Exception as e: + print(f"Error loading exit sprite: {e}") + + def set_player(self, player): + """ + Set the player reference for collision detection. + + Args: + player: The player entity to check collision with + """ + self.player = player + + def update(self): + """ + Check for collision with the player and trigger level completion. + """ + # Skip collision check if player reference is not set + if not self.player or not self.active: + return + + # Check if player is colliding with exit + if self.rect.colliderect(self.player.rect): + # Create and post a level complete event + exit_event = pygame.event.Event( + pygame.USEREVENT, + {"action": "level_complete", "next_level": self.next_level}, + ) + pygame.event.post(exit_event) + self.active = False # Prevent multiple triggers diff --git a/src/Map/parser.py b/src/Map/parser.py index 14c170b..eddf855 100644 --- a/src/Map/parser.py +++ b/src/Map/parser.py @@ -5,6 +5,7 @@ from src.Entity.Platform import Platform from src.Entity.Player import Player from src.Entity.Enemy import Enemy from src.Entity.Checkpoint import Checkpoint +from src.Entity.Exit import Exit class MapParser: @@ -12,6 +13,7 @@ class MapParser: self.game_resources = game_resources self.all_sprites = self.game_resources.all_sprites self.platforms = self.game_resources.platforms + self.exits = self.game_resources.exits self.enemies = pygame.sprite.Group() self.collectibles = pygame.sprite.Group() self.checkpoints = pygame.sprite.Group() @@ -38,6 +40,7 @@ class MapParser: "height": map_data.get("height", self.game_resources.HEIGHT), }, "checkpoints": self.checkpoints, + "exits": self.exits, } except Exception as e: print(f"Error loading map: {e}") @@ -51,6 +54,7 @@ class MapParser: self.enemies.empty() self.collectibles.empty() self.checkpoints.empty() + self.exits.empty() # Create ground elements if "ground" in map_data: @@ -146,3 +150,16 @@ class MapParser: ) self.checkpoints.add(checkpoint) self.all_sprites.add(checkpoint) + + if "exits" in map_data: + for exit_data in map_data["exits"]: + exit = Exit( + exit_data["x"], + exit_data["y"], + exit_data["width"], + exit_data["height"], + exit_data["next_level"], + exit_data.get("sprite"), + ) + self.exits.add(exit) + self.all_sprites.add(exit) diff --git a/src/constant.py b/src/constant.py index fba4fc2..74a35cc 100644 --- a/src/constant.py +++ b/src/constant.py @@ -18,13 +18,14 @@ class GameResources: # Ressources self.platforms = pygame.sprite.Group() + self.all_sprites = pygame.sprite.Group() + self.exits = pygame.sprite.Group() self.vec = pygame.math.Vector2 self.displaysurface = pygame.display.set_mode( (self.WIDTH, self.HEIGHT), pygame.RESIZABLE ) pygame.display.set_caption("Project Sanic") self.FramePerSec = pygame.time.Clock() - self.all_sprites = pygame.sprite.Group() # Font try: diff --git a/src/game.py b/src/game.py index a651b6f..0dbd68d 100644 --- a/src/game.py +++ b/src/game.py @@ -8,7 +8,16 @@ from src.Database.CheckpointDB import CheckpointDB def initialize_game(game_resources, map_file="map_test.json"): - """Initialize game with map from JSON file""" + """ + Initialize game with map from JSON file + + Args: + game_resources: GameResources object containing pygame resources + map_file (str): Name of the map JSON file to load + + Returns: + tuple: (player, platform, platforms_group, all_sprites, background, checkpoints, exits) + """ parser = MapParser(game_resources) map_objects = parser.load_map(map_file) @@ -31,8 +40,15 @@ def initialize_game(game_resources, map_file="map_test.json"): game_resources.all_sprites, None, None, + None, ) + # Set player reference for exits if they exist + exits = map_objects.get("exits", None) + if exits and map_objects["player"]: + for exit_obj in exits: + exit_obj.set_player(map_objects["player"]) + return ( map_objects["player"], None, @@ -40,13 +56,14 @@ def initialize_game(game_resources, map_file="map_test.json"): map_objects["all_sprites"], parser.background, map_objects["checkpoints"], + exits, ) def reset_game(game_resources): """Reset the game to initial state""" # Reload game objects - player, _, platforms, all_sprites, background, checkpoints = initialize_game( + player, _, platforms, all_sprites, background, checkpoints, exits = initialize_game( game_resources, "map_test.json" ) @@ -66,7 +83,7 @@ def reset_game_with_checkpoint(map_name, game_resources): checkpoint_pos = db.get_checkpoint(map_name) # Initialize game - player, _, platforms, all_sprites, background, checkpoints = initialize_game( + player, _, platforms, all_sprites, background, checkpoints, exits = initialize_game( game_resources, map_name ) @@ -78,5 +95,18 @@ def reset_game_with_checkpoint(map_name, game_resources): return player, platforms, all_sprites, background, checkpoints +def clear_checkpoint_database(): + """ + Clear all checkpoints from the database. + Used when starting a new game session. + """ + try: + db = CheckpointDB() + db.clear_all() + print("Checkpoint database cleared successfully") + except Exception as e: + print(f"Error clearing checkpoint database: {e}") + + if __name__ == "__main__": print("Please run the game using main.py")