From 00e72f4367d1da31d80cfbf1804f3fe18c5ce6ab Mon Sep 17 00:00:00 2001 From: Yannis300307 Date: Fri, 5 Jan 2024 17:00:30 +0100 Subject: [PATCH 01/37] Ajout d'une zone d'execution d'events --- src/engine/engine.py | 3 +++ src/engine/event_sheduler.py | 21 +++++++++++++++++++-- src/main.py | 4 +++- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/engine/engine.py b/src/engine/engine.py index 2d1dc8d..ddea6c6 100644 --- a/src/engine/engine.py +++ b/src/engine/engine.py @@ -2,6 +2,7 @@ from src.engine.boss_fight_manager import BossFightManager from src.engine.camera import Camera from src.engine.entity_manager import EntityManager from src.engine.event_handler import EventHandler +from src.engine.event_sheduler import EventSheduler from src.engine.map_manager import MapManager from src.engine.renderer import Renderer from src.engine.enums import GameState @@ -31,6 +32,7 @@ class Engine: self.camera = Camera() self.entity_manager = EntityManager(self.map_manager) self.boss_fight_manager = BossFightManager(self) + self.event_sheduler = EventSheduler(self) def loop(self): """Fonction à lancer au début du programme et qui va lancer les updates dans une boucle. @@ -47,6 +49,7 @@ class Engine: self.entity_manager.update(0.016666666) self.renderer.update(0.016666666) self.event_handler.update() + self.event_sheduler.update() def stop(self): """Arrête le programme.""" diff --git a/src/engine/event_sheduler.py b/src/engine/event_sheduler.py index c72456a..1056eb3 100644 --- a/src/engine/event_sheduler.py +++ b/src/engine/event_sheduler.py @@ -1,14 +1,31 @@ from types import FunctionType +import src.engine.engine + class EventSheduler: """Gère le lancement d'évenements avec des conditions.""" - def __init__(self): + def __init__(self, engine: 'src.engine.engine.Engine'): self.area_callbacks = [] + self.engine = engine def register_area(self, area_rect: tuple[int, int, int, int], callback: FunctionType | classmethod | staticmethod): self.area_callbacks.append((area_rect, callback)) + @staticmethod + def get_collisions_with_entity(rect: tuple[int, int, int, int], entity: 'Entity'): + """Retourne True si l'entité donnée touche le rectange donné.""" + return (rect[0] <= entity.x+entity.collision_rect[2] and + rect[0] + rect[2] >= entity.x+entity.collision_rect[0] and + rect[1] + rect[3] >= entity.y+entity.collision_rect[1] and + rect[1] <= entity.y+entity.collision_rect[3]) + def update(self): for area in self.area_callbacks: - area_rect = area[0] \ No newline at end of file + area_rect = area[0] + + if self.get_collisions_with_entity(area_rect, self.engine.entity_manager.get_by_name("player")): + print("oui") + + else: + print("non") diff --git a/src/main.py b/src/main.py index 5287bd9..cacd8eb 100644 --- a/src/main.py +++ b/src/main.py @@ -17,10 +17,12 @@ class Game(Engine): self.load_boss_fight_assets() self.spawn_mobs() - self.DEBUG_MODE = False + self.DEBUG_MODE = True self.game_state = GameState.NORMAL + self.event_sheduler.register_area((0, 20, 20, 20), None) + def create_player_entity(self): """Crée une entité joueur.""" anim = Anim(0.5) From b424bf7aa2bc460ee05eceeff8a33fd633a39701 Mon Sep 17 00:00:00 2001 From: Yannis300307 Date: Fri, 5 Jan 2024 18:37:05 +0100 Subject: [PATCH 02/37] =?UTF-8?q?Link=20d'entit=C3=A9s=20=C3=A0=20l'event?= =?UTF-8?q?=20sheduler?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/engine/event_sheduler.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/engine/event_sheduler.py b/src/engine/event_sheduler.py index 1056eb3..561d19f 100644 --- a/src/engine/event_sheduler.py +++ b/src/engine/event_sheduler.py @@ -1,6 +1,7 @@ from types import FunctionType import src.engine.engine +from src.engine.entity import Entity class EventSheduler: @@ -9,8 +10,9 @@ class EventSheduler: self.area_callbacks = [] self.engine = engine - def register_area(self, area_rect: tuple[int, int, int, int], callback: FunctionType | classmethod | staticmethod): - self.area_callbacks.append((area_rect, callback)) + def register_area(self, area_rect: tuple[int, int, int, int], callback: FunctionType | classmethod | staticmethod, + linked_entities_name: list[Entity]): + self.area_callbacks.append((area_rect, callback, linked_entities_name)) @staticmethod def get_collisions_with_entity(rect: tuple[int, int, int, int], entity: 'Entity'): @@ -21,11 +23,11 @@ class EventSheduler: rect[1] <= entity.y+entity.collision_rect[3]) def update(self): + """Met à jour l'event sheluder et execute les actions si les conditions à son execution sont respéctées.""" + + # On itère dans la liste des zones de détection for area in self.area_callbacks: - area_rect = area[0] - - if self.get_collisions_with_entity(area_rect, self.engine.entity_manager.get_by_name("player")): - print("oui") - - else: - print("non") + # On itère dans toutes les entités enregistrées + for entity in area[2]: + if self.get_collisions_with_entity(area[0], self.engine.entity_manager.get_by_name(entity)): + area[1](entity) From 4a88bb4f8fc9b6cb5112c52561b2745ccdc57273 Mon Sep 17 00:00:00 2001 From: Yannis300307 Date: Fri, 5 Jan 2024 18:37:53 +0100 Subject: [PATCH 03/37] =?UTF-8?q?Ajout=20du=20rendu=20des=20zones=20de=20d?= =?UTF-8?q?etection=20d'entit=C3=A9s=20dans=20le=20renderer=20en=20mode=20?= =?UTF-8?q?DEBUG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/engine/renderer.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/engine/renderer.py b/src/engine/renderer.py index 39f1393..0189465 100644 --- a/src/engine/renderer.py +++ b/src/engine/renderer.py @@ -98,6 +98,7 @@ class Renderer: self.render_entities(rendered_surface, gui_surface, delta) self.render_particles(rendered_surface, delta) self.render_layer(2, rendered_surface) + self.render_debug_area(rendered_surface) # Enfin, on redimensionne notre surface et on la colle sur la fenêtre principale self.window.blit( @@ -125,6 +126,20 @@ class Renderer: # Apres avoir tout rendu, on met à jour l'écran display.update() + def render_debug_area(self, rendered_surface: surface.Surface): + """Rend les zones de collisions et de détections quand le mode DEBUG est activé.""" + + # On calcule le décalage pour centrer la caméra + x_middle_offset = display.get_window_size()[0] / 2 / self.engine.camera.zoom + y_middle_offset = display.get_window_size()[1] / 2 / self.engine.camera.zoom + + for area in self.engine.event_sheduler.area_callbacks: + area_rect = area[0] + draw.rect(rendered_surface, (200, 100, 0), + (math.floor(x_middle_offset+area_rect[0]-self.engine.camera.x), + math.floor(y_middle_offset+area_rect[1]-self.engine.camera.y), + math.floor(area_rect[2]), math.floor(area_rect[3])), width=1) + def register_shadow(self, file_path: str, name: str): """Enregistre une image d'ombre utilisée pour le rendu des entités.""" shadow = image.load(file_path).convert_alpha() From 011c7f4895fe7d083c0ae556686e9d6c3aeb634f Mon Sep 17 00:00:00 2001 From: Yannis300307 Date: Fri, 5 Jan 2024 19:17:50 +0100 Subject: [PATCH 04/37] Ajout de la lecture des dialogues --- assets/dialogs.json | 4 ++++ src/engine/dialogs_manager.py | 21 +++++++++++++++++++-- src/engine/engine.py | 2 ++ src/main.py | 1 + 4 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 assets/dialogs.json diff --git a/assets/dialogs.json b/assets/dialogs.json new file mode 100644 index 0000000..4c15f5f --- /dev/null +++ b/assets/dialogs.json @@ -0,0 +1,4 @@ +{ + "test": ["test1", "test2", "test très long permettant de tester le retour à la ligne dans le renderer du jeu dans la fonction qui rend les dialogues et il faut éviter d'en faire des si long car ça pourrait dépacer en base de l'écran ! Bonne journée !"], + "test2": ["salut", "aurevoir"] +} \ No newline at end of file diff --git a/src/engine/dialogs_manager.py b/src/engine/dialogs_manager.py index bf15837..ecc94f9 100644 --- a/src/engine/dialogs_manager.py +++ b/src/engine/dialogs_manager.py @@ -4,10 +4,27 @@ import json class DialogsManager: """Classe qui gère la lecture des dialogues.""" def __init__(self): - self.current_dialog = [] + self.current_dialogs = [] + self.current_dialog_id = -1 self.dialogs = {} + def next_dialog(self): + """Passe au dialogue suivant. Renvoie True si le dialogue est fini.""" + self.current_dialog_id += 1 + if self.current_dialog_id == len(self.current_dialogs): + self.current_dialogs = [] + self.current_dialog_id = -1 + + def start_dialog(self, name: str): + """Lance le dialogue au nom donné.""" + self.current_dialogs = self.dialogs[name] + self.current_dialog_id = 0 + + def get_current_dialog_sentence(self) -> str: + """Renvoie la phrase actuelle du dialogue.""" + return self.current_dialogs[self.current_dialog_id] + def load_dialogs(self, file_path: str): """Charge les dialogues du jeu grave au fichier json donné.""" - with open(file_path, "r") as file: + with open(file_path, "r", encoding="utf-8") as file: self.dialogs = json.loads(file.read()) diff --git a/src/engine/engine.py b/src/engine/engine.py index ddea6c6..ca07190 100644 --- a/src/engine/engine.py +++ b/src/engine/engine.py @@ -1,5 +1,6 @@ from src.engine.boss_fight_manager import BossFightManager from src.engine.camera import Camera +from src.engine.dialogs_manager import DialogsManager from src.engine.entity_manager import EntityManager from src.engine.event_handler import EventHandler from src.engine.event_sheduler import EventSheduler @@ -33,6 +34,7 @@ class Engine: self.entity_manager = EntityManager(self.map_manager) self.boss_fight_manager = BossFightManager(self) self.event_sheduler = EventSheduler(self) + self.dialogs_manager = DialogsManager() def loop(self): """Fonction à lancer au début du programme et qui va lancer les updates dans une boucle. diff --git a/src/main.py b/src/main.py index cacd8eb..eb753e1 100644 --- a/src/main.py +++ b/src/main.py @@ -12,6 +12,7 @@ class Game(Engine): self.map_manager.load_new("maps/map5.tmj") self.renderer.load_tile_set("assets/textures/tileset.png", 16) + self.dialogs_manager.load_dialogs("assets/dialogs.json") self.create_player_entity() self.load_boss_fight_assets() From 2a47bb5d60c1dc788627df61db68bb8cfb65102e Mon Sep 17 00:00:00 2001 From: Yannis300307 Date: Fri, 5 Jan 2024 19:20:52 +0100 Subject: [PATCH 05/37] Ajout d'un locker de lancement de dialogue --- src/engine/dialogs_manager.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/engine/dialogs_manager.py b/src/engine/dialogs_manager.py index ecc94f9..bba5714 100644 --- a/src/engine/dialogs_manager.py +++ b/src/engine/dialogs_manager.py @@ -7,6 +7,7 @@ class DialogsManager: self.current_dialogs = [] self.current_dialog_id = -1 self.dialogs = {} + self.reading_dialog = False def next_dialog(self): """Passe au dialogue suivant. Renvoie True si le dialogue est fini.""" @@ -14,11 +15,17 @@ class DialogsManager: if self.current_dialog_id == len(self.current_dialogs): self.current_dialogs = [] self.current_dialog_id = -1 + self.reading_dialog = False def start_dialog(self, name: str): """Lance le dialogue au nom donné.""" - self.current_dialogs = self.dialogs[name] - self.current_dialog_id = 0 + if not self.reading_dialog: + self.current_dialogs = self.dialogs[name] + self.current_dialog_id = 0 + + print(self.current_dialogs) + + self.reading_dialog = True def get_current_dialog_sentence(self) -> str: """Renvoie la phrase actuelle du dialogue.""" From 879e6e8c0d39f50ce749ec0709f6ae88c2def2db Mon Sep 17 00:00:00 2001 From: Yannis300307 Date: Fri, 5 Jan 2024 19:57:24 +0100 Subject: [PATCH 06/37] =?UTF-8?q?D=C3=A9but=20de=20rendu=20de=20dialogues?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/dialogs.json | 2 +- assets/textures/GUI/dialogs_box.png | Bin 0 -> 5711 bytes src/engine/dialogs_manager.py | 24 +++++++++++- src/engine/engine.py | 1 + src/engine/renderer.py | 57 ++++++++++++++++++++-------- src/main.py | 8 ++-- 6 files changed, 71 insertions(+), 21 deletions(-) create mode 100644 assets/textures/GUI/dialogs_box.png diff --git a/assets/dialogs.json b/assets/dialogs.json index 4c15f5f..7d8409b 100644 --- a/assets/dialogs.json +++ b/assets/dialogs.json @@ -1,4 +1,4 @@ { - "test": ["test1", "test2", "test très long permettant de tester le retour à la ligne dans le renderer du jeu dans la fonction qui rend les dialogues et il faut éviter d'en faire des si long car ça pourrait dépacer en base de l'écran ! Bonne journée !"], + "test": ["test1111", "test2", "test très long permettant de tester le retour à la ligne dans le renderer du jeu dans la fonction qui rend les dialogues et il faut éviter d'en faire des si long car ça pourrait dépacer en base de l'écran ! Bonne journée !"], "test2": ["salut", "aurevoir"] } \ No newline at end of file diff --git a/assets/textures/GUI/dialogs_box.png b/assets/textures/GUI/dialogs_box.png new file mode 100644 index 0000000000000000000000000000000000000000..2e7b56a79847fcbbecf85610743c346a3431cab2 GIT binary patch literal 5711 zcmeHLi&GOv7+(-gP^mB(r3FKDC~7OHts_VwyhM>Asik7D0YWVn&5=h7hDbnSu`mo( ztl0VhiGm6h3RXBk0Xd68tvs}ZWH=szl=AXOB9LH%NrQLbpJ1nxow?cD@AvI~-|g65t0)TUU-48x}FX!M*_e znzdx+i-pFvrC{g2H~`-IZT2x+zV2fQ0L%Xh^!ME(io|*%hVu?no79Hzj7tZ(zB|qx zA9Oek+cb|}Ngwnj(SJA-e<_;ed)Jv0FQY74nCcvR%qCwbr-T&-(XVsA+Zx@{LUkd3 zT4i@8!$GD^=u!Aw$?i!pD3rIoYa>EdADn zIB@5-<^-xoL+A06`cPdUMuL|Z@$(S40}J^W+CRJ2#g{-&Kdb^t+p*oh zBtL%#$D&%%wU_I|#a~yqAi3tMpHL;Fr15YJOlS+yCeBbAD<;koanXB)h_!+RI2J~2 zf^?i7N7YJmf$rG^jng|byK9VPZ>X3u-2j(LQ+qx0=sir`^ivxgiE@fyiXp7OUmmCg zNf4&X48Q@&kClbOo5KCohaXK)9x)Y+j#BEJ55>w(^aQ-5fxDmn1nBo-1@oQAO!q`im4?y?wuf8y8rdIl%cNx)^|;(8U$a7WF|+B=RN{hZ5mzzi z*s9hHG&r+qWRi@y$y%Kq&Q@s`)W|Ch)g_Gpv0&rN~rJx#iFtEx_#eE4AYSOwp6ZM!2-QroU34L#Dsh5VX; zdClgLHoXc-NJ&(PSZK?D`*{bc#4Cg~x^c9;4Y!P(VWe={?mA|9e$cz2QwohG`f5U^ z$Vf_A-2t`e5U*avR@>sL=VaRyu^(;qio71f34$LVn3}ejl&dXpaA)O#SAMX)@^Aro zu!dhiH{V3G?0o>SU&yNgvC7A-C1yD6M@9&})fQ3so5XsquMgSmZCtkMI9Q6mS^JrW zGtJ$ryHTDEP4mOvk6`Ut#*s;=y3LRG4m1rt2ae3#O~KDX%akQFtu8sRWd6 zt_m8k#Ca6yNLqNwH;$teJ*f0yguEY&^>9(Q7H0g zJj$q%O?iRV&C@LF(mB~pPp&EKk(Mp+XRzC{Ig+JA8;&)i-sxTU66?&m!;3JsCt)X{cg<-kKTCnD6vEeCrgmfF_rIjkz0HyzFNXsl!504=1Wd$1_xH8NNGIk)Qq=;{qxIh6)C3*8mw^NqqbBux@S&zH9G+}TStLzgDWma zx?kpNE~Cy*`I`$tcWqcrfsloDY6xxvY4&95!ZFR~3d4l9!!>KDyMiBWsFmxJ#GJA+ z!t& ~J<&$@G67J(m+a;2y(**hR2gYCo^<-@jrF str: + def get_current_dialog_sentence(self, progressive=True) -> str: """Renvoie la phrase actuelle du dialogue.""" - return self.current_dialogs[self.current_dialog_id] + if progressive: + return self.current_dialogs[self.current_dialog_id][:self.current_dialogue_letter_id] + else: + return self.current_dialogs[self.current_dialog_id] def load_dialogs(self, file_path: str): """Charge les dialogues du jeu grave au fichier json donné.""" with open(file_path, "r", encoding="utf-8") as file: self.dialogs = json.loads(file.read()) + + def update(self, delta: float): + """Met à jour e gestionnaire de dialogues.""" + if self.reading_dialog: + self.letter_timer -= delta + + if self.letter_timer <= 0: + self.letter_timer = self.LETTER_WRITTING_DELAY + self.current_dialogue_letter_id += 1 + if self.current_dialogue_letter_id > len(self.current_dialogs[self.current_dialog_id]): + self.current_dialogue_letter_id -= 1 + + print(self.get_current_dialog_sentence()) \ No newline at end of file diff --git a/src/engine/engine.py b/src/engine/engine.py index ca07190..69fb4b2 100644 --- a/src/engine/engine.py +++ b/src/engine/engine.py @@ -52,6 +52,7 @@ class Engine: self.renderer.update(0.016666666) self.event_handler.update() self.event_sheduler.update() + self.dialogs_manager.update(0.016666666) def stop(self): """Arrête le programme.""" diff --git a/src/engine/renderer.py b/src/engine/renderer.py index 0189465..2dad103 100644 --- a/src/engine/renderer.py +++ b/src/engine/renderer.py @@ -15,7 +15,8 @@ class Renderer: def __init__(self, core: 'engine.Engine'): self.engine = core self.window_type = RESIZABLE - self.window_size = (display.Info().current_w, display.Info().current_h) if self.window_type == FULLSCREEN else (600, 600) + self.window_size = (display.Info().current_w, display.Info().current_h) if self.window_type == FULLSCREEN else ( + 600, 600) self.window = display.set_mode(self.window_size, self.window_type) self.tiles = [] self.tile_size = 0 @@ -26,6 +27,9 @@ class Renderer: self.boss_fight_player_animations: dict[str: Anim] = {} self.boss_fight_GUI_container = None + # Boite de dialogue + self.dialogs_box = None + # Variables utilisées par le menu principal self.main_menu_assets: dict[str: Anim] = {} @@ -54,8 +58,8 @@ class Renderer: part_speed_y = - part_speed_y # On choisit sa position dans le rectangle - part_x = random.randint(x-w, x+w-part_size) - part_y = random.randint(y-h, y+h-part_size) + part_x = random.randint(x - w, x + w - part_size) + part_y = random.randint(y - h, y + h - part_size) # On choisit la durée de vie part_life_time = random.uniform(min_life_time, max_life_time) @@ -123,9 +127,28 @@ class Renderer: self.window.blit(font.SysFont("Arial", 20).render(f"Zoom: {self.engine.camera.zoom}", True, (255, 0, 0)), (0, 60)) + # Rendu présent dans tous les types de jeu + self.render_dialogs_box() + # Apres avoir tout rendu, on met à jour l'écran display.update() + def render_dialogs_box(self): + """Rend la boite de dialogue lorsqu'un dialogue est lancé.""" + + # Rend le conteneur des dialogues + if self.engine.dialogs_manager.reading_dialog: + resized_box = transform.scale(self.dialogs_box, + (display.get_window_size()[0], + self.dialogs_box.get_height() / self.dialogs_box.get_width() * + display.get_window_size()[0])) + self.window.blit(resized_box, (0, display.get_window_size()[1] - resized_box.get_height())) + + # Rend le texte + text_font = font.SysFont("Arial", display.get_window_size()[0]//20) + rendered_text = text_font.render(self.engine.dialogs_manager.get_current_dialog_sentence(), True, (0, 0, 0)) + self.window.blit(rendered_text, (display.get_window_size()[0]/30, display.get_window_size()[1] - resized_box.get_height()+display.get_window_size()[0]/30)) + def render_debug_area(self, rendered_surface: surface.Surface): """Rend les zones de collisions et de détections quand le mode DEBUG est activé.""" @@ -136,9 +159,9 @@ class Renderer: for area in self.engine.event_sheduler.area_callbacks: area_rect = area[0] draw.rect(rendered_surface, (200, 100, 0), - (math.floor(x_middle_offset+area_rect[0]-self.engine.camera.x), - math.floor(y_middle_offset+area_rect[1]-self.engine.camera.y), - math.floor(area_rect[2]), math.floor(area_rect[3])), width=1) + (math.floor(x_middle_offset + area_rect[0] - self.engine.camera.x), + math.floor(y_middle_offset + area_rect[1] - self.engine.camera.y), + math.floor(area_rect[2]), math.floor(area_rect[3])), width=1) def register_shadow(self, file_path: str, name: str): """Enregistre une image d'ombre utilisée pour le rendu des entités.""" @@ -184,8 +207,8 @@ class Renderer: frame = transform.scale(frame, (display.get_window_size()[0] / 5, display.get_window_size()[0] / 5)) # On colle le boss à droite de la fenêtre - self.window.blit(frame, (display.get_window_size()[0]-frame.get_width()-display.get_window_size()[0]/20, - display.get_window_size()[1]/4-frame.get_height()/2)) + self.window.blit(frame, (display.get_window_size()[0] - frame.get_width() - display.get_window_size()[0] / 20, + display.get_window_size()[1] / 4 - frame.get_height() / 2)) # On récupère l'image de l'animation du joueur player_animation = self.boss_fight_player_animations[self.engine.boss_fight_manager.current_player_animation] @@ -195,14 +218,17 @@ class Renderer: frame = transform.scale(frame, (display.get_window_size()[0] / 5, display.get_window_size()[0] / 5)) # On colle le joueur à gauche de la fenêtre - self.window.blit(frame, (display.get_window_size()[0]/20, display.get_window_size()[1]/4-frame.get_height()/2)) + self.window.blit(frame, + (display.get_window_size()[0] / 20, display.get_window_size()[1] / 4 - frame.get_height() / 2)) def render_boss_fight_gui(self): """Rend la barre d'action en bas de l'écran pendant le combat de boss.""" resized_container = transform.scale(self.boss_fight_GUI_container, - (display.get_window_size()[0], self.boss_fight_GUI_container.get_height()/self.boss_fight_GUI_container.get_width()*display.get_window_size()[0])) - self.window.blit(resized_container, (0, display.get_window_size()[1]-resized_container.get_height())) + (display.get_window_size()[0], + self.boss_fight_GUI_container.get_height() / self.boss_fight_GUI_container.get_width() * + display.get_window_size()[0])) + self.window.blit(resized_container, (0, display.get_window_size()[1] - resized_container.get_height())) def render_entities(self, rendered_surface: surface.Surface, gui_surface: surface.Surface, delta: float): """Rend toutes les entités.""" @@ -250,10 +276,11 @@ class Renderer: cooldown_value = entity.damage_cooldown / entity.default_damage_cooldown # On calcule où placer la barre de vei sur la surface des GUI - life_bar_dest = (math.floor((entity.x - self.engine.camera.x + x_middle_offset) * self.engine.camera.zoom - - life_bar_width / 2), - math.floor((entity.y - self.engine.camera.y + y_middle_offset - frame.get_height() / 2) * - self.engine.camera.zoom - life_bar_height - life_bar_y_offset)) + life_bar_dest = ( + math.floor((entity.x - self.engine.camera.x + x_middle_offset) * self.engine.camera.zoom - + life_bar_width / 2), + math.floor((entity.y - self.engine.camera.y + y_middle_offset - frame.get_height() / 2) * + self.engine.camera.zoom - life_bar_height - life_bar_y_offset)) # Contour de la barre de vie draw.rect(gui_surface, (20, 0, 0), (life_bar_dest[0] - life_bar_border, diff --git a/src/main.py b/src/main.py index eb753e1..90af9f2 100644 --- a/src/main.py +++ b/src/main.py @@ -22,7 +22,9 @@ class Game(Engine): self.game_state = GameState.NORMAL - self.event_sheduler.register_area((0, 20, 20, 20), None) + self.event_sheduler.register_area((64, 64, 32, 32), lambda _: self.dialogs_manager.start_dialog("test"), ["player"]) + + self.renderer.dialogs_box = pygame.image.load("assets/textures/GUI/dialogs_box.png").convert_alpha() def create_player_entity(self): """Crée une entité joueur.""" @@ -64,7 +66,7 @@ class Game(Engine): mob.set_default_life(5) mob.max_speed = 1. - mob.x, mob.y = 160, 16 + mob.x, mob.y = 1600, 16 def load_boss_fight_assets(self): """Charge les animations de combat des combats de boss.""" @@ -75,7 +77,7 @@ class Game(Engine): boss_none.load_animation_from_directory("assets/textures/boss_fight/boss_sprite/test/none") self.renderer.register_boss_fight_boss_animation(boss_none, "none") - self.renderer.boss_fight_GUI_container = pygame.image.load("assets/textures/boss_fight/fight_actions_GUI.png") + self.renderer.boss_fight_GUI_container = pygame.image.load("assets/textures/boss_fight/fight_actions_GUI.png").convert_alpha() game = Game() From 70d1a136cea49bc32e56a6acd2e82eaccb0f238e Mon Sep 17 00:00:00 2001 From: Yannis300307 Date: Sat, 6 Jan 2024 14:30:32 +0100 Subject: [PATCH 07/37] Rendu des dialogues --- assets/dialogs.json | 3 ++- src/engine/dialogs_manager.py | 5 +---- src/engine/renderer.py | 9 +++++++-- src/main.py | 2 +- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/assets/dialogs.json b/assets/dialogs.json index 7d8409b..7386710 100644 --- a/assets/dialogs.json +++ b/assets/dialogs.json @@ -1,4 +1,5 @@ { "test": ["test1111", "test2", "test très long permettant de tester le retour à la ligne dans le renderer du jeu dans la fonction qui rend les dialogues et il faut éviter d'en faire des si long car ça pourrait dépacer en base de l'écran ! Bonne journée !"], - "test2": ["salut", "aurevoir"] + "test2": ["salut", "aurevoir"], + "test3": ["test très long permettant de tester le retour à la ligne dans le renderer du jeu dans la fonction qui rend les dialogues et il faut éviter d'en faire des si long car ça pourrait dépacer en base de l'écran ! Bonne journée !"] } \ No newline at end of file diff --git a/src/engine/dialogs_manager.py b/src/engine/dialogs_manager.py index a2d4dba..7da187b 100644 --- a/src/engine/dialogs_manager.py +++ b/src/engine/dialogs_manager.py @@ -10,7 +10,7 @@ class DialogsManager: self.reading_dialog = False self.current_dialogue_letter_id = 0 - self.LETTER_WRITTING_DELAY = 0.5 + self.LETTER_WRITTING_DELAY = 0.01 self.letter_timer = 0 def next_dialog(self): @@ -27,8 +27,6 @@ class DialogsManager: self.current_dialogs = self.dialogs[name] self.current_dialog_id = 0 - print(self.current_dialogs) - self.reading_dialog = True def get_current_dialog_sentence(self, progressive=True) -> str: @@ -54,4 +52,3 @@ class DialogsManager: if self.current_dialogue_letter_id > len(self.current_dialogs[self.current_dialog_id]): self.current_dialogue_letter_id -= 1 - print(self.get_current_dialog_sentence()) \ No newline at end of file diff --git a/src/engine/renderer.py b/src/engine/renderer.py index 2dad103..33a6333 100644 --- a/src/engine/renderer.py +++ b/src/engine/renderer.py @@ -145,8 +145,13 @@ class Renderer: self.window.blit(resized_box, (0, display.get_window_size()[1] - resized_box.get_height())) # Rend le texte - text_font = font.SysFont("Arial", display.get_window_size()[0]//20) - rendered_text = text_font.render(self.engine.dialogs_manager.get_current_dialog_sentence(), True, (0, 0, 0)) + + # On récupère le texte + sentence = self.engine.dialogs_manager.get_current_dialog_sentence() + + text_font = font.SysFont("Arial", display.get_window_size()[0]//30) + print(text_font.size(sentence)) + rendered_text = text_font.render(sentence, True, (0, 0, 0)) self.window.blit(rendered_text, (display.get_window_size()[0]/30, display.get_window_size()[1] - resized_box.get_height()+display.get_window_size()[0]/30)) def render_debug_area(self, rendered_surface: surface.Surface): diff --git a/src/main.py b/src/main.py index 90af9f2..820466f 100644 --- a/src/main.py +++ b/src/main.py @@ -22,7 +22,7 @@ class Game(Engine): self.game_state = GameState.NORMAL - self.event_sheduler.register_area((64, 64, 32, 32), lambda _: self.dialogs_manager.start_dialog("test"), ["player"]) + self.event_sheduler.register_area((64, 64, 32, 32), lambda _: self.dialogs_manager.start_dialog("test3"), ["player"]) self.renderer.dialogs_box = pygame.image.load("assets/textures/GUI/dialogs_box.png").convert_alpha() From d943e8f953a350b7882c4c936477f4eb836f8a97 Mon Sep 17 00:00:00 2001 From: yannis300307 Date: Sat, 6 Jan 2024 17:44:25 +0100 Subject: [PATCH 08/37] =?UTF-8?q?Ajout=20du=20retour=20=C3=A0=20la=20ligne?= =?UTF-8?q?=20dans=20le=20renderer=20pour=20les=20dialogues?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/engine/renderer.py | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/src/engine/renderer.py b/src/engine/renderer.py index 33a6333..563fd53 100644 --- a/src/engine/renderer.py +++ b/src/engine/renderer.py @@ -149,10 +149,41 @@ class Renderer: # On récupère le texte sentence = self.engine.dialogs_manager.get_current_dialog_sentence() + # On crée la font qui permettra de faire le rendu du texte après text_font = font.SysFont("Arial", display.get_window_size()[0]//30) - print(text_font.size(sentence)) - rendered_text = text_font.render(sentence, True, (0, 0, 0)) - self.window.blit(rendered_text, (display.get_window_size()[0]/30, display.get_window_size()[1] - resized_box.get_height()+display.get_window_size()[0]/30)) + + # On calcule la taille du décalage puis on calcule la largeur maximale que peut faire une ligne + x_border = display.get_window_size()[0]/30 + max_width = display.get_window_size()[0]-2*x_border + + # On passe le texte dans un algorithme qui coupe le texte entre les espaces pour empecher de dépacer la + # taille maximale de la ligne + lines = [] + current_line = "" + for i in sentence: + current_line += i + # Si on déplace de la ligne, on ajoute la ligne jusqu'au dernier mot + if text_font.size(current_line)[0] > max_width: + lines.append(current_line[:current_line.rfind(" ")]) + current_line = current_line[current_line.rfind(" "):] + + # Si la ligne est incomplète, on ajoute la ligne + lines.append(current_line) + + # On itère dans les lignes avec un enumerate pour avoir sont index + for i in enumerate(lines): + # On récupère le texte et s'il commence par un espace, on le retire + text = i[1] + if len(text) > 0 and text[0] == " ": + text = text[1:] + + # On rend la ligne au bon endroit sur l'écran + rendered_text = text_font.render(text, True, (0, 0, 0)) + self.window.blit(rendered_text, + (x_border, + display.get_window_size()[1] - resized_box.get_height() + + display.get_window_size()[0]/30 + + (text_font.get_height()+display.get_window_size()[0]/200)*i[0])) def render_debug_area(self, rendered_surface: surface.Surface): """Rend les zones de collisions et de détections quand le mode DEBUG est activé.""" From 68c6faf8964989259d4543d8c3aae7e2dad81c3b Mon Sep 17 00:00:00 2001 From: yannis300307 Date: Sat, 6 Jan 2024 17:44:47 +0100 Subject: [PATCH 09/37] Petite update des dialogues --- assets/dialogs.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/dialogs.json b/assets/dialogs.json index 7386710..2185f81 100644 --- a/assets/dialogs.json +++ b/assets/dialogs.json @@ -1,5 +1,5 @@ { - "test": ["test1111", "test2", "test très long permettant de tester le retour à la ligne dans le renderer du jeu dans la fonction qui rend les dialogues et il faut éviter d'en faire des si long car ça pourrait dépacer en base de l'écran ! Bonne journée !"], + "test": ["test1111", "test2", "test très long permettant de tester le retour à la ligne dans le renderer du jeu dans la fonction qui rend les dialogues et il faut éviter d'en faire des si long car ça pourrait dépacer en bas de l'écran ! Bonne journée !"], "test2": ["salut", "aurevoir"], - "test3": ["test très long permettant de tester le retour à la ligne dans le renderer du jeu dans la fonction qui rend les dialogues et il faut éviter d'en faire des si long car ça pourrait dépacer en base de l'écran ! Bonne journée !"] + "test3": ["test très long permettant de tester le retour à la ligne dans le renderer du jeu dans la fonction qui rend les dialogues et il faut éviter d'en faire des si long car ça pourrait dépacer en bas de l'écran ! Bonne journée !"] } \ No newline at end of file From 70bc3fe6f59bbc9703fc444f9732857d9e1ebb79 Mon Sep 17 00:00:00 2001 From: yannis300307 Date: Sat, 6 Jan 2024 17:45:17 +0100 Subject: [PATCH 10/37] =?UTF-8?q?Ajout=20du=20passage=20=C3=A0=20un=20autr?= =?UTF-8?q?e=20dialogue?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/engine/dialogs_manager.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/engine/dialogs_manager.py b/src/engine/dialogs_manager.py index 7da187b..651c9ab 100644 --- a/src/engine/dialogs_manager.py +++ b/src/engine/dialogs_manager.py @@ -9,16 +9,28 @@ class DialogsManager: self.dialogs = {} self.reading_dialog = False self.current_dialogue_letter_id = 0 + self.writing_dialog = False - self.LETTER_WRITTING_DELAY = 0.01 + self.LETTER_WRITING_DELAY = 0.02 self.letter_timer = 0 + def next_signal(self): + """Fonction exécutée lorsque l'utilisateur demande de passer au prochain dialogue. Si un dialogue est en + train d'être écrit, il écrit tout d'un coup.""" + + if self.writing_dialog: + self.current_dialogue_letter_id = len(self.current_dialogs[self.current_dialog_id]) + self.writing_dialog = False + else: + self.next_dialog() + def next_dialog(self): """Passe au dialogue suivant. Renvoie True si le dialogue est fini.""" self.current_dialog_id += 1 if self.current_dialog_id == len(self.current_dialogs): self.current_dialogs = [] self.current_dialog_id = -1 + self.writing_dialog = False self.reading_dialog = False def start_dialog(self, name: str): @@ -46,9 +58,12 @@ class DialogsManager: if self.reading_dialog: self.letter_timer -= delta + self.writing_dialog = True + if self.letter_timer <= 0: - self.letter_timer = self.LETTER_WRITTING_DELAY + self.letter_timer = self.LETTER_WRITING_DELAY self.current_dialogue_letter_id += 1 if self.current_dialogue_letter_id > len(self.current_dialogs[self.current_dialog_id]): self.current_dialogue_letter_id -= 1 + self.writing_dialog = False From 2967a1867fe6af8ee0848a06c90bab621282f6eb Mon Sep 17 00:00:00 2001 From: yannis300307 Date: Sat, 6 Jan 2024 17:45:38 +0100 Subject: [PATCH 11/37] =?UTF-8?q?Ajout=20du=20passage=20=C3=A0=20un=20autr?= =?UTF-8?q?e=20dialogue=20dans=20l'event=20handler?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/engine/event_handler.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/engine/event_handler.py b/src/engine/event_handler.py index 4d2ce83..5fb1a6c 100644 --- a/src/engine/event_handler.py +++ b/src/engine/event_handler.py @@ -22,7 +22,8 @@ class EventHandler: elif e.type == KEYDOWN: self.key_pressed.append(e.key) elif e.type == KEYUP: - self.key_pressed.remove(e.key) + if e.key in self.key_pressed: + self.key_pressed.remove(e.key) if self.engine.entity_manager.player_entity_name: if K_RIGHT in self.key_pressed: @@ -34,6 +35,10 @@ class EventHandler: if K_DOWN in self.key_pressed: self.engine.entity_manager.move_player_controls(0, 1) + if K_SPACE in self.key_pressed: + self.engine.dialogs_manager.next_signal() + self.key_pressed.remove(K_SPACE) + if self.engine.DEBUG_MODE: if K_l in self.key_pressed: self.engine.entity_manager.get_by_name("player").take_damages(1) From 75dc51ca5a6114013e6de0cea5faaa3091b28f37 Mon Sep 17 00:00:00 2001 From: yannis300307 Date: Sat, 6 Jan 2024 17:46:28 +0100 Subject: [PATCH 12/37] =?UTF-8?q?Ajout=20de=20nouveaux=20param=C3=A8tre=20?= =?UTF-8?q?pour=20la=20cr=C3=A9ation=20de=20zones=20de=20d=C3=A9clenchemen?= =?UTF-8?q?t?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/engine/event_sheduler.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/engine/event_sheduler.py b/src/engine/event_sheduler.py index 561d19f..0030339 100644 --- a/src/engine/event_sheduler.py +++ b/src/engine/event_sheduler.py @@ -11,8 +11,9 @@ class EventSheduler: self.engine = engine def register_area(self, area_rect: tuple[int, int, int, int], callback: FunctionType | classmethod | staticmethod, - linked_entities_name: list[Entity]): - self.area_callbacks.append((area_rect, callback, linked_entities_name)) + linked_entities_name: list[Entity], single_use: bool = True, no_spam: bool = False): + self.area_callbacks.append((area_rect, callback, linked_entities_name, single_use, no_spam, [])) + # La liste vide en dernier argument correspond aux entités actuellement dans la zone @staticmethod def get_collisions_with_entity(rect: tuple[int, int, int, int], entity: 'Entity'): @@ -26,8 +27,15 @@ class EventSheduler: """Met à jour l'event sheluder et execute les actions si les conditions à son execution sont respéctées.""" # On itère dans la liste des zones de détection - for area in self.area_callbacks: + for area in self.area_callbacks.copy(): # On itère dans toutes les entités enregistrées for entity in area[2]: - if self.get_collisions_with_entity(area[0], self.engine.entity_manager.get_by_name(entity)): + entity_in_area = self.get_collisions_with_entity(area[0], self.engine.entity_manager.get_by_name(entity)) + if entity_in_area and not (area[4] and entity in area[5]): area[1](entity) + if area[3]: + self.area_callbacks.remove(area) + if area[4]: + area[5].append(entity) + elif (not entity_in_area) and (area[4] and entity in area[5]): + area[5].remove(entity) From b74b731a5c63c0b97ae1e85091219aab80b779ea Mon Sep 17 00:00:00 2001 From: yannis300307 Date: Sat, 6 Jan 2024 17:46:42 +0100 Subject: [PATCH 13/37] Changement de dialogue dans le main --- src/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.py b/src/main.py index 820466f..1d348b2 100644 --- a/src/main.py +++ b/src/main.py @@ -22,7 +22,7 @@ class Game(Engine): self.game_state = GameState.NORMAL - self.event_sheduler.register_area((64, 64, 32, 32), lambda _: self.dialogs_manager.start_dialog("test3"), ["player"]) + self.event_sheduler.register_area((64, 64, 32, 32), lambda _: self.dialogs_manager.start_dialog("test"), ["player"], False, True) self.renderer.dialogs_box = pygame.image.load("assets/textures/GUI/dialogs_box.png").convert_alpha() From 1493cd578b286f4dbbdea79bc6bc885bb033cdcc Mon Sep 17 00:00:00 2001 From: yannis300307 Date: Sat, 6 Jan 2024 18:13:47 +0100 Subject: [PATCH 14/37] =?UTF-8?q?Fix=20des=20dialogues=20apparaissant=20in?= =?UTF-8?q?stantan=C3=A9ment=20la=20deuxi=C3=A8me=20fois=20qu'on=20les=20l?= =?UTF-8?q?ance?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/engine/dialogs_manager.py | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/engine/dialogs_manager.py b/src/engine/dialogs_manager.py index 651c9ab..bb0d252 100644 --- a/src/engine/dialogs_manager.py +++ b/src/engine/dialogs_manager.py @@ -18,16 +18,19 @@ class DialogsManager: """Fonction exécutée lorsque l'utilisateur demande de passer au prochain dialogue. Si un dialogue est en train d'être écrit, il écrit tout d'un coup.""" - if self.writing_dialog: - self.current_dialogue_letter_id = len(self.current_dialogs[self.current_dialog_id]) - self.writing_dialog = False - else: - self.next_dialog() + if self.reading_dialog: + if self.writing_dialog: + self.current_dialogue_letter_id = len(self.current_dialogs[self.current_dialog_id]) + else: + self.next_dialog() + + print("next") def next_dialog(self): """Passe au dialogue suivant. Renvoie True si le dialogue est fini.""" self.current_dialog_id += 1 - if self.current_dialog_id == len(self.current_dialogs): + self.writing_dialog = True + if self.current_dialog_id >= len(self.current_dialogs): self.current_dialogs = [] self.current_dialog_id = -1 self.writing_dialog = False @@ -35,9 +38,12 @@ class DialogsManager: def start_dialog(self, name: str): """Lance le dialogue au nom donné.""" + + # Si un dialogue n'est pas déja lancé, on lance le dialogue au nom donné if not self.reading_dialog: self.current_dialogs = self.dialogs[name] self.current_dialog_id = 0 + self.current_dialogue_letter_id = 0 self.reading_dialog = True @@ -58,8 +64,6 @@ class DialogsManager: if self.reading_dialog: self.letter_timer -= delta - self.writing_dialog = True - if self.letter_timer <= 0: self.letter_timer = self.LETTER_WRITING_DELAY self.current_dialogue_letter_id += 1 @@ -67,3 +71,5 @@ class DialogsManager: self.current_dialogue_letter_id -= 1 self.writing_dialog = False + #print(self.writing_dialog, self.reading_dialog) + From 1e7b62498a6fc20696c545e26391caa21a351d6d Mon Sep 17 00:00:00 2001 From: yannis300307 Date: Sat, 6 Jan 2024 18:40:57 +0100 Subject: [PATCH 15/37] =?UTF-8?q?Ajout=20d'un=20callback=20=C3=A0=20la=20f?= =?UTF-8?q?in=20du=20dialogue?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/engine/dialogs_manager.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/engine/dialogs_manager.py b/src/engine/dialogs_manager.py index bb0d252..cb6348e 100644 --- a/src/engine/dialogs_manager.py +++ b/src/engine/dialogs_manager.py @@ -1,4 +1,5 @@ import json +from types import FunctionType class DialogsManager: @@ -14,6 +15,8 @@ class DialogsManager: self.LETTER_WRITING_DELAY = 0.02 self.letter_timer = 0 + self.dialogue_finished_callback = None + def next_signal(self): """Fonction exécutée lorsque l'utilisateur demande de passer au prochain dialogue. Si un dialogue est en train d'être écrit, il écrit tout d'un coup.""" @@ -30,13 +33,15 @@ class DialogsManager: """Passe au dialogue suivant. Renvoie True si le dialogue est fini.""" self.current_dialog_id += 1 self.writing_dialog = True - if self.current_dialog_id >= len(self.current_dialogs): + if self.current_dialog_id >= len(self.current_dialogs): # Le dialogue est fini. self.current_dialogs = [] self.current_dialog_id = -1 self.writing_dialog = False self.reading_dialog = False + if self.dialogue_finished_callback is not None: + self.dialogue_finished_callback() - def start_dialog(self, name: str): + def start_dialog(self, name: str, dialogue_finished_callback: FunctionType | classmethod | staticmethod = None): """Lance le dialogue au nom donné.""" # Si un dialogue n'est pas déja lancé, on lance le dialogue au nom donné @@ -47,6 +52,8 @@ class DialogsManager: self.reading_dialog = True + self.dialogue_finished_callback = dialogue_finished_callback + def get_current_dialog_sentence(self, progressive=True) -> str: """Renvoie la phrase actuelle du dialogue.""" if progressive: From 910ef1039bdc4440374c92766db99f259122e465 Mon Sep 17 00:00:00 2001 From: yannis300307 Date: Sat, 6 Jan 2024 18:41:39 +0100 Subject: [PATCH 16/37] Correction de fautes dans des commentaires --- src/engine/event_sheduler.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/event_sheduler.py b/src/engine/event_sheduler.py index 0030339..393e8f8 100644 --- a/src/engine/event_sheduler.py +++ b/src/engine/event_sheduler.py @@ -17,14 +17,14 @@ class EventSheduler: @staticmethod def get_collisions_with_entity(rect: tuple[int, int, int, int], entity: 'Entity'): - """Retourne True si l'entité donnée touche le rectange donné.""" + """Retourne True si l'entité donnée touche le rectangle donné.""" return (rect[0] <= entity.x+entity.collision_rect[2] and rect[0] + rect[2] >= entity.x+entity.collision_rect[0] and rect[1] + rect[3] >= entity.y+entity.collision_rect[1] and rect[1] <= entity.y+entity.collision_rect[3]) def update(self): - """Met à jour l'event sheluder et execute les actions si les conditions à son execution sont respéctées.""" + """Met à jour l'event sheduler et execute les actions si les conditions à son execution sont respéctées.""" # On itère dans la liste des zones de détection for area in self.area_callbacks.copy(): From f2fa0dd81f113f126f1375e3a97dfa5db67cf844 Mon Sep 17 00:00:00 2001 From: yannis300307 Date: Sat, 6 Jan 2024 19:00:51 +0100 Subject: [PATCH 17/37] =?UTF-8?q?Ajout=20de=20la=20detection=20de=20clique?= =?UTF-8?q?s=20=C3=A0=20l'=C3=A9cran?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/engine/event_handler.py | 24 +++++++++++++++++++++--- src/main.py | 2 ++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/engine/event_handler.py b/src/engine/event_handler.py index 5fb1a6c..59d257c 100644 --- a/src/engine/event_handler.py +++ b/src/engine/event_handler.py @@ -1,4 +1,5 @@ import math +from types import FunctionType from pygame import event from pygame.locals import * @@ -8,9 +9,21 @@ import src.engine.engine as engine class EventHandler: """Classe utilisée pour traiter les pygame.event.get() et gérer les interactions avec le reste du programme.""" + def __init__(self, core: 'engine.Engine'): self.engine = core self.key_pressed = [] + self.buttons_area = [] + + @staticmethod + def get_click_collision(rect: tuple[int, int, int, int], point: tuple[int, int]): + """Vérifie si le point et le rectangle donné sont en collision.""" + return rect[0] < point[0] < rect[0] + rect[2] and rect[1] < point[1] < rect[1] + rect[3] + + def register_button_area(self, rect: tuple[int, int, int, int], callback: FunctionType | classmethod | staticmethod): + """Enregistre une zone comme bouton. La fonction donnée sera donc executé lorsque la zone sur la fenêtre + sera cliqué.""" + self.buttons_area.append((rect, callback)) def update(self): """Vérifie s'il y a de nouvelles interactions et les traites.""" @@ -24,6 +37,12 @@ class EventHandler: elif e.type == KEYUP: if e.key in self.key_pressed: self.key_pressed.remove(e.key) + elif e.type == MOUSEBUTTONDOWN: + # Vérifie si une des zones enregistrées comme bouton n'a pas été cliqué + if e.button == 1: + for area in self.buttons_area: + if self.get_click_collision(area[0], e.pos): + area[1]() if self.engine.entity_manager.player_entity_name: if K_RIGHT in self.key_pressed: @@ -44,8 +63,8 @@ class EventHandler: self.engine.entity_manager.get_by_name("player").take_damages(1) if K_p in self.key_pressed: self.engine.renderer.emit_particles(math.floor(self.engine.entity_manager.get_by_name("player").x), - math.floor(self.engine.entity_manager.get_by_name("player").y), - 16, 16, 16, 1, 8, 0, 1, 0.2, 1., (0, 200, 200)) + math.floor(self.engine.entity_manager.get_by_name("player").y), + 16, 16, 16, 1, 8, 0, 1, 0.2, 1., (0, 200, 200)) if K_o in self.key_pressed: print(f"Player pos: X = {self.engine.entity_manager.get_by_name('player').x} " f"Y = {self.engine.entity_manager.get_by_name('player').y}") @@ -54,4 +73,3 @@ class EventHandler: self.engine.camera.target_zoom *= 1.01 if K_c in self.key_pressed: self.engine.camera.target_zoom *= 0.99 - diff --git a/src/main.py b/src/main.py index 1d348b2..91d4c9f 100644 --- a/src/main.py +++ b/src/main.py @@ -26,6 +26,8 @@ class Game(Engine): self.renderer.dialogs_box = pygame.image.load("assets/textures/GUI/dialogs_box.png").convert_alpha() + self.event_handler.register_button_area((0, 0, 20, 20), lambda : print("salut")) + def create_player_entity(self): """Crée une entité joueur.""" anim = Anim(0.5) From 48611ef4e92ff52b9d7a015b33b6433df221bf5c Mon Sep 17 00:00:00 2001 From: yannis300307 Date: Sat, 6 Jan 2024 19:27:31 +0100 Subject: [PATCH 18/37] Support de la redimension automatique des boutons --- src/engine/event_handler.py | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/engine/event_handler.py b/src/engine/event_handler.py index 59d257c..905db38 100644 --- a/src/engine/event_handler.py +++ b/src/engine/event_handler.py @@ -1,7 +1,7 @@ import math from types import FunctionType -from pygame import event +from pygame import event, display from pygame.locals import * import src.engine.engine as engine @@ -16,14 +16,30 @@ class EventHandler: self.buttons_area = [] @staticmethod - def get_click_collision(rect: tuple[int, int, int, int], point: tuple[int, int]): + def get_click_collision(rect: tuple[float | int, float | int, float | int, float | int], point: tuple[int, int], + is_window_relative: int): """Vérifie si le point et le rectangle donné sont en collision.""" + window_size = display.get_window_size() + + if is_window_relative == 0: + return (rect[0]*window_size[0] < point[0]*window_size[0] < rect[0]*window_size[0] + rect[2]*window_size[0] + and rect[1]*window_size[0] < point[1]*window_size[0] < rect[1]*window_size[0] + rect[3]*window_size[0]) + + elif is_window_relative == 1: + return (rect[0] * window_size[1] < point[0] * window_size[1] < rect[0] * window_size[1] + rect[2] * + window_size[1] + and rect[1] * window_size[1] < point[1] * window_size[1] < rect[1] * window_size[1] + rect[3] * + window_size[1]) + return rect[0] < point[0] < rect[0] + rect[2] and rect[1] < point[1] < rect[1] + rect[3] - def register_button_area(self, rect: tuple[int, int, int, int], callback: FunctionType | classmethod | staticmethod): + def register_button_area(self, rect: tuple[float | int, float | int, float | int, float | int], + callback: FunctionType | classmethod | staticmethod, + is_window_relative: int = -1): """Enregistre une zone comme bouton. La fonction donnée sera donc executé lorsque la zone sur la fenêtre - sera cliqué.""" - self.buttons_area.append((rect, callback)) + sera cliqué. is_window_relative doit être 0 pour que le rect soit multipliée par la largeur de la fenêtre et 1 + pour qu'elle soit multipliée par la hauteur""" + self.buttons_area.append((rect, callback, is_window_relative)) def update(self): """Vérifie s'il y a de nouvelles interactions et les traites.""" @@ -41,7 +57,7 @@ class EventHandler: # Vérifie si une des zones enregistrées comme bouton n'a pas été cliqué if e.button == 1: for area in self.buttons_area: - if self.get_click_collision(area[0], e.pos): + if self.get_click_collision(area[0], e.pos, area[2]): area[1]() if self.engine.entity_manager.player_entity_name: From 0381ed401fd69b9cc9ad6b5a917abfa486fed93a Mon Sep 17 00:00:00 2001 From: yannis300307 Date: Sat, 6 Jan 2024 19:27:45 +0100 Subject: [PATCH 19/37] Ajout du rendu DEBUG des boutons --- src/engine/renderer.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/engine/renderer.py b/src/engine/renderer.py index 563fd53..1e3b1f7 100644 --- a/src/engine/renderer.py +++ b/src/engine/renderer.py @@ -127,6 +127,21 @@ class Renderer: self.window.blit(font.SysFont("Arial", 20).render(f"Zoom: {self.engine.camera.zoom}", True, (255, 0, 0)), (0, 60)) + # On rend maintenant toutes les zones de détection de la fenêtre + for area in self.engine.event_handler.buttons_area: + window_size = display.get_window_size() + if area[2] == 0: + draw.rect(self.window, (255, 255, 0), + (area[0][0] * window_size[0], area[0][1] * window_size[0], + area[0][2] * window_size[0], area[0][3] * window_size[0])) + elif area[2] == 1: + draw.rect(self.window, (255, 255, 0), + (area[0][0] * window_size[1], area[0][1] * window_size[1], + area[0][2] * window_size[1], area[0][3] * window_size[1])) + else: + draw.rect(self.window, (255, 255, 0), + area[0], width=1) + # Rendu présent dans tous les types de jeu self.render_dialogs_box() @@ -192,6 +207,7 @@ class Renderer: x_middle_offset = display.get_window_size()[0] / 2 / self.engine.camera.zoom y_middle_offset = display.get_window_size()[1] / 2 / self.engine.camera.zoom + # On itère et on rend toutes les zones de détection for area in self.engine.event_sheduler.area_callbacks: area_rect = area[0] draw.rect(rendered_surface, (200, 100, 0), From b6fddeb42e8425641244065ebc2bf58ee8c8d386 Mon Sep 17 00:00:00 2001 From: yannis300307 Date: Sat, 6 Jan 2024 19:33:53 +0100 Subject: [PATCH 20/37] Modification du rendu des boutons en DEBUG --- src/engine/renderer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/renderer.py b/src/engine/renderer.py index 1e3b1f7..c39b1b5 100644 --- a/src/engine/renderer.py +++ b/src/engine/renderer.py @@ -133,11 +133,11 @@ class Renderer: if area[2] == 0: draw.rect(self.window, (255, 255, 0), (area[0][0] * window_size[0], area[0][1] * window_size[0], - area[0][2] * window_size[0], area[0][3] * window_size[0])) + area[0][2] * window_size[0], area[0][3] * window_size[0]), width=1) elif area[2] == 1: draw.rect(self.window, (255, 255, 0), (area[0][0] * window_size[1], area[0][1] * window_size[1], - area[0][2] * window_size[1], area[0][3] * window_size[1])) + area[0][2] * window_size[1], area[0][3] * window_size[1]), width=1) else: draw.rect(self.window, (255, 255, 0), area[0], width=1) From 707947fa1d683ba2883c417070167af239ecace2 Mon Sep 17 00:00:00 2001 From: yannis300307 Date: Sat, 6 Jan 2024 19:34:17 +0100 Subject: [PATCH 21/37] =?UTF-8?q?Fix=20de=20la=20collision=20des=20boutons?= =?UTF-8?q?=20redimensionn=C3=A9s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/engine/event_handler.py | 10 ++++------ src/main.py | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/engine/event_handler.py b/src/engine/event_handler.py index 905db38..b04858d 100644 --- a/src/engine/event_handler.py +++ b/src/engine/event_handler.py @@ -22,14 +22,12 @@ class EventHandler: window_size = display.get_window_size() if is_window_relative == 0: - return (rect[0]*window_size[0] < point[0]*window_size[0] < rect[0]*window_size[0] + rect[2]*window_size[0] - and rect[1]*window_size[0] < point[1]*window_size[0] < rect[1]*window_size[0] + rect[3]*window_size[0]) + return (rect[0]*window_size[0] < point[0] < rect[0]*window_size[0] + rect[2]*window_size[0] + and rect[1]*window_size[0] < point[1] < rect[1]*window_size[0] + rect[3]*window_size[0]) elif is_window_relative == 1: - return (rect[0] * window_size[1] < point[0] * window_size[1] < rect[0] * window_size[1] + rect[2] * - window_size[1] - and rect[1] * window_size[1] < point[1] * window_size[1] < rect[1] * window_size[1] + rect[3] * - window_size[1]) + return (rect[0]*window_size[1] < point[0] < rect[0]*window_size[1] + rect[2]*window_size[1] and + rect[1]*window_size[1] < point[1] < rect[1]*window_size[1] + rect[3]*window_size[1]) return rect[0] < point[0] < rect[0] + rect[2] and rect[1] < point[1] < rect[1] + rect[3] diff --git a/src/main.py b/src/main.py index 91d4c9f..414b3a2 100644 --- a/src/main.py +++ b/src/main.py @@ -26,7 +26,7 @@ class Game(Engine): self.renderer.dialogs_box = pygame.image.load("assets/textures/GUI/dialogs_box.png").convert_alpha() - self.event_handler.register_button_area((0, 0, 20, 20), lambda : print("salut")) + self.event_handler.register_button_area((0, 0, 0.1, 0.1), lambda : print("salut"), 0) def create_player_entity(self): """Crée une entité joueur.""" From b1d7dc7a8b523bb291803773fa67ad71e4f2a068 Mon Sep 17 00:00:00 2001 From: yannis300307 Date: Sat, 6 Jan 2024 19:49:19 +0100 Subject: [PATCH 22/37] Ajout de la detection de clics pour le passage au prochain dialogue --- src/engine/dialogs_manager.py | 8 +++++++- src/engine/engine.py | 2 +- src/engine/event_handler.py | 15 +++++++++++++-- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/engine/dialogs_manager.py b/src/engine/dialogs_manager.py index cb6348e..7035b7d 100644 --- a/src/engine/dialogs_manager.py +++ b/src/engine/dialogs_manager.py @@ -1,10 +1,14 @@ import json from types import FunctionType +from src.engine.event_handler import EventHandler + class DialogsManager: """Classe qui gère la lecture des dialogues.""" - def __init__(self): + def __init__(self, event_handler: EventHandler): + self.event_handler = event_handler + self.current_dialogs = [] self.current_dialog_id = -1 self.dialogs = {} @@ -46,6 +50,8 @@ class DialogsManager: # Si un dialogue n'est pas déja lancé, on lance le dialogue au nom donné if not self.reading_dialog: + self.event_handler.register_button_area((0, 0, 1, 1), self.next_signal, "next_dialog", 0) + self.current_dialogs = self.dialogs[name] self.current_dialog_id = 0 self.current_dialogue_letter_id = 0 diff --git a/src/engine/engine.py b/src/engine/engine.py index 69fb4b2..0d67740 100644 --- a/src/engine/engine.py +++ b/src/engine/engine.py @@ -34,7 +34,7 @@ class Engine: self.entity_manager = EntityManager(self.map_manager) self.boss_fight_manager = BossFightManager(self) self.event_sheduler = EventSheduler(self) - self.dialogs_manager = DialogsManager() + self.dialogs_manager = DialogsManager(self.event_handler) def loop(self): """Fonction à lancer au début du programme et qui va lancer les updates dans une boucle. diff --git a/src/engine/event_handler.py b/src/engine/event_handler.py index b04858d..e14cf13 100644 --- a/src/engine/event_handler.py +++ b/src/engine/event_handler.py @@ -32,12 +32,23 @@ class EventHandler: return rect[0] < point[0] < rect[0] + rect[2] and rect[1] < point[1] < rect[1] + rect[3] def register_button_area(self, rect: tuple[float | int, float | int, float | int, float | int], - callback: FunctionType | classmethod | staticmethod, + callback: FunctionType | classmethod | staticmethod, name: str, is_window_relative: int = -1): """Enregistre une zone comme bouton. La fonction donnée sera donc executé lorsque la zone sur la fenêtre sera cliqué. is_window_relative doit être 0 pour que le rect soit multipliée par la largeur de la fenêtre et 1 pour qu'elle soit multipliée par la hauteur""" - self.buttons_area.append((rect, callback, is_window_relative)) + self.buttons_area.append((rect, callback, is_window_relative, name)) + + def remove_button_area(self, name: str): + """Supprime les boutons aux noms donnés.""" + + # On itère dans toute la liste et on ne garde que les éléments ne portant pas le nom cherché + cleared_list = [] + for area in self.buttons_area: + if area[3] != name: + cleared_list.append(area) + + self.buttons_area = cleared_list def update(self): """Vérifie s'il y a de nouvelles interactions et les traites.""" From f7d1ab976c50a9f053192803290398ab7ee540b8 Mon Sep 17 00:00:00 2001 From: yannis300307 Date: Sat, 6 Jan 2024 19:49:46 +0100 Subject: [PATCH 23/37] Correction d'un commentaire --- src/engine/dialogs_manager.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/engine/dialogs_manager.py b/src/engine/dialogs_manager.py index 7035b7d..fd2c538 100644 --- a/src/engine/dialogs_manager.py +++ b/src/engine/dialogs_manager.py @@ -34,7 +34,7 @@ class DialogsManager: print("next") def next_dialog(self): - """Passe au dialogue suivant. Renvoie True si le dialogue est fini.""" + """Passe au dialogue suivant. Appelle le callback si le dialogue est fini.""" self.current_dialog_id += 1 self.writing_dialog = True if self.current_dialog_id >= len(self.current_dialogs): # Le dialogue est fini. @@ -42,6 +42,7 @@ class DialogsManager: self.current_dialog_id = -1 self.writing_dialog = False self.reading_dialog = False + self.event_handler.remove_button_area("next_dialog") if self.dialogue_finished_callback is not None: self.dialogue_finished_callback() From 1e405d861f157078e9fd18c8b12a8f82cb4466c0 Mon Sep 17 00:00:00 2001 From: yannis300307 Date: Sat, 6 Jan 2024 20:56:35 +0100 Subject: [PATCH 24/37] Ajout d'un gestionnaire de menu --- src/engine/menu_manager.py | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 src/engine/menu_manager.py diff --git a/src/engine/menu_manager.py b/src/engine/menu_manager.py new file mode 100644 index 0000000..6026668 --- /dev/null +++ b/src/engine/menu_manager.py @@ -0,0 +1,4 @@ +class MenuManager: + """Classe qui gère les menus.""" + def __init__(self): + pass \ No newline at end of file From 3e7db7f382a2f5daa63c7d7e7dba265538b1e8c6 Mon Sep 17 00:00:00 2001 From: Yannis300307 Date: Sun, 7 Jan 2024 09:26:42 +0100 Subject: [PATCH 25/37] =?UTF-8?q?Ajout=20d'un=20quatri=C3=A8me=20mode=20de?= =?UTF-8?q?=20redimension=20de=20bouton?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/engine/event_handler.py | 4 ++++ src/engine/renderer.py | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/engine/event_handler.py b/src/engine/event_handler.py index e14cf13..c4c976d 100644 --- a/src/engine/event_handler.py +++ b/src/engine/event_handler.py @@ -29,6 +29,10 @@ class EventHandler: return (rect[0]*window_size[1] < point[0] < rect[0]*window_size[1] + rect[2]*window_size[1] and rect[1]*window_size[1] < point[1] < rect[1]*window_size[1] + rect[3]*window_size[1]) + elif is_window_relative == 2: + return (rect[0]*window_size[0] < point[0] < rect[0]*window_size[0] + rect[2]*window_size[0] and + rect[1]*window_size[1] < point[1] < rect[1]*window_size[1] + rect[3]*window_size[1]) + return rect[0] < point[0] < rect[0] + rect[2] and rect[1] < point[1] < rect[1] + rect[3] def register_button_area(self, rect: tuple[float | int, float | int, float | int, float | int], diff --git a/src/engine/renderer.py b/src/engine/renderer.py index c39b1b5..804fa29 100644 --- a/src/engine/renderer.py +++ b/src/engine/renderer.py @@ -138,6 +138,10 @@ class Renderer: draw.rect(self.window, (255, 255, 0), (area[0][0] * window_size[1], area[0][1] * window_size[1], area[0][2] * window_size[1], area[0][3] * window_size[1]), width=1) + elif area[2] == 2: + draw.rect(self.window, (255, 255, 0), + (area[0][0] * window_size[0], area[0][1] * window_size[1], + area[0][2] * window_size[0], area[0][3] * window_size[1]), width=1) else: draw.rect(self.window, (255, 255, 0), area[0], width=1) From 593c43a2dc8f65e6de4418ec7ebdb3de014cb14e Mon Sep 17 00:00:00 2001 From: Yannis300307 Date: Sun, 7 Jan 2024 09:30:09 +0100 Subject: [PATCH 26/37] Modification du type de redimension de bouton dans le dialogue manager --- src/engine/dialogs_manager.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/engine/dialogs_manager.py b/src/engine/dialogs_manager.py index fd2c538..0faec80 100644 --- a/src/engine/dialogs_manager.py +++ b/src/engine/dialogs_manager.py @@ -36,6 +36,7 @@ class DialogsManager: def next_dialog(self): """Passe au dialogue suivant. Appelle le callback si le dialogue est fini.""" self.current_dialog_id += 1 + self.current_dialogue_letter_id = 0 self.writing_dialog = True if self.current_dialog_id >= len(self.current_dialogs): # Le dialogue est fini. self.current_dialogs = [] @@ -51,7 +52,7 @@ class DialogsManager: # Si un dialogue n'est pas déja lancé, on lance le dialogue au nom donné if not self.reading_dialog: - self.event_handler.register_button_area((0, 0, 1, 1), self.next_signal, "next_dialog", 0) + self.event_handler.register_button_area((0, 0, 1, 1), self.next_signal, "next_dialog", 2) self.current_dialogs = self.dialogs[name] self.current_dialog_id = 0 @@ -84,6 +85,3 @@ class DialogsManager: if self.current_dialogue_letter_id > len(self.current_dialogs[self.current_dialog_id]): self.current_dialogue_letter_id -= 1 self.writing_dialog = False - - #print(self.writing_dialog, self.reading_dialog) - From 0f617c409b08956b7eb3c6dbfb4306d9d35f6726 Mon Sep 17 00:00:00 2001 From: Yannis300307 Date: Sun, 7 Jan 2024 11:47:53 +0100 Subject: [PATCH 27/37] Ajout du premier menu et du premier widget --- src/engine/menu_manager.py | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/src/engine/menu_manager.py b/src/engine/menu_manager.py index 6026668..fabd488 100644 --- a/src/engine/menu_manager.py +++ b/src/engine/menu_manager.py @@ -1,4 +1,37 @@ +class Widget: + """Classe parente des widgets de menu.""" + def __init__(self, x, y, is_window_relative): + self.x = x + self.y = y + self.is_window_relative = is_window_relative + + +class Label(Widget): + """Un widget de texte.""" + def __init__(self, x: int | float, y: int | float, text: str, size: int | float, centered: bool = False, + is_window_relative: bool = -1): + super().__init__(x, y, is_window_relative) + self.text = text + self.size = size + self.centered = centered + + +class Menu: + """Un menu contenant des widgets.""" + def __init__(self): + self.widgets: list[Widget] = [] + + def add_widget(self, widget: Widget): + """Ajoute le widget donné au menu.""" + self.widgets.append(widget) + + class MenuManager: """Classe qui gère les menus.""" + def __init__(self): - pass \ No newline at end of file + self.menus = {} + + def register_menu(self, menu: Menu, name: str): + """Ajoute le menu donné au manager de menu avec le nom donné.""" + self.menus[name] = menu From 43be50f410e15c80601da995830561422dddc811 Mon Sep 17 00:00:00 2001 From: Yannis300307 Date: Sun, 7 Jan 2024 11:51:47 +0100 Subject: [PATCH 28/37] Suppression de l'ancien code du main menu dans le renderer --- src/engine/renderer.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/engine/renderer.py b/src/engine/renderer.py index 804fa29..fe898fc 100644 --- a/src/engine/renderer.py +++ b/src/engine/renderer.py @@ -30,9 +30,6 @@ class Renderer: # Boite de dialogue self.dialogs_box = None - # Variables utilisées par le menu principal - self.main_menu_assets: dict[str: Anim] = {} - # Ombres d'entités self.shadows = {} @@ -68,9 +65,6 @@ class Renderer: # Le 0 correspond au temps de vie depuis la création de la particule self.particles.append([part_x, part_y, part_size, part_speed_x, part_speed_y, 0., part_life_time, color]) - def load_main_menu_assets(self, path: str): - """Charge les assets du menu principal depuis le dossier donné.""" - def load_tile_set(self, file_path: str, tile_size: int): """Charge le jeu de tuiles en utilisant le fichier donné et la taille donnée.""" tile_set = image.load(file_path).convert_alpha() @@ -362,9 +356,6 @@ class Renderer: entity.collision_rect[3] - entity.collision_rect[1]), width=1) - def render_main_menu(self): - """Rend le menu principal du jeu.""" - def render_layer(self, layer_id: int, rendered_surface: surface.Surface): """Rend la map.""" # On calcule le nombre de tiles à mettre sur notre écran en prenant en compte le zoom From 51c20b5e674079a2fcb14b977c53784821733ab4 Mon Sep 17 00:00:00 2001 From: Yannis300307 Date: Sun, 7 Jan 2024 12:14:00 +0100 Subject: [PATCH 29/37] Ajout de la redimension automatique des labels --- src/engine/engine.py | 2 ++ src/engine/menu_manager.py | 14 ++++++++++-- src/engine/renderer.py | 45 ++++++++++++++++++++++++++++++++++++++ src/main.py | 11 ++++++++++ 4 files changed, 70 insertions(+), 2 deletions(-) diff --git a/src/engine/engine.py b/src/engine/engine.py index 0d67740..ce18718 100644 --- a/src/engine/engine.py +++ b/src/engine/engine.py @@ -5,6 +5,7 @@ from src.engine.entity_manager import EntityManager from src.engine.event_handler import EventHandler from src.engine.event_sheduler import EventSheduler from src.engine.map_manager import MapManager +from src.engine.menu_manager import MenuManager from src.engine.renderer import Renderer from src.engine.enums import GameState import pygame @@ -35,6 +36,7 @@ class Engine: self.boss_fight_manager = BossFightManager(self) self.event_sheduler = EventSheduler(self) self.dialogs_manager = DialogsManager(self.event_handler) + self.menu_manager = MenuManager() def loop(self): """Fonction à lancer au début du programme et qui va lancer les updates dans une boucle. diff --git a/src/engine/menu_manager.py b/src/engine/menu_manager.py index fabd488..f0318d7 100644 --- a/src/engine/menu_manager.py +++ b/src/engine/menu_manager.py @@ -8,12 +8,13 @@ class Widget: class Label(Widget): """Un widget de texte.""" - def __init__(self, x: int | float, y: int | float, text: str, size: int | float, centered: bool = False, - is_window_relative: bool = -1): + def __init__(self, x: int | float, y: int | float, text: str, size: int | float, color: tuple[int, int, int], + centered: bool = False, is_window_relative: bool = -1): super().__init__(x, y, is_window_relative) self.text = text self.size = size self.centered = centered + self.color = color class Menu: @@ -31,7 +32,16 @@ class MenuManager: def __init__(self): self.menus = {} + self.active_menu: Menu | None = None def register_menu(self, menu: Menu, name: str): """Ajoute le menu donné au manager de menu avec le nom donné.""" self.menus[name] = menu + + def show(self, name: str): + """Affiche le menu au nom donné.""" + self.active_menu = self.menus[name] + + def hide(self): + """Affiche le menu actuelement à l'écran.""" + self.active_menu = None diff --git a/src/engine/renderer.py b/src/engine/renderer.py index fe898fc..8f93755 100644 --- a/src/engine/renderer.py +++ b/src/engine/renderer.py @@ -7,6 +7,7 @@ from pygame.locals import RESIZABLE, SRCALPHA, FULLSCREEN import src.engine.engine as engine from src.engine.animation import Anim from src.engine.enums import GameState +from src.engine.menu_manager import Label class Renderer: @@ -111,6 +112,9 @@ class Renderer: self.render_boss_fight_scene(delta) self.render_boss_fight_gui() + # Rend les menus + self.render_menus() + # Conteur de FPS en mode DEBUG if self.engine.DEBUG_MODE: self.window.blit(font.SysFont("Arial", 20).render(f"FPS: {self.engine.clock.get_fps()}", True, (255, 0, 0)), @@ -146,6 +150,47 @@ class Renderer: # Apres avoir tout rendu, on met à jour l'écran display.update() + def render_menus(self): + """Rend le menu enregistré comme visible.""" + window_size = display.get_window_size() + + # Si un menu est affiché, on itère dans tous ses widgets + if self.engine.menu_manager.active_menu is not None: + for widget in self.engine.menu_manager.active_menu.widgets: + # On multiplie les coordonnées par la taille de la fenetre si besoin + if widget.is_window_relative == 0: + x = widget.x * window_size[0] + y = widget.y * window_size[0] + elif widget.is_window_relative == 1: + x = widget.x * window_size[1] + y = widget.y * window_size[1] + elif widget.is_window_relative == 2: + x = widget.x * window_size[0] + y = widget.y * window_size[1] + else: + x = widget.x + y = widget.y + + # On vérifie quel est le widget + if isinstance(widget, Label): + # On multiplie la taille du texte si besoin + if widget.is_window_relative == 0: + size = widget.size*window_size[0] + elif widget.is_window_relative == 1: + size = widget.size*window_size[1] + elif widget.is_window_relative == 2: + size = widget.size*min(window_size[0], window_size[1]) + else: + size = widget.size + + text_font = font.SysFont("Arial", round(size)) + rendered_text = text_font.render(widget.text, True, widget.color) + if widget.centered: + self.window.blit(rendered_text, (x-rendered_text.get_width()//2, + y-rendered_text.get_height()//2)) + else: + self.window.blit(rendered_text, (x, y)) + def render_dialogs_box(self): """Rend la boite de dialogue lorsqu'un dialogue est lancé.""" diff --git a/src/main.py b/src/main.py index 414b3a2..ad30c2c 100644 --- a/src/main.py +++ b/src/main.py @@ -4,6 +4,7 @@ from src.custom_AI import WolfAI from src.engine.animation import Anim from src.engine.engine import Engine from src.engine.enums import GameState +from src.engine.menu_manager import Menu, Label class Game(Engine): @@ -28,6 +29,16 @@ class Game(Engine): self.event_handler.register_button_area((0, 0, 0.1, 0.1), lambda : print("salut"), 0) + self.setup_main_menu() + + def setup_main_menu(self): + """Crée les éléments du menu principal.""" + menu = Menu() + menu.add_widget(Label(0.5, 0.1, "The Forest's Secret", 0.1, (0, 255, 0), True, 2)) + self.menu_manager.register_menu(menu, "main") + + self.menu_manager.show("main") + def create_player_entity(self): """Crée une entité joueur.""" anim = Anim(0.5) From 39636498812a72779ea84377cc1d578496eaf11b Mon Sep 17 00:00:00 2001 From: Yannis300307 Date: Sun, 7 Jan 2024 17:05:50 +0100 Subject: [PATCH 30/37] Ajout du rendu des boutons --- src/engine/menu_manager.py | 24 +++++++++++++++++++++++- src/engine/renderer.py | 24 +++++++++++++++++++++++- src/main.py | 6 +++++- 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/src/engine/menu_manager.py b/src/engine/menu_manager.py index f0318d7..27929fa 100644 --- a/src/engine/menu_manager.py +++ b/src/engine/menu_manager.py @@ -1,3 +1,10 @@ +import threading +import tkinter +from types import FunctionType + +import pygame + + class Widget: """Classe parente des widgets de menu.""" def __init__(self, x, y, is_window_relative): @@ -9,7 +16,7 @@ class Widget: class Label(Widget): """Un widget de texte.""" def __init__(self, x: int | float, y: int | float, text: str, size: int | float, color: tuple[int, int, int], - centered: bool = False, is_window_relative: bool = -1): + centered: bool = False, is_window_relative: int = -1): super().__init__(x, y, is_window_relative) self.text = text self.size = size @@ -17,6 +24,21 @@ class Label(Widget): self.color = color +class Button(Widget): + """Un widget de bouton.""" + def __init__(self, x: int | float, y: int | float, text: str, size: int | float, color: tuple[int, int, int], + callback: FunctionType | classmethod | staticmethod, base_image: pygame.Surface, + hover_image: pygame.Surface, centered: bool = False, is_window_relative: int = -1): + super().__init__(x, y, is_window_relative) + self.text = text + self.size = size + self.color = color + self.callback = callback + self.base_image = base_image + self.hover_image = hover_image + self.centered = centered + + class Menu: """Un menu contenant des widgets.""" def __init__(self): diff --git a/src/engine/renderer.py b/src/engine/renderer.py index 8f93755..7d13849 100644 --- a/src/engine/renderer.py +++ b/src/engine/renderer.py @@ -7,7 +7,7 @@ from pygame.locals import RESIZABLE, SRCALPHA, FULLSCREEN import src.engine.engine as engine from src.engine.animation import Anim from src.engine.enums import GameState -from src.engine.menu_manager import Label +from src.engine.menu_manager import Label, Button class Renderer: @@ -190,6 +190,28 @@ class Renderer: y-rendered_text.get_height()//2)) else: self.window.blit(rendered_text, (x, y)) + elif isinstance(widget, Button): + print("a") + # On multiplie la taille du texte si besoin + if widget.is_window_relative == 0: + size = widget.size*window_size[0] + elif widget.is_window_relative == 1: + size = widget.size*window_size[1] + elif widget.is_window_relative == 2: + size = widget.size*min(window_size[0], window_size[1]) + else: + size = widget.size + + text_font = font.SysFont("Arial", round(size)) + + # On affiche l'image du boutton + self.window.blit(widget.base_image, (x-widget.base_image.get_width()//2, + y-widget.base_image.get_height()//2)) + + rendered_text = text_font.render(widget.text, True, widget.color) + self.window.blit(rendered_text, (x-rendered_text.get_width()//2, + y-rendered_text.get_height()//2)) + def render_dialogs_box(self): """Rend la boite de dialogue lorsqu'un dialogue est lancé.""" diff --git a/src/main.py b/src/main.py index ad30c2c..ec16d23 100644 --- a/src/main.py +++ b/src/main.py @@ -4,7 +4,7 @@ from src.custom_AI import WolfAI from src.engine.animation import Anim from src.engine.engine import Engine from src.engine.enums import GameState -from src.engine.menu_manager import Menu, Label +from src.engine.menu_manager import Menu, Label, Button class Game(Engine): @@ -35,6 +35,10 @@ class Game(Engine): """Crée les éléments du menu principal.""" menu = Menu() menu.add_widget(Label(0.5, 0.1, "The Forest's Secret", 0.1, (0, 255, 0), True, 2)) + + base_image = pygame.image.load("assets/textures/GUI/button_1.png").convert_alpha() + + menu.add_widget(Button(0.5, 0.3, "boutton", 0.1, (0, 255, 0), lambda : print("play"), base_image, base_image, True, 2)) self.menu_manager.register_menu(menu, "main") self.menu_manager.show("main") From 745a182ec89563daf3e5c5200df4d70d3a16ede9 Mon Sep 17 00:00:00 2001 From: Yannis300307 Date: Sun, 7 Jan 2024 17:06:26 +0100 Subject: [PATCH 31/37] Ajout d'une image de bouton --- assets/textures/GUI/button_1.png | Bin 0 -> 1426 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 assets/textures/GUI/button_1.png diff --git a/assets/textures/GUI/button_1.png b/assets/textures/GUI/button_1.png new file mode 100644 index 0000000000000000000000000000000000000000..2373576dfc935010049db78bbf02da9c32b7c6e7 GIT binary patch literal 1426 zcmb_c`BM^j9Q{I~Vd1eJ9qW)fZh31CYF3C99$=EWYQvbs=CNv~6lskYjIFDQrfXv* zq?xAWkr%8QqUkcJZIWjkl4%}fDPp1+E7`LD!~XC&-h4j4yqWjjtzd#bLVv$L004mt zz=i+-(XPN}r>?edMAr3a2ZS2pe-bpkvG}9~I=`L>Isrgy(Jsv|FfE2t0*F)q4EX;Q zWFYxzGyt$eIP8hg8zlMEbl_Bq#lV*i48;_`$H2y}3|B%hFqOpl=1>{^T%%~_6gKBR z!D zWkxR})B7P?I=qz8gLxBv(6bq*d?2f=4I8g~?*DTWgmURIN`!imAakcOsm#Z*qSOdb z%0vp_g1L53X%jh85ZCX{Y7ZVt(w`v;jxlqy_t9;?5|wxR2{4$M1HB8SNFX6%LDk|Z z!H>*8$#<)RArtZ5qT~CA09LZejACN4B?fB!UXSnRm@=~N41waSK>5 z^h|uxd4qZLUOi^ENP|EiuCC4Fys|W%p`oFjVW2}Q6y7~eApE_$+T!T!%zexA9^;iD zWB1UfA}@y-r}2lI)Gj36VC#WA%Pxz&mltzZ;28~GWQ77# z`D!bzd1^IExnndmGScY@q5LYlcmQQM37<(3q_?--L4OXk`Qe>h&)TsRkE2ql6tCg| zRw}gR!bXmmn&p8py1cNkFea5Q#aih-1IvfHtyCq3^u?vcMM`yXxC7Wi)AG7M=vn@w zQcNrStTrWRx>L~N0i{?hp4lMH7?6|U=Hl0O4s`kY5veNmeGD)TT|`%mcwzu87|;i7 zL2r~Pm^rKuR`N`j(pws+tE$1R~^oU=iEN#ih%b zZW}=)Ua2mA(FmGq2PDps+<8Ax)i_A%Nq`k^j(_?T?+G=E@l~zGIM9>F<`PXzOiJ(z z-DqHGooHB8SooYc_`t09xt7=LY?W3ST&;?aQe_1;cW|D&ydq?}dr*2~d>YEb1AiQO z@AKz`4ydKQP$;x9XPDX36)1Ts)K$@iVTf7{}Z`g;2g z{mO~PrY1a%Mr#!$lg2dBH%~+MUdquG@cSHd%XOBME@ozSb2yv;B2lJ-(4~SE)tR6m z-1X}nLqkKIT4j&&%8~i=E3;kh7cL>;u`raoJ1#l7`P#K>0TB_b384`0`|^!5WR=z? zN|z%r>90O&)XKi7Ev)qiZ>L3nfr-|&wQHG$(+%p7af>1F4!-=`_X1f5Sr%OZU0(0% z-<~z>+wC(U@ubBmSs5^LqfW&{hV~I#8mW}FVmRucM^M+)^3^ukeObN}$lHBv4b$9u zY}>O*O_i&{vugU0#uXzRDU@Cko%~f2=>0IkBk|FFn$mGN$pHD*VuBO5BASTHFFy!0 q9qsP4gyoN#d)hc+Gg(KTF*JxB`|JWsc^*F690fRE0=DTSIs0G7W~s>l literal 0 HcmV?d00001 From 21aa1c9768ec6281aac8a697b9bb6c563dca54c8 Mon Sep 17 00:00:00 2001 From: Yannis300307 Date: Sun, 7 Jan 2024 17:58:24 +0100 Subject: [PATCH 32/37] Ajout de la redimension automatique des boutons et hover --- src/engine/engine.py | 2 +- src/engine/event_handler.py | 10 ++++++++-- src/engine/menu_manager.py | 29 +++++++++++++++++++++++++---- src/engine/renderer.py | 23 ++++++++++++++++------- src/main.py | 2 +- 5 files changed, 51 insertions(+), 15 deletions(-) diff --git a/src/engine/engine.py b/src/engine/engine.py index ce18718..0b86865 100644 --- a/src/engine/engine.py +++ b/src/engine/engine.py @@ -36,7 +36,7 @@ class Engine: self.boss_fight_manager = BossFightManager(self) self.event_sheduler = EventSheduler(self) self.dialogs_manager = DialogsManager(self.event_handler) - self.menu_manager = MenuManager() + self.menu_manager = MenuManager(self) def loop(self): """Fonction à lancer au début du programme et qui va lancer les updates dans une boucle. diff --git a/src/engine/event_handler.py b/src/engine/event_handler.py index c4c976d..242f2b8 100644 --- a/src/engine/event_handler.py +++ b/src/engine/event_handler.py @@ -14,6 +14,7 @@ class EventHandler: self.engine = core self.key_pressed = [] self.buttons_area = [] + self.hovered_area = [] @staticmethod def get_click_collision(rect: tuple[float | int, float | int, float | int, float | int], point: tuple[int, int], @@ -37,11 +38,12 @@ class EventHandler: def register_button_area(self, rect: tuple[float | int, float | int, float | int, float | int], callback: FunctionType | classmethod | staticmethod, name: str, - is_window_relative: int = -1): + is_window_relative: int = -1, + hover_callback: FunctionType | classmethod | staticmethod = None): """Enregistre une zone comme bouton. La fonction donnée sera donc executé lorsque la zone sur la fenêtre sera cliqué. is_window_relative doit être 0 pour que le rect soit multipliée par la largeur de la fenêtre et 1 pour qu'elle soit multipliée par la hauteur""" - self.buttons_area.append((rect, callback, is_window_relative, name)) + self.buttons_area.append((rect, callback, is_window_relative, name, hover_callback)) def remove_button_area(self, name: str): """Supprime les boutons aux noms donnés.""" @@ -72,6 +74,10 @@ class EventHandler: for area in self.buttons_area: if self.get_click_collision(area[0], e.pos, area[2]): area[1]() + elif e.type == MOUSEMOTION: + for area in self.buttons_area: + if area[4] is not None and self.get_click_collision(area[0], e.pos, area[2]): + area[4]() if self.engine.entity_manager.player_entity_name: if K_RIGHT in self.key_pressed: diff --git a/src/engine/menu_manager.py b/src/engine/menu_manager.py index 27929fa..44dcb1f 100644 --- a/src/engine/menu_manager.py +++ b/src/engine/menu_manager.py @@ -1,9 +1,9 @@ -import threading -import tkinter from types import FunctionType import pygame +import src.engine.engine + class Widget: """Classe parente des widgets de menu.""" @@ -28,7 +28,8 @@ class Button(Widget): """Un widget de bouton.""" def __init__(self, x: int | float, y: int | float, text: str, size: int | float, color: tuple[int, int, int], callback: FunctionType | classmethod | staticmethod, base_image: pygame.Surface, - hover_image: pygame.Surface, centered: bool = False, is_window_relative: int = -1): + hover_image: pygame.Surface, centered: bool = False, is_window_relative: int = -1, + area_name: str = "menu_button"): super().__init__(x, y, is_window_relative) self.text = text self.size = size @@ -37,6 +38,11 @@ class Button(Widget): self.base_image = base_image self.hover_image = hover_image self.centered = centered + self.area_name = area_name + self.hovered = False + + def set_hover_state(self, state: bool): + self.hovered = state class Menu: @@ -52,14 +58,29 @@ class Menu: class MenuManager: """Classe qui gère les menus.""" - def __init__(self): + def __init__(self, engine: 'src.engine.engine.Engine'): self.menus = {} self.active_menu: Menu | None = None + self.engine = engine def register_menu(self, menu: Menu, name: str): """Ajoute le menu donné au manager de menu avec le nom donné.""" self.menus[name] = menu + # On itère dans tous les bouttons pour leur ajouter une interaction + for btn in menu.widgets: + if isinstance(btn, Button): + width = btn.base_image.get_width()/self.engine.renderer.window_size[0] + height = btn.base_image.get_height()/self.engine.renderer.window_size[1] + area_x = btn.x + area_y = btn.y + if btn.centered: + area_x -= width/2 + area_y -= height/2 + self.engine.event_handler.register_button_area((area_x, area_y, width, height), btn.callback, btn.area_name, + btn.is_window_relative, lambda: print("hover")) + print(btn.is_window_relative) + def show(self, name: str): """Affiche le menu au nom donné.""" self.active_menu = self.menus[name] diff --git a/src/engine/renderer.py b/src/engine/renderer.py index 7d13849..894cafb 100644 --- a/src/engine/renderer.py +++ b/src/engine/renderer.py @@ -191,7 +191,6 @@ class Renderer: else: self.window.blit(rendered_text, (x, y)) elif isinstance(widget, Button): - print("a") # On multiplie la taille du texte si besoin if widget.is_window_relative == 0: size = widget.size*window_size[0] @@ -204,14 +203,24 @@ class Renderer: text_font = font.SysFont("Arial", round(size)) - # On affiche l'image du boutton - self.window.blit(widget.base_image, (x-widget.base_image.get_width()//2, - y-widget.base_image.get_height()//2)) - rendered_text = text_font.render(widget.text, True, widget.color) - self.window.blit(rendered_text, (x-rendered_text.get_width()//2, - y-rendered_text.get_height()//2)) + btn_image = widget.base_image + btn_image = transform.scale(btn_image, (btn_image.get_width()*window_size[0]/self.window_size[0], + btn_image.get_height()*window_size[0]/self.window_size[0])) + + # On affiche l'image du boutton + if widget.centered: + self.window.blit(btn_image, (x-btn_image.get_width()//2, + y-btn_image.get_height()//2)) + + self.window.blit(rendered_text, (x-rendered_text.get_width()//2, + y-rendered_text.get_height()//2)) + + else: + self.window.blit(btn_image, (x, y)) + + self.window.blit(rendered_text, (x, y)) def render_dialogs_box(self): """Rend la boite de dialogue lorsqu'un dialogue est lancé.""" diff --git a/src/main.py b/src/main.py index ec16d23..d505fbb 100644 --- a/src/main.py +++ b/src/main.py @@ -38,7 +38,7 @@ class Game(Engine): base_image = pygame.image.load("assets/textures/GUI/button_1.png").convert_alpha() - menu.add_widget(Button(0.5, 0.3, "boutton", 0.1, (0, 255, 0), lambda : print("play"), base_image, base_image, True, 2)) + menu.add_widget(Button(0.5, 0.3, "boutton", 0.1, (0, 255, 0), lambda : print("play"), base_image, base_image, True, 0)) self.menu_manager.register_menu(menu, "main") self.menu_manager.show("main") From 82f8b692fbffbe7c6853e8545f6f27911625f3ee Mon Sep 17 00:00:00 2001 From: Yannis300307 Date: Sun, 7 Jan 2024 18:11:28 +0100 Subject: [PATCH 33/37] Ajout du hover du bouton --- src/engine/event_handler.py | 11 +++++++++-- src/engine/menu_manager.py | 4 ++-- src/engine/renderer.py | 5 ++++- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/engine/event_handler.py b/src/engine/event_handler.py index 242f2b8..1568ed0 100644 --- a/src/engine/event_handler.py +++ b/src/engine/event_handler.py @@ -76,8 +76,15 @@ class EventHandler: area[1]() elif e.type == MOUSEMOTION: for area in self.buttons_area: - if area[4] is not None and self.get_click_collision(area[0], e.pos, area[2]): - area[4]() + if area[4] is not None: + if self.get_click_collision(area[0], e.pos, area[2]): + if area not in self.hovered_area: + area[4](True) + self.hovered_area.append(area) + else: + if area in self.hovered_area: + area[4](False) + self.hovered_area.remove(area) if self.engine.entity_manager.player_entity_name: if K_RIGHT in self.key_pressed: diff --git a/src/engine/menu_manager.py b/src/engine/menu_manager.py index 44dcb1f..062e181 100644 --- a/src/engine/menu_manager.py +++ b/src/engine/menu_manager.py @@ -42,6 +42,7 @@ class Button(Widget): self.hovered = False def set_hover_state(self, state: bool): + """Modifie la valeur du hover.""" self.hovered = state @@ -78,8 +79,7 @@ class MenuManager: area_x -= width/2 area_y -= height/2 self.engine.event_handler.register_button_area((area_x, area_y, width, height), btn.callback, btn.area_name, - btn.is_window_relative, lambda: print("hover")) - print(btn.is_window_relative) + btn.is_window_relative, btn.set_hover_state) def show(self, name: str): """Affiche le menu au nom donné.""" diff --git a/src/engine/renderer.py b/src/engine/renderer.py index 894cafb..89a0126 100644 --- a/src/engine/renderer.py +++ b/src/engine/renderer.py @@ -205,7 +205,10 @@ class Renderer: rendered_text = text_font.render(widget.text, True, widget.color) - btn_image = widget.base_image + if widget.hovered: + btn_image = widget.base_image + else: + btn_image = widget.hover_image btn_image = transform.scale(btn_image, (btn_image.get_width()*window_size[0]/self.window_size[0], btn_image.get_height()*window_size[0]/self.window_size[0])) From cc77957b31a72d7fe35bdd9b3595784b61c966d0 Mon Sep 17 00:00:00 2001 From: Yannis300307 Date: Sun, 7 Jan 2024 18:15:37 +0100 Subject: [PATCH 34/37] Ajout du hover du bouton actuel --- assets/textures/GUI/button_2.png | Bin 0 -> 1392 bytes src/engine/renderer.py | 4 ++-- src/main.py | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 assets/textures/GUI/button_2.png diff --git a/assets/textures/GUI/button_2.png b/assets/textures/GUI/button_2.png new file mode 100644 index 0000000000000000000000000000000000000000..600a10c5ac1809a2150fe1d5eea883b364715dcf GIT binary patch literal 1392 zcmcJP|34FW9LGN!o3%xkJSbYL^q}014jC8oKL8MI3)~QJZB~X>b!ZEO=I`YJ9u94v(F)xt_ap8A)MumC!eLsyA)XjW1HhpB zOF*7eD&-zpWpKM+{Sa;Ze58MD*E*2Rg2YutGw zc23Uxx`mi=>cj?JV>X;crOG2!D_7;KiXkk!?&g~m28*R}=~ei;drBp9r%ajR1%XX) zdQHRC^wAiw%P50Tnmb9}^J=v>Vkxe|UtHfZnv9gXj%!|!Adc{IUCKtQOC{!R4tE*B z&B!pxxZm_J50{shN7t3s-Rh4#hBcN&J35UD_zew9`RMgv@aZ1`{Y9a`Z*PH6cr>p! zVw4Q7)dbbv5s5^f&YwLi9D=`!f;N~H%;PsjV<4@*tJ-ZeaZ-z%XuqPFs$jbV2OR7>9UHAXizE{?OPv#YGIxVZRH8B@!qY~`Xk z<(a5zUWrN>j$tnf=VR0KszkBV&WhXUWubAnQm<>~-dbP1CKvaf%utu`L>L5aFdolq zDWl|mZo=yz%EOkvOdYW+B0Z2*j&(vo{Mu2#?%oSJ!;OG+KN7@mg#pJ*DA;}o0u0Ik zxc0wdeJnfS$(d?VH5!62A6!(cThYo7cLq<3nF~j;#)Gr7UqNkf%X}p_g7xO-M?oX9 z$Jxz#e6X{~o-dI|=zmeQzH2qfe$JIW9-f%kttI95d>r*{QyDXZFu}p=oQSnItr$8k zkhD-6QNZJnU5yw`uw{|04>Pr{b7H7JlJ*#0sHN46r0Q)NDD%qpvC4n>tgaDotn@Wm zX1IaAzU##^mKOvKZEbDu=G>4{o0u!84*3H~BCqbrlNbjF2cH^|ttF}G9)fL7ObxTj zAN5)eALst2*^zbV_t^=Z=rXs}87Ri0MTa`CLG^ z#)!f#U7@%-TZ8<;(_=S7JGpen<9Hr!=A1MQ(y1Yieb|&NTHX`*&h@6}y4gOqK6=@R zy#S>rCc5Uxo<<&oNeiMK?(+UTS?|jqC(EKhXtD*-BCp>cx;ZApM0?9QD5PL^9}s;9 z5nHXHGYCk!sT*;oIgGC4xo%^M$e^#oG$b#ZWpA2QE?*r!w*U|*#;A?BeK$&#?LJO+ z83vbMx9FHmomf=#^z;NC)R(5ev{Ch3XC2`v1RIgekxQ@_6`nh}s-RjrDQGIU$TA5A swr^H<@Aw=iV78Of4(q`L-32T_ALu=okeQIA{gS}jlSFvv@zdr10N`PVYXATM literal 0 HcmV?d00001 diff --git a/src/engine/renderer.py b/src/engine/renderer.py index 89a0126..e4a7558 100644 --- a/src/engine/renderer.py +++ b/src/engine/renderer.py @@ -206,9 +206,9 @@ class Renderer: rendered_text = text_font.render(widget.text, True, widget.color) if widget.hovered: - btn_image = widget.base_image - else: btn_image = widget.hover_image + else: + btn_image = widget.base_image btn_image = transform.scale(btn_image, (btn_image.get_width()*window_size[0]/self.window_size[0], btn_image.get_height()*window_size[0]/self.window_size[0])) diff --git a/src/main.py b/src/main.py index d505fbb..4746e4c 100644 --- a/src/main.py +++ b/src/main.py @@ -37,8 +37,9 @@ class Game(Engine): menu.add_widget(Label(0.5, 0.1, "The Forest's Secret", 0.1, (0, 255, 0), True, 2)) base_image = pygame.image.load("assets/textures/GUI/button_1.png").convert_alpha() + hover_image = pygame.image.load("assets/textures/GUI/button_2.png").convert_alpha() - menu.add_widget(Button(0.5, 0.3, "boutton", 0.1, (0, 255, 0), lambda : print("play"), base_image, base_image, True, 0)) + menu.add_widget(Button(0.5, 0.3, "boutton", 0.1, (0, 255, 0), lambda : print("play"), base_image, hover_image, True, 0)) self.menu_manager.register_menu(menu, "main") self.menu_manager.show("main") From fe2c07b5ace437b119de3200c89db97aefb9da36 Mon Sep 17 00:00:00 2001 From: Yannis300307 Date: Sun, 7 Jan 2024 18:29:18 +0100 Subject: [PATCH 35/37] Ajout du menu principal --- src/engine/menu_manager.py | 31 ++++++++++++++++++------------- src/engine/renderer.py | 12 ++++++++++-- src/main.py | 8 ++++++-- 3 files changed, 34 insertions(+), 17 deletions(-) diff --git a/src/engine/menu_manager.py b/src/engine/menu_manager.py index 062e181..e972a35 100644 --- a/src/engine/menu_manager.py +++ b/src/engine/menu_manager.py @@ -68,23 +68,28 @@ class MenuManager: """Ajoute le menu donné au manager de menu avec le nom donné.""" self.menus[name] = menu - # On itère dans tous les bouttons pour leur ajouter une interaction - for btn in menu.widgets: - if isinstance(btn, Button): - width = btn.base_image.get_width()/self.engine.renderer.window_size[0] - height = btn.base_image.get_height()/self.engine.renderer.window_size[1] - area_x = btn.x - area_y = btn.y - if btn.centered: - area_x -= width/2 - area_y -= height/2 - self.engine.event_handler.register_button_area((area_x, area_y, width, height), btn.callback, btn.area_name, - btn.is_window_relative, btn.set_hover_state) - def show(self, name: str): """Affiche le menu au nom donné.""" self.active_menu = self.menus[name] + # On itère dans tous les bouttons pour leur ajouter une interaction + for btn in self.active_menu.widgets: + if isinstance(btn, Button): + width = btn.base_image.get_width() / self.engine.renderer.window_size[0] + height = btn.base_image.get_height() / self.engine.renderer.window_size[1] + area_x = btn.x + area_y = btn.y + if btn.centered: + area_x -= width / 2 + area_y -= height / 2 + self.engine.event_handler.register_button_area((area_x, area_y, width, height), btn.callback, + btn.area_name, + btn.is_window_relative, btn.set_hover_state) + def hide(self): """Affiche le menu actuelement à l'écran.""" + # On itère dans tous les bouttons pour retirer l'interaction + for btn in self.active_menu.widgets: + if isinstance(btn, Button): + self.engine.event_handler.remove_button_area(btn.area_name) self.active_menu = None diff --git a/src/engine/renderer.py b/src/engine/renderer.py index e4a7558..5e53da0 100644 --- a/src/engine/renderer.py +++ b/src/engine/renderer.py @@ -209,8 +209,16 @@ class Renderer: btn_image = widget.hover_image else: btn_image = widget.base_image - btn_image = transform.scale(btn_image, (btn_image.get_width()*window_size[0]/self.window_size[0], - btn_image.get_height()*window_size[0]/self.window_size[0])) + + if widget.is_window_relative == 0: + btn_image = transform.scale(btn_image, (btn_image.get_width()*window_size[0]/self.window_size[0], + btn_image.get_height()*window_size[0]/self.window_size[0])) + elif widget.is_window_relative == 1: + btn_image = transform.scale(btn_image, (btn_image.get_width()*window_size[1]/self.window_size[1], + btn_image.get_height()*window_size[1]/self.window_size[1])) + elif widget.is_window_relative == 2: + btn_image = transform.scale(btn_image, (btn_image.get_width()*window_size[0]/self.window_size[0], + btn_image.get_height()*window_size[1]/self.window_size[1])) # On affiche l'image du boutton if widget.centered: diff --git a/src/main.py b/src/main.py index 4746e4c..4e156ed 100644 --- a/src/main.py +++ b/src/main.py @@ -21,7 +21,7 @@ class Game(Engine): self.DEBUG_MODE = True - self.game_state = GameState.NORMAL + self.game_state = GameState.MAIN_MENU self.event_sheduler.register_area((64, 64, 32, 32), lambda _: self.dialogs_manager.start_dialog("test"), ["player"], False, True) @@ -31,6 +31,10 @@ class Game(Engine): self.setup_main_menu() + def start_game(self): + self.game_state = GameState.NORMAL + self.menu_manager.hide() + def setup_main_menu(self): """Crée les éléments du menu principal.""" menu = Menu() @@ -39,7 +43,7 @@ class Game(Engine): base_image = pygame.image.load("assets/textures/GUI/button_1.png").convert_alpha() hover_image = pygame.image.load("assets/textures/GUI/button_2.png").convert_alpha() - menu.add_widget(Button(0.5, 0.3, "boutton", 0.1, (0, 255, 0), lambda : print("play"), base_image, hover_image, True, 0)) + menu.add_widget(Button(0.5, 0.3, "play", 0.08, (0, 255, 0), self.start_game, base_image, hover_image, True, 0)) self.menu_manager.register_menu(menu, "main") self.menu_manager.show("main") From 059559a474589805675f84d0db70185ababc50fb Mon Sep 17 00:00:00 2001 From: Yannis300307 Date: Sun, 7 Jan 2024 18:30:39 +0100 Subject: [PATCH 36/37] Changement du type d'adaptation du titre du jeu --- src/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.py b/src/main.py index 4e156ed..8910a5f 100644 --- a/src/main.py +++ b/src/main.py @@ -38,7 +38,7 @@ class Game(Engine): def setup_main_menu(self): """Crée les éléments du menu principal.""" menu = Menu() - menu.add_widget(Label(0.5, 0.1, "The Forest's Secret", 0.1, (0, 255, 0), True, 2)) + menu.add_widget(Label(0.5, 0.1, "The Forest's Secret", 0.1, (0, 255, 0), True, 0)) base_image = pygame.image.load("assets/textures/GUI/button_1.png").convert_alpha() hover_image = pygame.image.load("assets/textures/GUI/button_2.png").convert_alpha() From 85801350028468b760971606e862be91d6a6e080 Mon Sep 17 00:00:00 2001 From: Yannis300307 Date: Sun, 7 Jan 2024 18:35:18 +0100 Subject: [PATCH 37/37] Changement du texte en noir --- src/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.py b/src/main.py index 8910a5f..24ccfbd 100644 --- a/src/main.py +++ b/src/main.py @@ -38,12 +38,12 @@ class Game(Engine): def setup_main_menu(self): """Crée les éléments du menu principal.""" menu = Menu() - menu.add_widget(Label(0.5, 0.1, "The Forest's Secret", 0.1, (0, 255, 0), True, 0)) + menu.add_widget(Label(0.5, 0.1, "The Forest's Secret", 0.1, (0, 0, 0), True, 0)) base_image = pygame.image.load("assets/textures/GUI/button_1.png").convert_alpha() hover_image = pygame.image.load("assets/textures/GUI/button_2.png").convert_alpha() - menu.add_widget(Button(0.5, 0.3, "play", 0.08, (0, 255, 0), self.start_game, base_image, hover_image, True, 0)) + menu.add_widget(Button(0.5, 0.3, "play", 0.08, (0, 0, 0), self.start_game, base_image, hover_image, True, 0)) self.menu_manager.register_menu(menu, "main") self.menu_manager.show("main")