mirror of
https://github.com/BreizhHardware/project_sanic.git
synced 2026-01-18 16:47:25 +01:00
Implement game state management with menu and leaderboard functionality
This commit is contained in:
BIN
assets/player/Sanic Boule Annimate.png
Normal file
BIN
assets/player/Sanic Boule Annimate.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.5 MiB |
BIN
assets/player/Sanic Boule.png
Normal file
BIN
assets/player/Sanic Boule.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 498 KiB |
101
main.py
101
main.py
@@ -1,5 +1,104 @@
|
||||
import pygame
|
||||
import sys
|
||||
from pygame.locals import *
|
||||
|
||||
# Import from pygame_basics
|
||||
from src.pygame_basics import (
|
||||
WIDTH,
|
||||
HEIGHT,
|
||||
FPS,
|
||||
displaysurface,
|
||||
FramePerSec,
|
||||
font,
|
||||
initialize_game,
|
||||
)
|
||||
|
||||
# Import from menu
|
||||
from src.menu import Menu, Leaderboard
|
||||
|
||||
|
||||
def main():
|
||||
print("Hello World!")
|
||||
# Game states
|
||||
MENU = 0
|
||||
PLAYING = 1
|
||||
INFINITE = 2
|
||||
LEADERBOARD = 3
|
||||
|
||||
# Initialize game state and objects
|
||||
current_state = MENU
|
||||
menu = Menu()
|
||||
leaderboard = Leaderboard()
|
||||
|
||||
# Initialize game components
|
||||
P1, PT1, platforms, all_sprites = initialize_game()
|
||||
|
||||
# Main game loop
|
||||
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:
|
||||
if current_state in [PLAYING, INFINITE]:
|
||||
current_state = MENU
|
||||
else:
|
||||
pygame.quit()
|
||||
sys.exit()
|
||||
|
||||
# Handle menu events
|
||||
if current_state == MENU:
|
||||
action = menu.handle_event(event)
|
||||
if action == "play":
|
||||
current_state = PLAYING
|
||||
elif action == "infinite":
|
||||
current_state = INFINITE
|
||||
elif action == "leaderboard":
|
||||
current_state = LEADERBOARD
|
||||
elif action == "quit":
|
||||
pygame.quit()
|
||||
sys.exit()
|
||||
|
||||
# Handle leaderboard events
|
||||
elif current_state == LEADERBOARD:
|
||||
action = leaderboard.handle_event(event)
|
||||
if action == "menu":
|
||||
current_state = MENU
|
||||
|
||||
# Clear screen
|
||||
displaysurface.fill((0, 0, 0))
|
||||
|
||||
# Draw appropriate screen based on state
|
||||
if current_state == MENU:
|
||||
menu.draw(displaysurface)
|
||||
|
||||
elif current_state == PLAYING:
|
||||
# Regular game code
|
||||
P1.move()
|
||||
P1.update()
|
||||
for entity in all_sprites:
|
||||
displaysurface.blit(entity.surf, entity.rect)
|
||||
|
||||
# Display FPS and coordinates
|
||||
fps = int(FramePerSec.get_fps())
|
||||
fps_text = font.render(f"FPS: {fps}", True, (255, 255, 255))
|
||||
displaysurface.blit(fps_text, (10, 10))
|
||||
|
||||
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))
|
||||
|
||||
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)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
176
src/menu.py
Normal file
176
src/menu.py
Normal file
@@ -0,0 +1,176 @@
|
||||
import pygame
|
||||
from pygame.locals import *
|
||||
from src.pygame_basics import WIDTH, HEIGHT, font
|
||||
|
||||
|
||||
class Menu:
|
||||
def __init__(self):
|
||||
self.buttons = []
|
||||
button_width = 250
|
||||
button_height = 60
|
||||
button_spacing = 20
|
||||
start_y = HEIGHT // 2 - 100
|
||||
|
||||
# Create buttons centered horizontally
|
||||
self.buttons.append(
|
||||
Button(
|
||||
"Jouer",
|
||||
WIDTH // 2 - button_width // 2,
|
||||
start_y,
|
||||
button_width,
|
||||
button_height,
|
||||
"play",
|
||||
)
|
||||
)
|
||||
|
||||
start_y += button_height + button_spacing
|
||||
self.buttons.append(
|
||||
Button(
|
||||
"Jouer en mode infini",
|
||||
WIDTH // 2 - button_width // 2,
|
||||
start_y,
|
||||
button_width,
|
||||
button_height,
|
||||
"infinite",
|
||||
)
|
||||
)
|
||||
|
||||
start_y += button_height + button_spacing
|
||||
self.buttons.append(
|
||||
Button(
|
||||
"Classement",
|
||||
WIDTH // 2 - button_width // 2,
|
||||
start_y,
|
||||
button_width,
|
||||
button_height,
|
||||
"leaderboard",
|
||||
)
|
||||
)
|
||||
|
||||
start_y += button_height + button_spacing
|
||||
self.buttons.append(
|
||||
Button(
|
||||
"Quitter",
|
||||
WIDTH // 2 - button_width // 2,
|
||||
start_y,
|
||||
button_width,
|
||||
button_height,
|
||||
"quit",
|
||||
)
|
||||
)
|
||||
|
||||
def draw(self, surface):
|
||||
# Draw title
|
||||
title = pygame.font.SysFont("Arial", 72).render(
|
||||
"Project Sanic", True, (0, 191, 255)
|
||||
)
|
||||
title_rect = title.get_rect(center=(WIDTH // 2, HEIGHT // 4))
|
||||
surface.blit(title, title_rect)
|
||||
|
||||
# Draw buttons
|
||||
for button in self.buttons:
|
||||
button.draw(surface)
|
||||
|
||||
def handle_event(self, event):
|
||||
for button in self.buttons:
|
||||
action = button.handle_event(event)
|
||||
if action:
|
||||
return action
|
||||
return None
|
||||
|
||||
|
||||
class Leaderboard:
|
||||
def __init__(self):
|
||||
self.tabs = ["Mode Normal", "Mode Infini"]
|
||||
self.current_tab = 0
|
||||
self.scores = {
|
||||
0: [("Player1", 1000), ("Player2", 800), ("Player3", 600)],
|
||||
1: [("Player1", 2000), ("Player2", 1500), ("Player3", 1200)],
|
||||
}
|
||||
self.back_button = Button("Retour", 20, HEIGHT - 70, 120, 50, "menu")
|
||||
tab_width = 150
|
||||
self.tab_buttons = [
|
||||
Button(self.tabs[0], WIDTH // 2 - tab_width, 80, tab_width, 40, "tab_0"),
|
||||
Button(self.tabs[1], WIDTH // 2, 80, tab_width, 40, "tab_1"),
|
||||
]
|
||||
|
||||
def draw(self, surface):
|
||||
# Draw title
|
||||
title = pygame.font.SysFont("Arial", 48).render(
|
||||
"Classement", True, (0, 191, 255)
|
||||
)
|
||||
title_rect = title.get_rect(center=(WIDTH // 2, 40))
|
||||
surface.blit(title, title_rect)
|
||||
|
||||
# Draw tabs
|
||||
for i, button in enumerate(self.tab_buttons):
|
||||
if i == self.current_tab:
|
||||
pygame.draw.rect(
|
||||
surface,
|
||||
(100, 149, 237),
|
||||
(button.x, button.y, button.width, button.height),
|
||||
)
|
||||
button.draw(surface)
|
||||
|
||||
# Draw scores
|
||||
y_pos = 150
|
||||
for i, (name, score) in enumerate(self.scores[self.current_tab]):
|
||||
rank_text = font.render(f"{i+1}. {name}: {score}", True, (255, 255, 255))
|
||||
surface.blit(rank_text, (WIDTH // 2 - rank_text.get_width() // 2, y_pos))
|
||||
y_pos += 40
|
||||
|
||||
self.back_button.draw(surface)
|
||||
|
||||
def handle_event(self, event):
|
||||
action = self.back_button.handle_event(event)
|
||||
if action:
|
||||
return action
|
||||
|
||||
for i, button in enumerate(self.tab_buttons):
|
||||
action = button.handle_event(event)
|
||||
if action and action.startswith("tab_"):
|
||||
self.current_tab = int(action.split("_")[1])
|
||||
return None
|
||||
|
||||
|
||||
class Button:
|
||||
def __init__(self, text, x, y, width, height, action=None):
|
||||
self.text = text
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.action = action
|
||||
self.hover = False
|
||||
|
||||
def draw(self, surface):
|
||||
# Button colors
|
||||
color = (100, 149, 237) if self.hover else (65, 105, 225)
|
||||
border_color = (255, 255, 255)
|
||||
|
||||
# Draw button with border
|
||||
pygame.draw.rect(surface, color, (self.x, self.y, self.width, self.height))
|
||||
pygame.draw.rect(
|
||||
surface, border_color, (self.x, self.y, self.width, self.height), 2
|
||||
)
|
||||
|
||||
# Draw text
|
||||
text_surf = font.render(self.text, True, (255, 255, 255))
|
||||
text_rect = text_surf.get_rect(
|
||||
center=(self.x + self.width / 2, self.y + self.height / 2)
|
||||
)
|
||||
surface.blit(text_surf, text_rect)
|
||||
|
||||
def is_hover(self, pos):
|
||||
return (
|
||||
self.x <= pos[0] <= self.x + self.width
|
||||
and self.y <= pos[1] <= self.y + self.height
|
||||
)
|
||||
|
||||
def handle_event(self, event):
|
||||
if event.type == MOUSEMOTION:
|
||||
self.hover = self.is_hover(event.pos)
|
||||
elif event.type == MOUSEBUTTONDOWN:
|
||||
if self.hover and self.action:
|
||||
return self.action
|
||||
return None
|
||||
@@ -1,28 +1,32 @@
|
||||
import pygame
|
||||
from pygame.locals import *
|
||||
import sys
|
||||
import os
|
||||
from pygame.locals import *
|
||||
import time
|
||||
import os
|
||||
|
||||
# Initialize Pygame
|
||||
pygame.init()
|
||||
|
||||
vec = pygame.math.Vector2
|
||||
HEIGHT = 450
|
||||
WIDTH = 400
|
||||
# Constants
|
||||
WIDTH = 800
|
||||
HEIGHT = 600
|
||||
FPS = 60
|
||||
VEC = pygame.math.Vector2
|
||||
ACC = 0.5
|
||||
FRIC = -0.12
|
||||
FPS = 60
|
||||
vec = pygame.math.Vector2
|
||||
|
||||
# Setup display
|
||||
displaysurface = pygame.display.set_mode((WIDTH, HEIGHT))
|
||||
pygame.display.set_caption("Game")
|
||||
FramePerSec = pygame.time.Clock()
|
||||
|
||||
displaysurface = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
|
||||
WIDTH, HEIGHT = displaysurface.get_size()
|
||||
pygame.display.set_caption("Project Sanic")
|
||||
# Font setup
|
||||
font = pygame.font.SysFont("Arial", 20)
|
||||
|
||||
# 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
|
||||
# Global variables for access in other modules
|
||||
platforms = pygame.sprite.Group()
|
||||
all_sprites = pygame.sprite.Group()
|
||||
|
||||
|
||||
class Player(pygame.sprite.Sprite):
|
||||
@@ -31,11 +35,14 @@ class Player(pygame.sprite.Sprite):
|
||||
|
||||
# Animation variables
|
||||
self.animation_frames = []
|
||||
self.jump_frames = []
|
||||
self.dash_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.moving = False
|
||||
self.dashing = False
|
||||
|
||||
# Load static image and animation frames
|
||||
self.load_images()
|
||||
@@ -67,7 +74,7 @@ class Player(pygame.sprite.Sprite):
|
||||
self.static_image, (120, 120)
|
||||
)
|
||||
|
||||
# Load animation sprite sheet
|
||||
# Load regular animation sprite sheet
|
||||
if os.path.isfile("assets/player/Sanic Annimate.png"):
|
||||
sprite_sheet = pygame.image.load(
|
||||
"assets/player/Sanic Annimate.png"
|
||||
@@ -85,44 +92,77 @@ class Player(pygame.sprite.Sprite):
|
||||
frame = pygame.transform.scale(frame, (120, 120))
|
||||
self.animation_frames.append(frame)
|
||||
|
||||
# Load jump animation sprite sheet
|
||||
if os.path.isfile("assets/player/Sanic Boule.png"):
|
||||
self.jump_frames.append(
|
||||
pygame.transform.scale(
|
||||
pygame.image.load(
|
||||
"assets/player/Sanic Boule.png"
|
||||
).convert_alpha(),
|
||||
(120, 120),
|
||||
)
|
||||
)
|
||||
|
||||
# Load dash animation sprite sheet
|
||||
if os.path.isfile("assets/player/Sanic Boule Annimate.png"):
|
||||
dash_sheet = pygame.image.load(
|
||||
"assets/player/Sanic Boule Annimate.png"
|
||||
).convert_alpha()
|
||||
|
||||
# Extract the frames with 2000px gap
|
||||
dash_frame_height = dash_sheet.get_height()
|
||||
|
||||
for i in range(4): # Assuming 4 frames
|
||||
frame = dash_sheet.subsurface(
|
||||
(i * 2000, 0, dash_frame_height, dash_frame_height)
|
||||
)
|
||||
frame = pygame.transform.scale(frame, (120, 120))
|
||||
self.dash_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
|
||||
):
|
||||
current_time = time.time()
|
||||
|
||||
# Priority: Dashing > Jumping > Moving > Static
|
||||
if self.dashing and self.dash_frames:
|
||||
if current_time - self.last_update > self.animation_speed:
|
||||
self.current_frame = (self.current_frame + 1) % len(self.dash_frames)
|
||||
self.surf = self.dash_frames[self.current_frame]
|
||||
self.last_update = current_time
|
||||
elif self.jumping and self.jump_frames:
|
||||
self.surf = self.jump_frames[0] # Use jump frame
|
||||
elif self.moving and self.animation_frames:
|
||||
if current_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
|
||||
self.last_update = current_time
|
||||
elif self.static_image:
|
||||
self.surf = self.static_image
|
||||
|
||||
def dash(self, acc):
|
||||
self.acc.x = 5 * acc
|
||||
self.dashing = True # Set dashing flag
|
||||
|
||||
def move(self):
|
||||
self.acc = vec(0, 1) # Gravity
|
||||
|
||||
# Reset moving flag
|
||||
# Reset flags
|
||||
self.moving = False
|
||||
self.dashing = 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
|
||||
self.moving = True
|
||||
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
|
||||
self.moving = True
|
||||
if pressed_keys[K_a]:
|
||||
self.dash(ACC)
|
||||
|
||||
@@ -163,7 +203,7 @@ class Player(pygame.sprite.Sprite):
|
||||
self.jumping = False
|
||||
|
||||
|
||||
class platform(pygame.sprite.Sprite):
|
||||
class Platform(pygame.sprite.Sprite):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.surf = pygame.Surface((WIDTH, 20))
|
||||
@@ -171,41 +211,59 @@ class platform(pygame.sprite.Sprite):
|
||||
self.rect = self.surf.get_rect(center=(WIDTH / 2, HEIGHT - 10))
|
||||
|
||||
|
||||
PT1 = platform()
|
||||
P1 = Player()
|
||||
platforms = pygame.sprite.Group()
|
||||
platforms.add(PT1)
|
||||
all_sprites = pygame.sprite.Group()
|
||||
all_sprites.add(PT1)
|
||||
all_sprites.add(P1)
|
||||
def initialize_game():
|
||||
global platforms, all_sprites
|
||||
|
||||
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:
|
||||
# Clear previous sprites if any
|
||||
platforms.empty()
|
||||
all_sprites.empty()
|
||||
|
||||
# Create new game objects
|
||||
PT1 = Platform()
|
||||
P1 = Player()
|
||||
|
||||
# Add them to the groups
|
||||
platforms.add(PT1)
|
||||
all_sprites.add(PT1)
|
||||
all_sprites.add(P1)
|
||||
|
||||
return P1, PT1, platforms, all_sprites
|
||||
|
||||
|
||||
def run_game(P1, all_sprites):
|
||||
"""Run the main game loop without menu system"""
|
||||
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))
|
||||
displaysurface.fill((0, 0, 0))
|
||||
|
||||
P1.move()
|
||||
P1.update()
|
||||
for entity in all_sprites:
|
||||
displaysurface.blit(entity.surf, entity.rect)
|
||||
P1.move()
|
||||
P1.update()
|
||||
for entity in all_sprites:
|
||||
displaysurface.blit(entity.surf, entity.rect)
|
||||
|
||||
# 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 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))
|
||||
# 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)
|
||||
pygame.display.update()
|
||||
FramePerSec.tick(FPS)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
P1, PT1, platforms, all_sprites = initialize_game()
|
||||
run_game(P1, all_sprites)
|
||||
Reference in New Issue
Block a user