From 5ca7ed5195604ac7244ab9503b66a0276477462e Mon Sep 17 00:00:00 2001 From: Faraphel Date: Thu, 9 Mar 2023 14:31:46 +0100 Subject: [PATCH] implemented settings --- NOTE.md | 7 +- main.pyw | 4 +- source/gui/{sound => media}/Game.py | 4 +- source/gui/{sound => media}/__init__.py | 0 source/gui/media/abc/MediaGroup.py | 26 ++++ source/gui/media/abc/__init__.py | 1 + source/gui/media/type/Sound.py | 18 +++ source/gui/{sound => media}/type/__init__.py | 0 source/gui/media/type/abc/Media.py | 34 +++++ source/gui/media/type/abc/__init__.py | 1 + source/gui/scene/Game.py | 20 +-- source/gui/scene/GameResult.py | 2 +- source/gui/scene/HistoryGame.py | 10 +- source/gui/scene/HistoryMenu.py | 10 +- source/gui/scene/Settings.py | 149 +++++++++++++++++-- source/gui/scene/abc/BaseGame.py | 14 +- source/gui/sound/abc/SoundGroup.py | 11 -- source/gui/sound/abc/__init__.py | 1 - source/gui/sound/type/Sound.py | 13 -- source/gui/sound/type/abc/SoundType.py | 41 ----- source/gui/sound/type/abc/__init__.py | 1 - source/gui/widget/Scroller.py | 2 +- source/gui/window/GameWindow.py | 13 +- 23 files changed, 274 insertions(+), 108 deletions(-) rename source/gui/{sound => media}/Game.py (86%) rename source/gui/{sound => media}/__init__.py (100%) create mode 100644 source/gui/media/abc/MediaGroup.py create mode 100644 source/gui/media/abc/__init__.py create mode 100644 source/gui/media/type/Sound.py rename source/gui/{sound => media}/type/__init__.py (100%) create mode 100644 source/gui/media/type/abc/Media.py create mode 100644 source/gui/media/type/abc/__init__.py delete mode 100644 source/gui/sound/abc/SoundGroup.py delete mode 100644 source/gui/sound/abc/__init__.py delete mode 100644 source/gui/sound/type/Sound.py delete mode 100644 source/gui/sound/type/abc/SoundType.py delete mode 100644 source/gui/sound/type/abc/__init__.py diff --git a/NOTE.md b/NOTE.md index 0c88d74..f58f880 100644 --- a/NOTE.md +++ b/NOTE.md @@ -2,11 +2,12 @@ A faire : 1. Principal : - - Paramètres (contenu : fps, volume dans le jeu, plein écran, ...) (bouton dans le jeu) - Documenter (Docstring, README, ...) + - test avec "assert" (cahier des charges) + - mode d'emploi (video + pdf) expliquant le fonctionnement 2. Visuel : - - animations, mettre la musique, ... + - animations de fin, mettre la musique, ... - Voir les TODOs 3. Bug : @@ -14,5 +15,3 @@ A faire : 4. Vérification : - Tester sur Linux - - test avec "assert" (cahier des charges) - - mode d'emploi (video + pdf) expliquant le fonctionnement diff --git a/main.pyw b/main.pyw index 8bd8710..a2854a1 100644 --- a/main.pyw +++ b/main.pyw @@ -13,10 +13,10 @@ Label.default_kwargs["font_name"] = "Century Gothic" # NOQA: Label à un "defau # Create a new window -window = GameWindow(resizable=True, vsync=False, caption="Bataille Navale") +window = GameWindow(resizable=True, vsync=True, caption="Bataille Navale") window.set_minimum_size(720, 480) window.add_scene(MainMenu) # Start the event loop -pyglet.app.run(interval=0) +pyglet.app.run() diff --git a/source/gui/sound/Game.py b/source/gui/media/Game.py similarity index 86% rename from source/gui/sound/Game.py rename to source/gui/media/Game.py index d74c61d..28932c5 100644 --- a/source/gui/sound/Game.py +++ b/source/gui/media/Game.py @@ -1,11 +1,11 @@ from .type import Sound -from .abc import SoundGroup +from .abc import MediaGroup from source.path import path_sound path = path_sound / "game" -class Game(SoundGroup): +class Game(MediaGroup): touched = Sound(path / "touched.wav") sunken_ally = Sound(path / "sunken_ally.wav") won = Sound(path / "won.wav") diff --git a/source/gui/sound/__init__.py b/source/gui/media/__init__.py similarity index 100% rename from source/gui/sound/__init__.py rename to source/gui/media/__init__.py diff --git a/source/gui/media/abc/MediaGroup.py b/source/gui/media/abc/MediaGroup.py new file mode 100644 index 0000000..4af891d --- /dev/null +++ b/source/gui/media/abc/MediaGroup.py @@ -0,0 +1,26 @@ +from abc import ABC + +import pyglet + + +class MediaGroup(ABC): + """ + This class represent a music group that can be played. + """ + + player: pyglet.media.Player + + def __init_subclass__(cls, **kwargs): + cls.player = pyglet.media.Player() + + @classmethod + def get(cls, item, default=None): + return getattr(cls, item, default) + + @classmethod + def get_volume(cls): + return cls.player.volume + + @classmethod + def set_volume(cls, value: float): + cls.player.volume = value diff --git a/source/gui/media/abc/__init__.py b/source/gui/media/abc/__init__.py new file mode 100644 index 0000000..211c4d0 --- /dev/null +++ b/source/gui/media/abc/__init__.py @@ -0,0 +1 @@ +from .MediaGroup import MediaGroup diff --git a/source/gui/media/type/Sound.py b/source/gui/media/type/Sound.py new file mode 100644 index 0000000..caa4c91 --- /dev/null +++ b/source/gui/media/type/Sound.py @@ -0,0 +1,18 @@ +from pathlib import Path +from typing import TYPE_CHECKING + +import pyglet + +from source.gui.media.type.abc import Media + + +if TYPE_CHECKING: + from source.gui.media.abc import MediaGroup + + +class Sound(Media): + def __init__(self, path: Path): + self.path = path + + def __get__(self, instance, owner: "MediaGroup") -> pyglet.media.Source: + return self.get_media(self.path, owner) diff --git a/source/gui/sound/type/__init__.py b/source/gui/media/type/__init__.py similarity index 100% rename from source/gui/sound/type/__init__.py rename to source/gui/media/type/__init__.py diff --git a/source/gui/media/type/abc/Media.py b/source/gui/media/type/abc/Media.py new file mode 100644 index 0000000..4de58d9 --- /dev/null +++ b/source/gui/media/type/abc/Media.py @@ -0,0 +1,34 @@ +from abc import ABC, abstractmethod +from pathlib import Path +from typing import TYPE_CHECKING + +import pyglet + + +if TYPE_CHECKING: + from source.gui.media.abc import MediaGroup + + +class Media(ABC): + loaded_media: dict[Path, pyglet.media.Source] = {} + + @classmethod + def get_media(cls, path: Path, owner: "MediaGroup") -> pyglet.media.Source: + if (media := cls.loaded_media.get(path)) is None: + # charge le son + media = pyglet.media.load(path) + cls.loaded_media[path] = media + + # modifie la fonction pour jouer le son en utilisant le player + def _play(): + owner.player.delete() # arrête la musique en cours s'il y en a une et vide la queue + owner.player.queue(media) # ajoute la musique à la queue + owner.player.play() # joue la musique + + media.play = _play + + return media + + @abstractmethod + def __get__(self, instance, owner) -> pyglet.media.Source: + pass diff --git a/source/gui/media/type/abc/__init__.py b/source/gui/media/type/abc/__init__.py new file mode 100644 index 0000000..340d035 --- /dev/null +++ b/source/gui/media/type/abc/__init__.py @@ -0,0 +1 @@ +from .Media import Media diff --git a/source/gui/scene/Game.py b/source/gui/scene/Game.py index 09497f3..d7c975f 100644 --- a/source/gui/scene/Game.py +++ b/source/gui/scene/Game.py @@ -10,7 +10,7 @@ from source.core.enums import BombState from source.core.error import InvalidBombPosition, PositionAlreadyShot from source.gui.scene import GameResult from source.gui.scene.abc import BaseGame -from source.gui import widget, texture, scene, sound +from source.gui import widget, texture, scene, media from source.network.packet import * from source.type import Point2D from source.utils import StoppableThread @@ -79,7 +79,7 @@ class Game(BaseGame): self.button_save = self.add_widget( widget.Button, - x=70*vw, y=0, width=15*vw, height=10*vh, + x=55*vw, y=0, width=15*vw, height=10*vh, label_text="Sauvegarder", @@ -294,10 +294,10 @@ class Game(BaseGame): # joue la musique associée à ce mouvement match bomb_state: - case BombState.NOTHING: sound.Game.touched.play() - case BombState.TOUCHED: sound.Game.missed.play() - case BombState.SUNKEN: sound.Game.sunken_ally.play() - case BombState.WON: sound.Game.loose.play() + case BombState.NOTHING: media.Game.touched.play() + case BombState.TOUCHED: media.Game.missed.play() + case BombState.SUNKEN: media.Game.sunken_ally.play() + case BombState.WON: media.Game.loose.play() # envoie le résultat à l'autre joueur PacketBombState(position=packet.position, bomb_state=bomb_state).send_connection(self.connection) @@ -327,10 +327,10 @@ class Game(BaseGame): # joue la musique associée à ce mouvement match packet.bomb_state: - case BombState.NOTHING: sound.Game.missed.play() - case BombState.TOUCHED: sound.Game.touched.play() - case BombState.SUNKEN: sound.Game.sunken_enemy.play() - case BombState.WON: sound.Game.won.play() + case BombState.NOTHING: media.Game.missed.play() + case BombState.TOUCHED: media.Game.touched.play() + case BombState.SUNKEN: media.Game.sunken_enemy.play() + case BombState.WON: media.Game.won.play() if packet.bomb_state is BombState.WON: # si cette bombe a touché le dernier bateau, alors l'on a gagné diff --git a/source/gui/scene/GameResult.py b/source/gui/scene/GameResult.py index 63557d1..20b09a9 100644 --- a/source/gui/scene/GameResult.py +++ b/source/gui/scene/GameResult.py @@ -2,7 +2,7 @@ from typing import TYPE_CHECKING import pyglet.clock -from source.gui import texture, widget, sound +from source.gui import texture, widget, media from source.gui.position import vw_full, vh_full from source.gui.scene.abc.Popup import Popup diff --git a/source/gui/scene/HistoryGame.py b/source/gui/scene/HistoryGame.py index b90e803..8cbeb72 100644 --- a/source/gui/scene/HistoryGame.py +++ b/source/gui/scene/HistoryGame.py @@ -36,9 +36,10 @@ class HistoryGame(BaseGame): self.previous = self.add_widget( widget.Button, - x=20*vw, y=10*vh, width=20*vw, height=10*vh, + x=35*vw, y=10*vh, width=5*vw, height=10*vh, - label_text="Précédent", + label_text="<", + label_font_size=20, style=texture.Button.Style1 ) @@ -47,9 +48,10 @@ class HistoryGame(BaseGame): self.next = self.add_widget( widget.Button, - x=60*vw, y=10*vh, width=20*vw, height=10*vh, + x=60*vw, y=10*vh, width=5*vw, height=10*vh, - label_text="Suivant", + label_text=">", + label_font_size=20, style=texture.Button.Style1 ) diff --git a/source/gui/scene/HistoryMenu.py b/source/gui/scene/HistoryMenu.py index 3b6e8a2..cf46fd4 100644 --- a/source/gui/scene/HistoryMenu.py +++ b/source/gui/scene/HistoryMenu.py @@ -74,9 +74,10 @@ class HistoryMenu(Scene): # si nous ne sommes pas à la première page, ajoute un bouton "précédent". self.previous = self.add_widget( widget.Button, - x=10*vw, y=45*vh, width=10*vw, height=10*vh, + x=10*vw, y=45*vh, width=8*vw, height=15*vh, - label_text="Précédent", + label_text="<", + label_font_size=30, style=texture.Button.Style1 ) @@ -90,9 +91,10 @@ class HistoryMenu(Scene): # si nous ne sommes pas à la dernière page, ajoute un bouton "suivant". self.next = self.add_widget( widget.Button, - x=80*vw, y=45*vh, width=10*vw, height=10*vh, + x=80*vw, y=45*vh, width=8*vw, height=15*vh, - label_text="Suivant", + label_text=">", + label_font_size=30, style=texture.Button.Style1 ) diff --git a/source/gui/scene/Settings.py b/source/gui/scene/Settings.py index 38cfc03..e995e03 100644 --- a/source/gui/scene/Settings.py +++ b/source/gui/scene/Settings.py @@ -1,6 +1,8 @@ from typing import TYPE_CHECKING -from source.gui import widget, texture +import pyglet.app + +from source.gui import widget, texture, media from source.gui.position import vw_full, vh_full, vw, vh from source.gui.scene.abc.Popup import Popup @@ -31,23 +33,152 @@ class Settings(Popup): self.back.add_listener("on_click_release", lambda *_: self.window.remove_scene(self)) - self.checkbox = self.add_widget( + # Plein écran + + self.fullscreen = self.add_widget( widget.Checkbox, - x=45*vw, y=45*vh, width=10*vw, height=10*vh, + x=70*vw, y=87*vh, width=6*vw, height=10*vh, - style=texture.Checkbox.Style1 + style=texture.Checkbox.Style1, + + state=self.window.fullscreen ) - self.checkbox.add_listener("on_click_release", - lambda *_: self.window.set_fullscreen(self.checkbox.state)) + self.fullscreen.add_listener( + "on_click_release", + lambda widget, *_: self.window.set_fullscreen(widget.state) + ) - self.scroller = self.add_widget( + self.add_widget( + widget.Text, + + x=80*vw, y=90*vh, + + text="Plein écran", + font_size=20, + ) + + # Vsync + + self.vsync = self.add_widget( + widget.Checkbox, + + x=70 * vw, y=76 * vh, width=6 * vw, height=10 * vh, + + style=texture.Checkbox.Style1, + + state=self.window.vsync + ) + + self.vsync.add_listener( + "on_click_release", + lambda widget, *_: self.window.set_vsync(widget.state) + ) + + self.add_widget( + widget.Text, + + x=80 * vw, y=79 * vh, + + text="V-Sync", + font_size=20, + ) + + # Compteur de FPS + + self.show_fps = self.add_widget( + widget.Checkbox, + + x=70 * vw, y=65 * vh, width=6 * vw, height=10 * vh, + + style=texture.Checkbox.Style1, + + state=self.window.fps_enable + ) + + self.show_fps.add_listener( + "on_click_release", + lambda widget, *_: self.window.set_fps_enabled(widget.state) + ) + + self.add_widget( + widget.Text, + + x=80 * vw, y=68 * vh, + + text="Compteur FPS", + font_size=20, + ) + + # Limite FPS + + self.fps_limit = self.add_widget( widget.Scroller, - x=30*vw, y=20*vh, width=30*vw, height=10*vh, + x=70*vw, y=54*vh, width=20*vw, height=10*vh, style=texture.Scroller.Style1, + from_=1, + value=60, + to=250, - text_transform=lambda value: round(value, 2) + text_transform=lambda value: round(value) if value <= 240 else "Illimité" + ) + + def change_fps(widget): + pyglet.clock.unschedule(pyglet.app.event_loop._redraw_windows) # NOQA + + if widget.value <= 240: + pyglet.clock.schedule_interval( + pyglet.app.event_loop._redraw_windows, # NOQA + 1 / widget.value + ) + else: + pyglet.clock.schedule(pyglet.app.event_loop._redraw_windows) # NOQA + + self.fps_limit.add_listener( + "on_value_change", + change_fps + ) + + self.add_widget( + widget.Text, + + x=92 * vw, y=57 * vh, + + text="FPS", + font_size=20, + ) + + # Volume + + self.volume_sfx = self.add_widget( + widget.Scroller, + + x=5 * vw, y=87 * vh, width=20 * vw, height=10 * vh, + + style=texture.Scroller.Style1, + from_=0, + value=media.Game.get_volume(), + to=1, + + text_transform=lambda value: f"{round(value * 100)}%" + ) + + def change_volume_sfx(widget): + media.Game.set_volume(widget.value) + + self.volume_sfx.add_listener( + "on_value_change", + change_volume_sfx + ) + + self.add_widget( + widget.Text, + + x=27 * vw, y=90 * vh, + + text="Effets Sonore", + font_size=20, ) diff --git a/source/gui/scene/abc/BaseGame.py b/source/gui/scene/abc/BaseGame.py index 6773259..d0e1efb 100644 --- a/source/gui/scene/abc/BaseGame.py +++ b/source/gui/scene/abc/BaseGame.py @@ -1,7 +1,7 @@ from abc import ABC from typing import TYPE_CHECKING -from source.gui import widget, texture +from source.gui import widget, texture, scene from source.gui.position import right, vw, vh, vw_full, vh_full, px from source.gui.scene.abc import Scene from source.type import Point2D @@ -106,6 +106,18 @@ class BaseGame(Scene, ABC): anchor_x="center", anchor_y="center" ) + self.button_settings = self.add_widget( + widget.Button, + + x=70 * vw, y=0, width=15 * vw, height=10 * vh, + + label_text="Paramètres", + + style=texture.Button.Style1 + ) + + self.button_settings.add_listener("on_click_release", lambda *_: self.window.add_scene(scene.Settings)) + self.button_quit = self.add_widget( widget.Button, diff --git a/source/gui/sound/abc/SoundGroup.py b/source/gui/sound/abc/SoundGroup.py deleted file mode 100644 index 10809c5..0000000 --- a/source/gui/sound/abc/SoundGroup.py +++ /dev/null @@ -1,11 +0,0 @@ -from abc import ABC - - -class SoundGroup(ABC): - """ - This class represent a music group that can be played. - """ - - @classmethod - def get(cls, item, default=None): - return getattr(cls, item, default) diff --git a/source/gui/sound/abc/__init__.py b/source/gui/sound/abc/__init__.py deleted file mode 100644 index 4caa4df..0000000 --- a/source/gui/sound/abc/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .SoundGroup import SoundGroup diff --git a/source/gui/sound/type/Sound.py b/source/gui/sound/type/Sound.py deleted file mode 100644 index d1b0b80..0000000 --- a/source/gui/sound/type/Sound.py +++ /dev/null @@ -1,13 +0,0 @@ -from pathlib import Path - -import pyglet - -from source.gui.sound.type.abc import SoundType - - -class Sound(SoundType): - def __init__(self, path: Path): - self.path = path - - def __get__(self, instance, owner) -> pyglet.media.Source: - return self.get_sound(self.path) diff --git a/source/gui/sound/type/abc/SoundType.py b/source/gui/sound/type/abc/SoundType.py deleted file mode 100644 index 37b4361..0000000 --- a/source/gui/sound/type/abc/SoundType.py +++ /dev/null @@ -1,41 +0,0 @@ -from abc import ABC, abstractmethod -from pathlib import Path - -import pyglet - - -class SoundType(ABC): - loaded_sound: dict[Path, pyglet.media.Source] = {} - player: pyglet.media.Player - - def __init_subclass__(cls, **kwargs): - cls.player = pyglet.media.Player() - - @classmethod - def get_sound(cls, path: Path) -> pyglet.media.Source: - if (sound := cls.loaded_sound.get(path)) is None: - # charge le son - sound = pyglet.media.load(path) - cls.loaded_sound[path] = sound - - # modifie la fonction pour jouer le son en utilisant le player - def _play(): - cls.player.delete() # arrête la musique en cours s'il y en a une et vide la queue - cls.player.queue(sound) # ajoute la musique à la queue - cls.player.play() # joue la musique - - sound.play = _play - - return sound - - @abstractmethod - def __get__(self, instance, owner) -> pyglet.image.AbstractImage: - pass - - @property - def volume(self): - return self.player.volume - - @volume.setter - def volume(self, volume: float): - self.player.volume = volume diff --git a/source/gui/sound/type/abc/__init__.py b/source/gui/sound/type/abc/__init__.py deleted file mode 100644 index 2f75779..0000000 --- a/source/gui/sound/type/abc/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .SoundType import SoundType diff --git a/source/gui/widget/Scroller.py b/source/gui/widget/Scroller.py index 52fb643..4f3d992 100644 --- a/source/gui/widget/Scroller.py +++ b/source/gui/widget/Scroller.py @@ -89,7 +89,7 @@ class Scroller(BoxWidget): self.label.text = str(self.text_transform(self.value)) def _refresh_cursor(self, rel_x: int): - self.value = rel_x / self.width + self.value = (rel_x / self.width) * (self.to - self.from_) + self.from_ # property diff --git a/source/gui/window/GameWindow.py b/source/gui/window/GameWindow.py index 0f505f7..d070321 100644 --- a/source/gui/window/GameWindow.py +++ b/source/gui/window/GameWindow.py @@ -12,13 +12,20 @@ class GameWindow(Window): # NOQA def __init__(self, fps_color: ColorRGBA = (255, 255, 255, 200), - fps_enable: bool = True, + fps_enable: bool = False, *args, **kwargs): super().__init__(*args, **kwargs) self._fps_counter = pyglet.window.FPSDisplay(self, color=fps_color) - self.fps_enable = fps_enable + self._fps_enable = fps_enable + + @property + def fps_enable(self): + return self._fps_enable + + def set_fps_enabled(self, value: bool): + self._fps_enable = value def on_draw_after(self): - if self.fps_enable: self._fps_counter.draw() + if self._fps_enable: self._fps_counter.draw()