implemented settings

This commit is contained in:
Faraphel 2023-03-09 14:31:46 +01:00
parent 6e6e42d54e
commit 5ca7ed5195
23 changed files with 274 additions and 108 deletions

View file

@ -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

View file

@ -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()

View file

@ -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")

View file

@ -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

View file

@ -0,0 +1 @@
from .MediaGroup import MediaGroup

View file

@ -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)

View file

@ -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

View file

@ -0,0 +1 @@
from .Media import Media

View file

@ -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é

View file

@ -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

View file

@ -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
)

View file

@ -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
)

View file

@ -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,
)

View file

@ -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,

View file

@ -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)

View file

@ -1 +0,0 @@
from .SoundGroup import SoundGroup

View file

@ -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)

View file

@ -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

View file

@ -1 +0,0 @@
from .SoundType import SoundType

View file

@ -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

View file

@ -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()