mirror of
https://github.com/BreizhHardware/project_sanic.git
synced 2026-01-18 16:47:25 +01:00
FEAT [Leaderboard] - Add infinite mode points counter : using DB it's displayed in the Leaderboard too
This commit is contained in:
@@ -5,24 +5,20 @@ import os
|
||||
class InfiniteModeDB:
|
||||
def __init__(self, db_file="game.db"):
|
||||
"""
|
||||
Initialize database connection for infinite game mode points management
|
||||
Initialize database connection for infinite game mode points management.
|
||||
|
||||
Args:
|
||||
db_file: SQLite database file path
|
||||
db_file: SQLite database file path.
|
||||
"""
|
||||
# Create database directory if it doesn't exist
|
||||
os.makedirs(
|
||||
os.path.dirname(db_file) if os.path.dirname(db_file) else ".", exist_ok=True
|
||||
)
|
||||
|
||||
self.conn = sqlite3.connect(db_file)
|
||||
self.cursor = self.conn.cursor()
|
||||
self._create_tables()
|
||||
self.clear_InfiniteModeDB()
|
||||
|
||||
def _create_tables(self):
|
||||
print("Creating infinite mode table if it doesn't exist")
|
||||
"""Create required tables if they don't exist"""
|
||||
"""Create required tables if they don't exist."""
|
||||
self.cursor.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS InfiniteMode (
|
||||
@@ -32,24 +28,14 @@ class InfiniteModeDB:
|
||||
"""
|
||||
)
|
||||
self.conn.commit()
|
||||
def get_all(self):
|
||||
"""
|
||||
Get all scores from the table
|
||||
|
||||
Returns:
|
||||
List of tuples containing player name and score
|
||||
"""
|
||||
def get_all(self):
|
||||
"""Get all scores from the table."""
|
||||
self.cursor.execute("SELECT * FROM InfiniteMode")
|
||||
return self.cursor.fetchall()
|
||||
|
||||
def add_score(self, player_name, score):
|
||||
"""
|
||||
Add a new score to the InfiniteMode
|
||||
|
||||
Args:
|
||||
player_name: Name of the player
|
||||
score: Score to be added
|
||||
"""
|
||||
"""Add a new score to the InfiniteMode."""
|
||||
self.cursor.execute(
|
||||
"INSERT INTO InfiniteMode (player_name, score) VALUES (?, ?)",
|
||||
(player_name, score),
|
||||
@@ -57,13 +43,14 @@ class InfiniteModeDB:
|
||||
self.conn.commit()
|
||||
|
||||
def clear_InfiniteModeDB(self):
|
||||
"""
|
||||
Clear all scores from the leaderboard
|
||||
"""
|
||||
self.cursor.execute("DELETE FROM InfiniteMode")
|
||||
self.conn.commit()
|
||||
"""Clear all scores from the InfiniteMode table."""
|
||||
try:
|
||||
self.cursor.execute("DELETE FROM InfiniteMode")
|
||||
self.conn.commit()
|
||||
except sqlite3.Error as e:
|
||||
print(f"Error clearing InfiniteMode table: {e}")
|
||||
|
||||
def close(self):
|
||||
"""Close database connection"""
|
||||
"""Close database connection."""
|
||||
if self.conn:
|
||||
self.conn.close()
|
||||
@@ -5,23 +5,20 @@ import os
|
||||
class LeaderboardDB:
|
||||
def __init__(self, db_file="game.db"):
|
||||
"""
|
||||
Initialize database connection for infinite game mode points management
|
||||
Initialize database connection for leaderboard management.
|
||||
|
||||
Args:
|
||||
db_file: SQLite database file path
|
||||
db_file: SQLite database file path.
|
||||
"""
|
||||
# Create database directory if it doesn't exist
|
||||
os.makedirs(
|
||||
os.path.dirname(db_file) if os.path.dirname(db_file) else ".", exist_ok=True
|
||||
)
|
||||
|
||||
self.conn = sqlite3.connect(db_file)
|
||||
self.cursor = self.conn.cursor()
|
||||
self._create_tables()
|
||||
|
||||
def _create_tables(self):
|
||||
print("Ensuring the Leaderboard table has the correct schema")
|
||||
# Create the table with the correct schema
|
||||
"""Ensure the Leaderboard table has the correct schema."""
|
||||
self.cursor.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS Leaderboard (
|
||||
@@ -32,36 +29,16 @@ class LeaderboardDB:
|
||||
"""
|
||||
)
|
||||
self.conn.commit()
|
||||
def get_all(self):
|
||||
"""
|
||||
Get all scores from the table limited at 10 rows
|
||||
|
||||
Returns:
|
||||
List of tuples containing player name and score
|
||||
"""
|
||||
self.cursor.execute("SELECT score, date FROM Leaderboard LIMIT 10")
|
||||
return self.cursor.fetchall()
|
||||
|
||||
def get_top_3_scores(self):
|
||||
"""
|
||||
Get top 3 scores from the leaderboard
|
||||
|
||||
Returns:
|
||||
List of tuples containing player name and score
|
||||
"""
|
||||
def get_top_10_scores(self):
|
||||
"""Get top 10 scores from the leaderboard."""
|
||||
self.cursor.execute(
|
||||
"SELECT score, date FROM Leaderboard ORDER BY score DESC LIMIT 3"
|
||||
"SELECT score, date FROM Leaderboard ORDER BY score DESC LIMIT 10"
|
||||
)
|
||||
return self.cursor.fetchall()
|
||||
|
||||
def add_score(self, player_name, score):
|
||||
"""
|
||||
Add a new score to the InfiniteMode
|
||||
|
||||
Args:
|
||||
player_name: Name of the player
|
||||
score: Score to be added
|
||||
"""
|
||||
"""Add a new score to the leaderboard."""
|
||||
self.cursor.execute(
|
||||
"INSERT INTO Leaderboard (player_name, score) VALUES (?, ?)",
|
||||
(player_name, score),
|
||||
@@ -69,13 +46,11 @@ class LeaderboardDB:
|
||||
self.conn.commit()
|
||||
|
||||
def clear_leaderboard(self):
|
||||
"""
|
||||
Clear all scores from the leaderboard
|
||||
"""
|
||||
"""Clear all scores from the leaderboard."""
|
||||
self.cursor.execute("DELETE FROM Leaderboard")
|
||||
self.conn.commit()
|
||||
|
||||
def close(self):
|
||||
"""Close database connection"""
|
||||
"""Close database connection."""
|
||||
if self.conn:
|
||||
self.conn.close()
|
||||
@@ -11,11 +11,12 @@ from src.Database.LevelDB import LevelDB
|
||||
class Leaderboard:
|
||||
"""This class represents the leaderboard menu for the game."""
|
||||
|
||||
def __init__(self, WIDTH, HEIGHT, font, db_path="game.db"):
|
||||
def __init__(self, WIDTH, HEIGHT, font, leaderboard_db, db_path="game.db"):
|
||||
self.WIDTH = WIDTH
|
||||
self.HEIGHT = HEIGHT
|
||||
self.font = font
|
||||
self.db_path = db_path
|
||||
self.leaderboard_db = leaderboard_db
|
||||
|
||||
self.levels = self.get_available_levels()
|
||||
self.level_tabs = [f"Level {level}" for level in self.levels]
|
||||
@@ -58,8 +59,23 @@ class Leaderboard:
|
||||
for i, level in enumerate(self.levels):
|
||||
self.scores[i] = self.get_level_scores(str(level))
|
||||
|
||||
# TO DO: Load scores for infinite mode
|
||||
self.scores[len(self.levels)] = []
|
||||
# Load scores for infinite mode
|
||||
try:
|
||||
# Get the TOP 10 scores for infinite mode
|
||||
all_scores = self.leaderboard_db.get_top_10_scores()
|
||||
|
||||
# Format the scores for display
|
||||
formatted_scores = []
|
||||
for score, date in all_scores:
|
||||
date_obj = datetime.strptime(date, "%Y-%m-%d %H:%M:%S")
|
||||
formatted_date = date_obj.strftime("%d/%m/%Y")
|
||||
formatted_scores.append((formatted_date, score))
|
||||
|
||||
# Assign the formatted scores to the infinite mode tab
|
||||
self.scores[len(self.levels)] = formatted_scores
|
||||
except Exception as e:
|
||||
print(f"Error loading infinite mode scores: {e}")
|
||||
self.scores[len(self.levels)] = []
|
||||
|
||||
def get_level_scores(self, level_id):
|
||||
"""Get the top 10 scores for a specific level from the database."""
|
||||
@@ -104,6 +120,9 @@ class Leaderboard:
|
||||
|
||||
def draw(self, surface):
|
||||
"""Draw the leaderboard on the given surface."""
|
||||
# Refresh scores to ensure the latest data is displayed
|
||||
self.load_scores()
|
||||
|
||||
self.bg_manager.draw(surface)
|
||||
|
||||
# Draw a semi-transparent panel
|
||||
@@ -159,7 +178,7 @@ class Leaderboard:
|
||||
(self.WIDTH // 2 - no_scores_text.get_width() // 2, y_pos + 40),
|
||||
)
|
||||
else:
|
||||
for i, (date, time, collected, total) in enumerate(scores_for_tab):
|
||||
for i, score_data in enumerate(scores_for_tab):
|
||||
row_bg = (30, 30, 60, 150) if i % 2 == 0 else (40, 40, 80, 150)
|
||||
row_rect = pygame.Rect(self.WIDTH // 2 - 200, y_pos - 5, 400, 30)
|
||||
row_surface = pygame.Surface(
|
||||
@@ -169,28 +188,40 @@ class Leaderboard:
|
||||
surface.blit(row_surface, row_rect)
|
||||
|
||||
# Rank
|
||||
rank_text = self.font.render(f"{i+1}.", True, (255, 255, 255))
|
||||
rank_text = self.font.render(f"{i + 1}.", True, (255, 255, 255))
|
||||
surface.blit(rank_text, (header_positions[0], y_pos))
|
||||
|
||||
# Date
|
||||
date_text = self.font.render(date, True, (255, 255, 255))
|
||||
surface.blit(date_text, (header_positions[1], y_pos))
|
||||
if self.current_tab == len(self.levels): # Infinite mode
|
||||
date, score = score_data
|
||||
# Date
|
||||
date_text = self.font.render(date, True, (255, 255, 255))
|
||||
surface.blit(date_text, (header_positions[1], y_pos))
|
||||
|
||||
# Time
|
||||
time_text = self.font.render(
|
||||
self.format_time(time), True, (255, 255, 255)
|
||||
)
|
||||
surface.blit(time_text, (header_positions[2], y_pos))
|
||||
# Time (score)
|
||||
score_text = self.font.render(str(score), True, (255, 255, 255))
|
||||
surface.blit(score_text, (header_positions[2], y_pos))
|
||||
else: # Level scores
|
||||
date, time, collected, total = score_data
|
||||
|
||||
# Collected items
|
||||
collected_color = (255, 255, 255)
|
||||
if collected == total:
|
||||
collected_color = (0, 255, 0)
|
||||
# Date
|
||||
date_text = self.font.render(date, True, (255, 255, 255))
|
||||
surface.blit(date_text, (header_positions[1], y_pos))
|
||||
|
||||
collected_text = self.font.render(
|
||||
f"{collected}/{total}", True, collected_color
|
||||
)
|
||||
surface.blit(collected_text, (header_positions[3], y_pos))
|
||||
# Time
|
||||
time_text = self.font.render(
|
||||
self.format_time(time), True, (255, 255, 255)
|
||||
)
|
||||
surface.blit(time_text, (header_positions[2], y_pos))
|
||||
|
||||
# Collected items
|
||||
collected_color = (255, 255, 255)
|
||||
if collected == total:
|
||||
collected_color = (0, 255, 0)
|
||||
|
||||
collected_text = self.font.render(
|
||||
f"{collected}/{total}", True, collected_color
|
||||
)
|
||||
surface.blit(collected_text, (header_positions[3], y_pos))
|
||||
|
||||
y_pos += 40
|
||||
|
||||
|
||||
@@ -138,13 +138,8 @@ def start_infinite_mode(game_resources):
|
||||
game_resources.infinite_mode = True
|
||||
|
||||
# Open the temporary database
|
||||
print("Creating leaderboard database")
|
||||
game_resources.infinite_mode_db = InfiniteModeDB()
|
||||
|
||||
# Open the leaderboard database
|
||||
print("Creating leaderboard database")
|
||||
game_resources.leaderboard_db = LeaderboardDB()
|
||||
|
||||
# Generate the first level
|
||||
first_level = infinite_manager.start_infinite_mode()
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import sys
|
||||
from pygame.locals import *
|
||||
import numpy as np
|
||||
|
||||
from src.Database.LeaderboardDB import LeaderboardDB
|
||||
from src.Database.LevelDB import LevelDB
|
||||
from src.Entity.Enemy import Enemy
|
||||
from src.Menu.LevelSelectMenu import LevelSelectMenu
|
||||
@@ -68,8 +69,9 @@ def initialize_game_resources():
|
||||
level_select_menu = None
|
||||
editor_select_menu = None
|
||||
level_file = "map/levels/1.json"
|
||||
leaderboard_db = LeaderboardDB()
|
||||
leaderboard = Leaderboard(
|
||||
game_resources.WIDTH, game_resources.HEIGHT, game_resources.font
|
||||
game_resources.WIDTH, game_resources.HEIGHT, game_resources.font, leaderboard_db
|
||||
)
|
||||
|
||||
return (
|
||||
@@ -88,7 +90,8 @@ def initialize_game_resources():
|
||||
leaderboard,
|
||||
projectiles,
|
||||
joysticks,
|
||||
editor_select_menu, # Added editor_select_menu to the return tuple
|
||||
editor_select_menu,
|
||||
leaderboard_db,
|
||||
)
|
||||
|
||||
|
||||
@@ -498,6 +501,11 @@ def handle_exits(
|
||||
speedrun_timer.save_time(collected_coins, total_coins)
|
||||
if hasattr(game_resources, "infinite_mode") and game_resources.infinite_mode:
|
||||
# Infinite mode: load the next level without going back to menu
|
||||
if hasattr(game_resources, "infinite_mode_db"):
|
||||
# Zeldo : add 100 points
|
||||
game_resources.infinite_mode_db.add_score("player", 100)
|
||||
# Add coins points also
|
||||
game_resources.infinite_mode_db.add_score("player", P1.coins * 10)
|
||||
result = handle_exit_collision(exit, game_resources, level_file)
|
||||
return {"action": "continue_infinite", "result": result}
|
||||
else:
|
||||
@@ -545,6 +553,7 @@ def draw_ui_elements(displaysurface, P1, FramePerSec, font, speedrun_timer=None)
|
||||
|
||||
|
||||
def handle_death_screen(
|
||||
P1,
|
||||
displaysurface,
|
||||
death_timer,
|
||||
dt,
|
||||
@@ -555,6 +564,7 @@ def handle_death_screen(
|
||||
game_resources,
|
||||
WIDTH,
|
||||
HEIGHT,
|
||||
leaderboard_db,
|
||||
):
|
||||
"""Handle player death screen"""
|
||||
# Fill background
|
||||
@@ -590,6 +600,20 @@ def handle_death_screen(
|
||||
"projectiles": projectiles,
|
||||
}
|
||||
else:
|
||||
if hasattr(game_resources, "infinite_mode_db"):
|
||||
# Save score to database
|
||||
game_resources.infinite_mode_db.add_score("player", P1.coins * 10)
|
||||
# Get all scores from the database
|
||||
all_scores = game_resources.infinite_mode_db.get_all()
|
||||
game_resources.infinite_mode_db.clear_InfiniteModeDB()
|
||||
game_resources.infinite_mode_db.close()
|
||||
# Calculate total points, add them to leaderboard table
|
||||
if(leaderboard_db):
|
||||
total = 0
|
||||
for i in range(len(all_scores)):
|
||||
total += all_scores[i][1]
|
||||
leaderboard_db.add_score("player", total)
|
||||
|
||||
# Return to menu
|
||||
if hasattr(game_resources, "infinite_mode"):
|
||||
game_resources.infinite_mode = False
|
||||
@@ -626,6 +650,7 @@ def handler():
|
||||
projectiles,
|
||||
joysticks,
|
||||
editor_select_menu,
|
||||
leaderboard_db,
|
||||
) = initialize_game_resources()
|
||||
|
||||
# Initialize editor variables
|
||||
@@ -859,6 +884,7 @@ def handler():
|
||||
elif current_state == DEATH_SCREEN:
|
||||
# Handle death screen
|
||||
death_result = handle_death_screen(
|
||||
P1,
|
||||
displaysurface,
|
||||
death_timer,
|
||||
dt,
|
||||
@@ -869,6 +895,7 @@ def handler():
|
||||
game_resources,
|
||||
game_resources.WIDTH,
|
||||
game_resources.HEIGHT,
|
||||
leaderboard_db
|
||||
)
|
||||
|
||||
death_timer = death_result["death_timer"]
|
||||
|
||||
Reference in New Issue
Block a user