Feat(Exit) - Implement Exit class for level completion; update game initialization and map parsing to support exits

This commit is contained in:
Félix MARQUET
2025-03-28 11:05:38 +01:00
parent 40a0bf18f7
commit 87ec74b5b9
8 changed files with 144 additions and 15 deletions

3
.gitignore vendored
View File

@@ -4,4 +4,5 @@
.idea
.idea/*
checkpoint.db
checkpoint.db
checkpoint.db-journal

11
main.py
View File

@@ -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()

View File

@@ -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"
}
]
}

View File

@@ -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}")

62
src/Entity/Exit.py Normal file
View File

@@ -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

View File

@@ -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)

View File

@@ -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:

View File

@@ -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")