From 00e72f4367d1da31d80cfbf1804f3fe18c5ce6ab Mon Sep 17 00:00:00 2001 From: Yannis300307 Date: Fri, 5 Jan 2024 17:00:30 +0100 Subject: [PATCH 01/23] 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/23] =?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/23] =?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/23] 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/23] 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/23] =?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/23] 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/23] =?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/23] 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/23] =?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/23] =?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/23] =?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/23] 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/23] =?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/23] =?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/23] 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/23] =?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/23] 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/23] 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/23] 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/23] =?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/23] 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/23] 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()