diff --git a/src/engine/menu_manager.py b/src/engine/menu_manager.py index b5463ef..5065549 100644 --- a/src/engine/menu_manager.py +++ b/src/engine/menu_manager.py @@ -149,7 +149,7 @@ class MenuManager: motion_callback=widget.set_value) def hide(self): - """Affiche le menu actuelement à l'écran.""" + """Cache le menu actuelement à l'écran.""" # On itère dans tous les bouttons pour retirer l'interaction for widget in self.active_menu.widgets: if isinstance(widget, Button): diff --git a/src/engine/renderer.py b/src/engine/renderer.py index 457fca5..ebfbd33 100644 --- a/src/engine/renderer.py +++ b/src/engine/renderer.py @@ -1,6 +1,8 @@ import math import random +from time import time_ns +from types import FunctionType from pygame import display, image, surface, transform, draw, font from pygame.locals import RESIZABLE, SRCALPHA, FULLSCREEN @@ -15,6 +17,7 @@ class Renderer: def __init__(self, core: 'engine.Engine'): self.engine = core + self.timer = 0 # Timer local self.window_type = RESIZABLE self.window_size = (display.Info().current_w, display.Info().current_h) if self.window_type == FULLSCREEN else ( 600, 600) @@ -37,6 +40,24 @@ class Renderer: # Particules affichées self.particles = [] + # Varialbes du fadeout + self.fadeout_timer = 0 # Timer de fadeout + self.fadeout_is_fading = False + self.fadeout_fade_in_s = 0 + self.fadeout_fade_color = (255, 255, 255) + self.fadeout_fade_opacity = 100 + self.fadeout_pause = False + self.fadeout_fade_callback = None + + # Variables du fadein + self.fadein_timer = 0 # Timer de fadein + self.fadein_is_fading = False + self.fadein_fade_in_s = 0 + self.fadein_fade_color = (255, 255, 255) + self.fadein_fade_opacity = 100 + self.fadein_pause = False + self.fadein_fade_callback = None + def emit_particles(self, x: int, y: int, w: int, h: int, count: int, min_size: int, max_size: int, min_speed: float, max_speed: float, min_life_time: float, max_life_time: float, color: tuple[int, int, int]): @@ -80,18 +101,40 @@ class Renderer: def update(self, delta: float): """Fait le rendu du jeu.""" + self.timer -= delta + self.fadeout_timer -= delta + self.fadein_timer -= delta + + if self.fadeout_timer < 0: + if self.fadeout_is_fading: + self.fadeout_is_fading = False + if self.fadeout_pause: + self.engine.entity_manager.resume() + self.fadeout_pause = False + if self.fadeout_fade_callback is not None: + self.fadeout_fade_callback() + + if self.fadein_timer < 0: + if self.fadein_is_fading: + self.fadein_is_fading = False + if self.fadein_pause: + self.engine.entity_manager.resume() + self.fadein_pause = False + if self.fadein_fade_callback is not None: + self.fadein_fade_callback() + self.window.fill((255, 255, 255)) + # On crée une surface qui sera ajoutée à la fenêtre apres rendered_surface pour pouvoir mettre des GUI + gui_surface = surface.Surface(display.get_window_size(), SRCALPHA) + gui_surface.fill((0, 0, 0, 0)) + if self.engine.game_state == GameState.NORMAL: # On crée une surface temporaire qui nous permettra de faire le rendu à l'échelle 1:1 rendered_surface_size = (display.get_window_size()[0] / self.engine.camera.zoom, display.get_window_size()[1] / self.engine.camera.zoom) rendered_surface = surface.Surface(rendered_surface_size) - # On crée une surface qui sera ajoutée à la fenêtre apres rendered_surface pour pouvoir mettre des GUI - gui_surface = surface.Surface(display.get_window_size(), SRCALPHA) - gui_surface.fill((0, 0, 0, 0)) - self.render_layer(0, rendered_surface) self.render_layer(1, rendered_surface) self.render_entities(rendered_surface, gui_surface, delta) @@ -105,7 +148,6 @@ class Renderer: math.ceil(rendered_surface_size[1] * self.engine.camera.zoom))), (0, 0)) - self.window.blit(gui_surface, (0, 0)) elif self.engine.game_state == GameState.BOSS_FIGHT: self.window.fill((255, 230, 230)) @@ -115,6 +157,19 @@ class Renderer: # Rend les menus self.render_menus() + if self.fadeout_is_fading != self.fadein_is_fading: + if self.fadeout_is_fading: + r, g, b = self.fadeout_fade_color + a = (1 - self.fadeout_timer / self.fadeout_fade_in_s) * self.fadeout_fade_opacity + gui_surface.fill((r, g, b, a)) + + if self.fadein_is_fading: + r, g, b = self.fadein_fade_color + a = self.fadein_timer / self.fadein_fade_in_s * self.fadein_fade_opacity + gui_surface.fill((r, g, b, a)) + + self.window.blit(gui_surface, (0, 0)) + # Conteur de FPS en mode DEBUG if self.engine.DEBUG_MODE: self.window.blit(font.SysFont("Arial", 20).render(f"FPS: {round(self.engine.clock.get_fps())}, Game Status: {'Paused' if self.engine.entity_manager.paused else 'Playing'}", True, (255, 0, 0)), @@ -581,3 +636,27 @@ class Renderer: (math.floor(x * self.tile_size - self.engine.camera.x + x_middle_offset), math.floor(y * self.tile_size - self.engine.camera.y + y_middle_offset), self.tile_size, self.tile_size), width=1) + + def fadeout(self, fade_s: float, fade_color: tuple[int, int, int] = (0, 0, 0), fade_opacity: int = 100, pause_world: bool = True, callback: FunctionType = None): + """Fait un fondu vers la couleur au format : (255, 255, 255) et a l'opacité max spécifié, et dans le temps spécifié, appelle la fonction callback une fois le fadout terminé""" + self.fadein_is_fading = False + self.fadeout_timer = fade_s + self.fadeout_fade_in_s = fade_s + self.fadeout_is_fading = True + self.fadeout_fade_color = fade_color + self.fadeout_fade_opacity = round(fade_opacity * 255 / 100) + self.fadeout_pause = pause_world + self.fadeout_fade_callback = callback + self.engine.entity_manager.pause() + + def fadein(self, fade_s: float, fade_color: tuple[int, int, int] = (0, 0, 0), fade_opacity: int = 100, pause_world: bool = True, callback: FunctionType = None): + """Fait un fondu depuis la couleur au format : (255, 255, 255) et depuis l'opacité spécifié, et dans le temps spécifié, appelle la fonction callback une fois le fadout terminé""" + self.fadeout_is_fading = False + self.fadein_timer = fade_s + self.fadein_fade_in_s = fade_s + self.fadein_is_fading = True + self.fadein_fade_color = fade_color + self.fadein_fade_opacity = round(fade_opacity * 255 / 100) + self.fadein_pause = pause_world + self.fadein_fade_callback = callback + self.engine.entity_manager.pause() \ No newline at end of file diff --git a/src/main.py b/src/main.py index 33e0a31..9effaca 100644 --- a/src/main.py +++ b/src/main.py @@ -33,6 +33,10 @@ class Game(Engine): def start_game(self): self.game_state = GameState.NORMAL + self.renderer.fadein(1, (0, 0, 0), 100, True) + + def play_button_callback(self): + self.renderer.fadeout(1, (0, 0, 0), 100, True, self.start_game) self.menu_manager.hide() def setup_main_menu(self): @@ -47,7 +51,7 @@ class Game(Engine): slider_hover_image = pygame.image.load("assets/textures/GUI/slider_cursor_2.png").convert_alpha() slider_rail_image = pygame.image.load("assets/textures/GUI/slider_rail_1.png").convert_alpha() - menu.add_widget(Button(0.5, 0.3, "play", 0.08, (0, 0, 0), self.start_game, btn_base_image, btn_hover_image, "play_button", True, 0)) + menu.add_widget(Button(0.5, 0.3, "play", 0.08, (0, 0, 0), self.play_button_callback, btn_base_image, btn_hover_image, "play_button", True, 0)) self.menu_manager.register_menu(menu, "main")