implemented settings
This commit is contained in:
parent
6e6e42d54e
commit
5ca7ed5195
23 changed files with 274 additions and 108 deletions
7
NOTE.md
7
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
|
||||
|
|
4
main.pyw
4
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()
|
||||
|
||||
|
|
|
@ -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")
|
26
source/gui/media/abc/MediaGroup.py
Normal file
26
source/gui/media/abc/MediaGroup.py
Normal 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
|
1
source/gui/media/abc/__init__.py
Normal file
1
source/gui/media/abc/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
from .MediaGroup import MediaGroup
|
18
source/gui/media/type/Sound.py
Normal file
18
source/gui/media/type/Sound.py
Normal 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)
|
34
source/gui/media/type/abc/Media.py
Normal file
34
source/gui/media/type/abc/Media.py
Normal 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
|
1
source/gui/media/type/abc/__init__.py
Normal file
1
source/gui/media/type/abc/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
from .Media import Media
|
|
@ -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é
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
|
|
|
@ -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,
|
||||
|
||||
|
|
|
@ -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)
|
|
@ -1 +0,0 @@
|
|||
from .SoundGroup import SoundGroup
|
|
@ -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)
|
|
@ -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
|
|
@ -1 +0,0 @@
|
|||
from .SoundType import SoundType
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in a new issue