From fa8b5042ba2904e0340bda6d77ee395b0f5065af Mon Sep 17 00:00:00 2001 From: Tipragot Date: Wed, 1 Nov 2023 18:45:55 +0100 Subject: [PATCH] =?UTF-8?q?Ajout=20d'un=20syst=C3=A8me=20d'audio?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/engine/ecs.py | 8 ++++ src/main.py | 12 +++++- src/plugins/animation.py | 2 +- src/plugins/defaults.py | 5 ++- src/plugins/sound.py | 79 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 102 insertions(+), 4 deletions(-) create mode 100644 src/plugins/sound.py diff --git a/src/engine/ecs.py b/src/engine/ecs.py index ad61ff8..8e58b65 100644 --- a/src/engine/ecs.py +++ b/src/engine/ecs.py @@ -44,6 +44,14 @@ class Entity: """ return self.__identifier + def __eq__(self, __value: object) -> bool: + if isinstance(__value, Entity): + return self.__identifier == __value.identifier + return False + + def __hash__(self) -> int: + return self.__identifier + def __repr__(self) -> str: return f"Entity({self.__identifier})" diff --git a/src/main.py b/src/main.py index b9d1495..f1c1477 100644 --- a/src/main.py +++ b/src/main.py @@ -5,13 +5,23 @@ Module d'exemple de l'utilisation du moteur de jeu. from engine import Scene, start_game from plugins import assets, defaults from plugins.animation import Animation +from plugins.sound import Sound start_game( defaults.PLUGIN, assets.loading_scene( Scene( - [lambda world: world.new_entity().set(Animation("animations/intro"))], + [ + lambda world: world.new_entity().set( + Animation( + "animations/intro", + callback=lambda world, entity: entity.set( + Sound(world[assets.Assets].get_sound("edqsd")) + ), + ) + ) + ], [], [], ), diff --git a/src/plugins/animation.py b/src/plugins/animation.py index 499435a..5ea69b3 100644 --- a/src/plugins/animation.py +++ b/src/plugins/animation.py @@ -85,8 +85,8 @@ def __update_animations(world: World) -> None: PLUGIN = GlobalPlugin( + [], [], [__update_animations], [], - [], ) diff --git a/src/plugins/defaults.py b/src/plugins/defaults.py index 9f83fbc..e963ca1 100644 --- a/src/plugins/defaults.py +++ b/src/plugins/defaults.py @@ -2,7 +2,7 @@ Plugin qui rassemple tous les plugins globaux. """ -from plugins import animation, assets, display, inputs, render, text, timing +from plugins import animation, assets, display, inputs, render, sound, text, timing PLUGIN = ( @@ -10,7 +10,8 @@ PLUGIN = ( + timing.PLUGIN + assets.PLUGIN + inputs.PLUGIN - + animation.PLUGIN + + sound.PLUGIN + text.PLUGIN + + animation.PLUGIN + render.PLUGIN ) diff --git a/src/plugins/sound.py b/src/plugins/sound.py new file mode 100644 index 0000000..0396041 --- /dev/null +++ b/src/plugins/sound.py @@ -0,0 +1,79 @@ +""" +Un plugin permettant de jouer des sons. +""" + + +from typing import Callable +import pygame +from engine import GlobalPlugin, KeepAlive +from engine.ecs import Entity, World + + +class Channels(KeepAlive, dict[Entity, pygame.mixer.Channel]): + """ + Ressource qui stoque les sons actuellement joués dans le jeu. + """ + + +class Sound: + """ + Composant permettant de jouer un son. + """ + + def __init__( + self, + sound: pygame.mixer.Sound, + loop: bool = False, + volume: float = 1.0, + fade_ms: int = 0, + callback: Callable[[World, Entity], object] = lambda _w, _e: None, + ): + self.sound = sound + self.loop = loop + self.volume = volume + self.fade_ms = fade_ms + self.callback = callback + + +def __initialize(world: World): + """ + Ajoute les ressources utiles pour le plugin. + """ + world.set(Channels()) + + +def __update_sounds(world: World): + """ + Met à jour les sons du jeu. + """ + # Ajout des sons non gérés + channels = world[Channels] + sound_entities = world.query(Sound) + for entity in sound_entities: + if entity not in channels: + sound = entity[Sound] + channel = sound.sound.play(sound.loop, fade_ms=sound.fade_ms) + if channel is not None: # type: ignore + channel.set_volume(sound.volume) + channels[entity] = channel + + # On supprime les sons qui sont arrêtés ou qui n'ont plus d'entité + channels_to_remove: list[Entity] = [] + for entity, channel in channels.items(): + if not channel.get_busy() and Sound in entity: + callback = entity[Sound].callback + del entity[Sound] + callback(world, entity) + elif entity not in sound_entities: + channel.stop() + channels_to_remove.append(entity) + for entity in channels_to_remove: + del channels[entity] + + +PLUGIN = GlobalPlugin( + [__initialize], + [], + [__update_sounds], + [], +)