Compare commits

..

No commits in common. "Merge-in-game_assembly-(NO-MORRE-TIME)" and "main" have entirely different histories.

19 changed files with 197 additions and 5469 deletions

6
.gitignore vendored
View file

@ -160,9 +160,3 @@ cython_debug/
# option (not recommended) you can uncomment the following to ignore the entire idea folder. # option (not recommended) you can uncomment the following to ignore the entire idea folder.
.idea/ .idea/
# DEBUG OST
assets/OST/Hyrule Field - The Legend of Zelda Ocarina of Time.mp3
assets/OST/Lost Woods - The Legend of Zelda Ocarina of Time.mp3
assets/OST/Title Theme - The Legend of Zelda Ocarina of Time.mp3
assets/OST/Vampire Killer.mp3
assets/sounds/Vampire Killer.mp3

Binary file not shown.

Before

Width:  |  Height:  |  Size: 303 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 245 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 210 KiB

After

Width:  |  Height:  |  Size: 41 KiB

File diff suppressed because it is too large Load diff

View file

@ -2,12 +2,10 @@ from src.engine.entity import Entity
class Camera: class Camera:
def __init__(self, DEBUG_MODE: bool, zoom: float): def __init__(self):
self.DEBUG_MODE = DEBUG_MODE
self.x = 0 self.x = 0
self.y = 0 self.y = 0
self.zoom = zoom self.zoom = 1.75
# Décalage lors du mouvement du joueur # Décalage lors du mouvement du joueur
self.player_moving_offset = 100 self.player_moving_offset = 100
@ -21,12 +19,9 @@ class Camera:
self.followed_entity: Entity | None = None self.followed_entity: Entity | None = None
def update(self, delta: float, zoom: float): def update(self, delta: float):
"""Met à jour la caméra. Permet, par exemple, de faire le scrolling.""" """Met à jour la caméra. Permet, par exemple, de faire le scrolling."""
if not self.DEBUG_MODE:
self.zoom = zoom
# Si on suit une entité, on met à jour les coordonnées de suivi # Si on suit une entité, on met à jour les coordonnées de suivi
if self.followed_entity is not None: if self.followed_entity is not None:
self.target_x = (self.followed_entity.x + self.followed_entity.mouvements[0] * self.target_x = (self.followed_entity.x + self.followed_entity.mouvements[0] *

View file

@ -11,7 +11,6 @@ from src.engine.menu_manager import MenuManager
from src.engine.renderer import Renderer from src.engine.renderer import Renderer
from src.engine.enums import GameState from src.engine.enums import GameState
from src.engine.sound_manager import SoundManager from src.engine.sound_manager import SoundManager
from src.engine.settings_manager import SettingsManager
import pygame import pygame
@ -30,90 +29,43 @@ class Engine:
self.running = False self.running = False
# Composants du moteur de jeu # Composants du moteur de jeu
self.settings_manager = SettingsManager(60, 1.75) # DOIT ABSOLUMENT ETRE EN PREMIER (Sinon les autres composants qui nécessite les settings crash)
self.renderer = Renderer(self) self.renderer = Renderer(self)
self.event_handler = EventHandler(self) self.event_handler = EventHandler(self)
self.map_manager = MapManager() self.map_manager = MapManager()
self.camera = Camera(self.DEBUG_MODE, self.settings_manager.get_zoom()) self.camera = Camera()
self.entity_manager = EntityManager(self.map_manager) self.entity_manager = EntityManager(self.map_manager)
self.boss_fight_manager = BossFightManager(self) self.boss_fight_manager = BossFightManager(self)
self.event_sheduler = EventSheduler(self) self.event_sheduler = EventSheduler(self)
self.dialogs_manager = DialogsManager(self) self.dialogs_manager = DialogsManager(self)
self.menu_manager = MenuManager(self) self.menu_manager = MenuManager(self)
self.sound_manager = SoundManager(self.settings_manager.get_music_master_volume(), self.sound_manager = SoundManager(60)
self.settings_manager.get_sound_global_master_volume(),
self.settings_manager.get_sound_master_volume())
self.global_latency = 0
self.last_latency = []
self.latency_precision = self.settings_manager.latency_precision
def loop(self): def loop(self):
"""Fonction à lancer au début du programme et qui va lancer les updates dans une boucle. """Fonction à lancer au début du programme et qui va lancer les updates dans une boucle.
Attend jusqu'à la fin du jeu.""" Attend jusqu'à la fin du jeu."""
self.running = True self.running = True
# Initialisation ddes valeurs de delta et de last_time
delta = 1. # Le delta est le temps depuis la dernière image delta = 1. # Le delta est le temps depuis la dernière image
last_time = time.time() last_time = time.time_ns()/10E8
while self.running: while self.running:
refresh_rate = self.settings_manager.get_refresh_rate() self.update(delta)
if refresh_rate == -1: # Pas de limite, vers l'infini et l'au-delà !!!
self.update(delta) new_time = time.time_ns()/10E8
new_time = time.time() delta = new_time-last_time
delta = new_time - last_time last_time = new_time
last_time = new_time
else:
while time.time() < last_time + 1 / refresh_rate - self.global_latency:
pass
new_time = time.time()
delta = new_time-last_time
last_time = new_time
self.update(delta)
new_refresh_rate = self.settings_manager.get_refresh_rate()
if refresh_rate != new_refresh_rate:
refresh_rate = new_refresh_rate
self.global_latency = 0
self.last_latency = []
latency = 0
latency = delta - 1/refresh_rate
if not latency > self.global_latency * 100 or self.global_latency == 0: # Impossible que le jeu prenne autant de retard, on skip cette latence dans le calcul, l'utilisateur a surement cliquer hors de la fenêtre
if len(self.last_latency) < self.latency_precision:
self.last_latency.append(latency)
else:
self.last_latency.pop(0)
self.last_latency.append(latency)
n = 0
for i in self.last_latency:
n += i
self.global_latency = n/len(self.last_latency)
def update(self, delta: float): def update(self, delta: float):
"""Fonction qui regroupe toutes les updates des composants. Elle permet de mettre à jour le jeu quand on """Fonction qui regroupe toutes les updates des composants. Elle permet de mettre à jour le jeu quand on
l'appelle.""" l'appelle."""
self.camera.update(delta, self.settings_manager.get_zoom()) self.camera.update(delta)
self.entity_manager.update(delta) self.entity_manager.update(delta)
self.renderer.update(delta) self.renderer.update(delta)
self.event_handler.update(delta) self.event_handler.update(delta)
self.event_sheduler.update() self.event_sheduler.update()
self.dialogs_manager.update(delta) self.dialogs_manager.update(delta)
self.sound_manager.update(delta, self.settings_manager.get_music_master_volume(), self.sound_manager.update(delta)
self.settings_manager.get_sound_global_master_volume(),
self.settings_manager.get_sound_master_volume())
def stop(self): def stop(self):
"""Arrête le programme.""" """Arrête le programme."""
self.running = False self.running = False
pygame.quit() pygame.quit()

View file

@ -1,6 +1,5 @@
import math import math
from src.engine.enums import EntityDeathResult
from src.engine.map_manager import MapManager from src.engine.map_manager import MapManager
from src.engine.mobs_AI import MobAI from src.engine.mobs_AI import MobAI
@ -43,9 +42,6 @@ class Entity:
self.shadow = None self.shadow = None
self.death_callback = None
self.death_result = EntityDeathResult.REMOVED
def set_default_life(self, life: int): def set_default_life(self, life: int):
"""Définit le nombre de PV de l'entité. Mettre -1 pour rendre l'entité immortelle.""" """Définit le nombre de PV de l'entité. Mettre -1 pour rendre l'entité immortelle."""
self.life_points = life self.life_points = life

View file

@ -1,5 +1,4 @@
from src.engine.entity import Entity from src.engine.entity import Entity
from src.engine.enums import EntityDeathResult
from src.engine.map_manager import MapManager from src.engine.map_manager import MapManager
@ -30,16 +29,10 @@ class EntityManager:
def update(self, delta: float): def update(self, delta: float):
"""Met à jour toutes les entités enregistrées.""" """Met à jour toutes les entités enregistrées."""
for entity_name in list(self.entities.keys()): for entity_name in list(self.entities.keys()):
entity: Entity = self.entities[entity_name] entity = self.entities[entity_name]
entity.update(delta) entity.update(delta)
if entity.life_points == 0: if entity.life_points == 0:
if entity.death_callback is not None: self.entities.pop(entity_name)
entity.death_callback()
if entity.death_result == EntityDeathResult.REMOVED:
self.entities.pop(entity_name)
elif entity.death_result == EntityDeathResult.RESET_LIFE:
entity.life_points = entity.max_life_points
if entity.brain is not None and not self.paused: if entity.brain is not None and not self.paused:
entity.brain.update(delta) entity.brain.update(delta)

View file

@ -8,8 +8,3 @@ class GameState(Enum):
BOSS_FIGHT = 2 BOSS_FIGHT = 2
MAIN_MENU = 3 MAIN_MENU = 3
# AJouter si besoin, mais à utiliser de préférence avec parsimony # AJouter si besoin, mais à utiliser de préférence avec parsimony
class EntityDeathResult(Enum):
REMOVED = 0 # The entity is removed
RESET_LIFE = 1

View file

@ -225,9 +225,9 @@ class EventHandler:
if K_o in self.key_pressed: if K_o in self.key_pressed:
print(f"Player pos: X = {self.engine.entity_manager.get_by_name('player').x} " 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}") f"Y = {self.engine.entity_manager.get_by_name('player').y}")
self.key_pressed.remove(K_o)
if K_x in self.key_pressed: if K_x in self.key_pressed:
self.engine.settings_manager.zoom *= 1.01 self.engine.camera.target_zoom *= 1.01
if K_c in self.key_pressed: if K_c in self.key_pressed:
self.engine.settings_manager.zoom *= 0.99 self.engine.camera.target_zoom *= 0.99

View file

@ -89,15 +89,6 @@ class Button(Widget):
"""Modifie la valeur du hover.""" """Modifie la valeur du hover."""
self.hovered = state self.hovered = state
class Image(Widget):
"""Un widget d'image."""
def __init__(self, x: int | float, y: int | float, size: int | float, image_path: str, widget_name: str,
centered: bool = False, is_window_relative: int = -1):
super().__init__(x, y, is_window_relative, widget_name)
self.size = size
self.image = pygame.image.load(image_path)
self.centered = centered
class Menu: class Menu:
"""Un menu contenant des widgets.""" """Un menu contenant des widgets."""

View file

@ -9,7 +9,7 @@ from pygame.locals import RESIZABLE, SRCALPHA, FULLSCREEN
import src.engine.engine as engine import src.engine.engine as engine
from src.engine.animation import Anim from src.engine.animation import Anim
from src.engine.enums import GameState from src.engine.enums import GameState
from src.engine.menu_manager import Label, Button, Slider, Image from src.engine.menu_manager import Label, Button, Slider
class Renderer: class Renderer:
@ -17,13 +17,11 @@ class Renderer:
def __init__(self, core: 'engine.Engine'): def __init__(self, core: 'engine.Engine'):
self.engine = core self.engine = core
self.fullscreen_size = display.Info().current_w, display.Info().current_h
self.timer = 0 # Timer local self.timer = 0 # Timer local
self.window_type = RESIZABLE self.window_type = RESIZABLE
self.window_size = self.fullscreen_size if self.window_type == FULLSCREEN else ( self.window_size = (display.Info().current_w, display.Info().current_h) if self.window_type == FULLSCREEN else (
600, 600) 600, 600)
self.window = display.set_mode(self.window_size, self.window_type) self.window = display.set_mode(self.window_size, self.window_type)
self.tiles = [] self.tiles = []
self.tile_size = 0 self.tile_size = 0
self.animations: dict[str: Anim] = {} self.animations: dict[str: Anim] = {}
@ -177,11 +175,11 @@ class Renderer:
self.window.blit(font.SysFont("Arial", 20).render(f"FPS: {round(1/delta if delta else 1)}, Game Status: {'Paused' if self.engine.entity_manager.paused else 'Playing'}", True, (255, 0, 0)), self.window.blit(font.SysFont("Arial", 20).render(f"FPS: {round(1/delta if delta else 1)}, Game Status: {'Paused' if self.engine.entity_manager.paused else 'Playing'}", True, (255, 0, 0)),
(0, 0)) (0, 0))
player = self.engine.entity_manager.get_by_name('player') player = self.engine.entity_manager.get_by_name('player')
self.window.blit(font.SysFont("Arial", 20).render(f"X: {round(player.x, 2):.2f} Y:{round(player.y, 2):.2f}", self.window.blit(font.SysFont("Arial", 20).render(f"X: {round(player.x, 2)} Y:{round(player.y, 2)}",
True, (255, 0, 0)), (0, 30)) True, (255, 0, 0)), (0, 30))
self.window.blit(font.SysFont("Arial", 20).render(f"Zoom: {round(self.engine.settings_manager.get_zoom(), 2)}", self.window.blit(font.SysFont("Arial", 20).render(f"Zoom: {round(self.engine.camera.zoom, 2)}",
True, (255, 0, 0)), (0, 60)) True, (255, 0, 0)), (0, 60))
self.window.blit(font.SysFont("Arial", 20).render(f"Volume: {self.engine.sound_manager.music_get_volume()}, Pos: {self.engine.sound_manager.music_get_current_song_pos():.3f}s, Index: {self.engine.sound_manager.music_current_index}, Paused: {self.engine.sound_manager.music_is_paused}", self.window.blit(font.SysFont("Arial", 20).render(f"Volume: {self.engine.sound_manager.music_get_volume()}, Pos: {self.engine.sound_manager.music_get_current_song_pos()}s, Index: {self.engine.sound_manager.music_current_index}, Paused: {self.engine.sound_manager.music_is_paused}",
True, (255, 0, 0)), (0, 90)) True, (255, 0, 0)), (0, 90))
self.window.blit(font.SysFont("Arial", 20).render(f"Track: {self.engine.sound_manager.music_current_song}", self.window.blit(font.SysFont("Arial", 20).render(f"Track: {self.engine.sound_manager.music_current_song}",
True, (255, 0, 0)), (0, 120)) True, (255, 0, 0)), (0, 120))
@ -386,36 +384,6 @@ class Renderer:
y - rail_image.get_height() // 2)) y - rail_image.get_height() // 2))
self.window.blit(slider_image, (x+widget.value*width-slider_image.get_width()//2, self.window.blit(slider_image, (x+widget.value*width-slider_image.get_width()//2,
y-slider_image.get_height()//2)) y-slider_image.get_height()//2))
elif isinstance(widget, Image):
if widget.is_window_relative == 0:
size = widget.size*window_size[0]
elif widget.is_window_relative == 1:
size = widget.size*window_size[1]
elif widget.is_window_relative == 2:
size = widget.size*min(window_size[0], window_size[1])
else:
size = widget.size
image = widget.image
if widget.is_window_relative == 0:
image = transform.scale(image, (image.get_width()*window_size[0]/self.window_size[0],
image.get_height()*window_size[0]/self.window_size[0]))
elif widget.is_window_relative == 1:
image = transform.scale(image, (image.get_width()*window_size[1]/self.window_size[1],
image.get_height()*window_size[1]/self.window_size[1]))
elif widget.is_window_relative == 2:
image = transform.scale(image, (image.get_width()*window_size[0]/self.window_size[0],
image.get_height()*window_size[1]/self.window_size[1]))
# On affiche l'image
if widget.centered:
self.window.blit(image, (x-image.get_width()//2,
y-image.get_height()//2))
else:
self.window.blit(image, (x, y))
def render_dialogs_box(self): def render_dialogs_box(self):
"""Rend la boite de dialogue lorsqu'un dialogue est lancé.""" """Rend la boite de dialogue lorsqu'un dialogue est lancé."""
@ -691,12 +659,4 @@ class Renderer:
self.fadein_fade_opacity = round(fade_opacity * 255 / 100) self.fadein_fade_opacity = round(fade_opacity * 255 / 100)
self.fadein_pause = pause_world self.fadein_pause = pause_world
self.fadein_fade_callback = callback self.fadein_fade_callback = callback
self.engine.entity_manager.pause() self.engine.entity_manager.pause()
def set_display(self, window_type: FULLSCREEN | RESIZABLE, size: tuple[int, int] = None):
self.window_type = window_type
self.window_size = self.fullscreen_size if self.window_type == FULLSCREEN else (
size[0], size[1])
self.window = display.set_mode(self.window_size, self.window_type)
display.flip()

View file

@ -1,27 +0,0 @@
class SettingsManager:
def __init__(self, default_master_volume: float, default_zoom: float) -> None:
self.refresh_rate = 30
self.latency_precision = 100 # Nombre de valeurs de latence stocké (Pour faire la moyenne)
self.master_volume = default_master_volume
self.sound_master_volume = 100
self.music_master_volume = 100
self.sound_global_master_volume = 100
self.zoom = default_zoom
def get_refresh_rate(self):
return self.refresh_rate
def get_zoom(self):
return self.zoom
def get_music_master_volume(self):
return round(self.master_volume / 100 * self.music_master_volume, 3)
def get_sound_global_master_volume(self):
return round(self.master_volume / 100 * self.sound_global_master_volume, 3)
def get_sound_master_volume(self):
return round(self.master_volume / 100 * self.sound_master_volume, 3)

View file

@ -1,113 +1,44 @@
from src.engine.entity import Entity from pygame import mixer
from random import randint
from pygame import mixer, error
from math import sqrt
from time import time
class SoundManager: class SoundManager:
def __init__(self, music_master_volume: float, sound_global_master_volume: float, sound_master_volume: float): def __init__(self, music_base_volume: float):
self.__tick = 0 # Compteur de la valeur d'un tick (Utilisé pour le comptage de tick) self.__tick = 0 # Compteur de la valeur d'un tick sur 1 (Utilisé pour le comptage de tick)
self.tick = 0 # Compteur de tick
self.time = 0 # Temps local a la class (en s) self.time = 0 # Temps local a la class (en s)
self.music_master_volume = music_master_volume
self.sound_global_master_volume = sound_global_master_volume
self.sound_master_volume = sound_master_volume
self.music_playlist = [] self.music_playlist = []
self.music_current_song = "" self.music_current_song = ""
self.music_play_playlist = False self.music_play_playlist = False
self.music_current_index = 0 self.music_current_index = 0
self.music_shuffle_playlist = True
self.music_next_request = False
self.music_set_volume(100)
self.music_before_pause_pos = 0 self.music_before_pause_pos = 0
self.music_before_pause_song = "" self.music_before_pause_song = ""
self.music_is_paused = False self.music_is_paused = False
self.music_pos_delay = 0 self.music_pos_delay = 0
self.sound_currently_playing: dict[float: list[mixer.Sound, float, list[float, float], float]] = {} # Format {unique_id : [Sound, max_volume, [pos_x, pos_y], stop_at]} self.music_set_volume(music_base_volume)
self.sound_loaded: dict[str: mixer.Sound] = {}# Format : {name: mixer.Sound}
self.sound_global_currently_playing: dict[float: list[mixer.Sound, float, float]] = {} # Format {unique_id: [Sound, volume, stop_at]}
self.sound_hears_anchor = None
def update(self, delta: float, music_master_volume: float, sound_global_master_volume: float, sound_master_volume: float): def update(self, delta: float):
self.__tick += delta self.__tick += delta
self.tick = int(self.__tick / delta) self.tick = int(self.__tick / delta)
self.time = self.tick * delta self.time = self.tick * delta
self.music_master_volume = music_master_volume
self.sound_global_master_volume = sound_global_master_volume
self.sound_master_volume = sound_master_volume
if self.sound_hears_anchor: # Update la position des "Oreilles" du joueur (Ou de l'entité séléctionné comme ancre pour les oreilles)
self.sound_hears_x = self.sound_hears_anchor.x
self.sound_hears_y = self.sound_hears_anchor.y
for key in self.sound_global_currently_playing.keys(): # Son globaux
sound_container: list[mixer.Sound, float, float] = self.sound_global_currently_playing[key]
if sound_container[2] > self.time:
self.sound_global_currently_playing.pop(key)
else:
sound_container[0].set_volume(round(sound_global_master_volume / 100 * sound_container[1] / 100, 3))
for key in self.sound_currently_playing.keys(): # Son locaux
sound_container: list[mixer.Sound, float, list[float, float], float] = self.sound_currently_playing[key]
if sound_container[3] > self.time: # Timeout des sons
self.sound_currently_playing.pop(key)
else: # Gère le volume en fonction de la position
sound = sound_container[0]
max_volume = sound_container[1]
pos_x, pos_y = sound_container[2]
sound.set_volume(max(0, int((round(sound_master_volume / 100 * max_volume / 100, 3)) - sqrt((pos_x - self.sound_hears_x) ** 2 + (pos_y - self.sound_hears_y) ** 2))) / (round(sound_master_volume / 100 * max_volume / 100, 3)))
if self.music_play_playlist and not self.music_is_paused: # Musique de fond if self.music_play_playlist and not self.music_is_paused: # Musique de fond
try: if not mixer.music.get_busy():
if not mixer.music.get_busy() or self.music_next_request:
if self.music_next_request: if len(self.music_playlist) == 0:
self.music_next_request = False pass
mixer.music.fadeout(1) elif self.music_current_song == "":
self.__music_play(self.music_playlist[0])
if len(self.music_playlist) == 0: else:
pass just_played_index = self.music_playlist.index(self.music_current_song)
elif self.music_current_song == "": if len(self.music_playlist) - 1 <= just_played_index: # Dernier son de la playlist / la playlist a rétréci entre temps
self.__music_play(self.music_playlist[0]) self.music_current_index = 0
self.__music_play(self.music_playlist[0]) # Recommence depuis le début de la playlist
else: else:
if self.music_current_song in self.music_playlist: self.music_current_index = just_played_index + 1
just_played_index = self.music_playlist.index(self.music_current_song) self.__music_play(self.music_playlist[self.music_current_index]) # Joue la musique suivante dans la playlist
if self.music_shuffle_playlist and len(self.music_playlist) != 1:
while True:
new_index = randint(0, len(self.music_playlist) - 1)
if new_index != just_played_index:
break
self.music_current_index = new_index
self.__music_play(self.music_playlist[new_index])
elif len(self.music_playlist) - 1 <= just_played_index: # Dernier son de la playlist / la playlist a rétréci entre temps
self.music_current_index = 0
self.__music_play(self.music_playlist[0]) # Recommence depuis le début de la playlist
else:
self.music_current_index = just_played_index + 1
self.__music_play(self.music_playlist[self.music_current_index]) # Joue la musique suivante dans la playlist
else: # Song removed from playlist, no idea what was the index, starting again from start or from random index if playlist_shuffle = True
new_index = randint(0, len(self.music_playlist) - 1)
self.music_current_index = new_index
self.__music_play(self.music_playlist[new_index])
except error:
pass
def music_get_volume(self): def music_get_volume(self):
@ -115,7 +46,7 @@ class SoundManager:
def music_set_volume(self, new_volume: float): def music_set_volume(self, new_volume: float):
"""Définit le nouveau volume de la musique""" """Définit le nouveau volume de la musique"""
mixer.music.set_volume(round(self.music_master_volume / 100 * new_volume / 100, 3)) mixer.music.set_volume((round(new_volume / 100, 3)))
def music_pause(self, fade_s: float, restart_tolerance: float = 33): def music_pause(self, fade_s: float, restart_tolerance: float = 33):
"""Met en pause la musique, la musique reprendra à la fin de la musique moin la tolérance (en pourcentage)""" """Met en pause la musique, la musique reprendra à la fin de la musique moin la tolérance (en pourcentage)"""
@ -130,12 +61,14 @@ class SoundManager:
self.music_before_pause_pos = 0 self.music_before_pause_pos = 0
self.music_before_pause_song = "" self.music_before_pause_song = ""
def music_get_current_song_pos(self): def music_get_current_song_pos(self):
if mixer.music.get_busy(): if mixer.music.get_busy():
return round(mixer.music.get_pos() / 1000 + self.music_pos_delay, 3) return round(mixer.music.get_pos() /1000 + self.music_pos_delay, 3)
else: else:
return round(self.music_before_pause_pos, 3) return round(self.music_before_pause_pos, 3)
def __music_play(self, song: str, fade_s: float = 0, start_at: float = 0): def __music_play(self, song: str, fade_s: float = 0, start_at: float = 0):
mixer.music.unload() mixer.music.unload()
mixer.music.load(song) mixer.music.load(song)
@ -151,7 +84,7 @@ class SoundManager:
def music_remove_from_playlist(self, song_path: str = None, index: int = None): def music_remove_from_playlist(self, song_path: str = None, index: int = None):
if song_path: if song_path:
index = self.music_playlist.index(song_path) index = self.music_playlist.index(song_path)
if index != None: if index:
self.music_playlist.pop(index) self.music_playlist.pop(index)
def music_start_playlist(self): def music_start_playlist(self):
@ -159,65 +92,3 @@ class SoundManager:
def music_stop_playlist(self): def music_stop_playlist(self):
self.music_play_playlist = False self.music_play_playlist = False
def music_playlist_set_shuffle(self, shuffle: bool):
self.music_shuffle_playlist = shuffle
def music_next(self):
self.music_next_request = True
def sound_link_hears(self, entity: Entity):
self.sound_hears_anchor = entity
def create_unique_id(self):
return time()*10e99999
def sound_load(self, file_path: str, name: str):
self.sound_loaded[name] = mixer.Sound(file_path)
def sound_play(self, name: str, max_volume: float, pos_x: float, pos_y: float):
sound = self.sound_loaded[name]
stop_at = stop_at = self.time + sound.get_length()
unique_id = self.create_unique_id()
self.sound_currently_playing[unique_id] = [sound, max_volume, [pos_x, pos_y], stop_at] # Format {unique_id : [Sound, max_volume, [pos_x, pos_y], stop_at]
return unique_id
def sound_stop(self, name: str, unique_id: float = None, all: bool = False):
if all:
for key in self.sound_currently_playing.keys():
self.sound_currently_playing.pop(key)[0].stop()
elif unique_id:
sound_container = self.sound_currently_playing.get(unique_id, None)
if sound_container:
self.sound_currently_playing.pop(unique_id)[0].stop()
else:
for key in self.sound_currently_playing.keys():
if self.sound_loaded[name] == self.sound_currently_playing[key][0]:
self.sound_currently_playing.pop(key)[0].stop()
def sound_global_play(self, name: str, volume: float):
"""Joue un son avec le même son dans tout le monde"""
sound = self.sound_loaded[name]
stop_at = self.time + sound.get_length()
unique_id = self.create_unique_id()
self.sound_global_currently_playing[unique_id] = [sound, volume, stop_at]
sound.play()
return unique_id
def sound_global_stop(self, name: str, unique_id: float = None, all: bool = False):
if all:
for key in self.sound_global_currently_playing.keys():
self.sound_global_currently_playing.pop(key)[0].stop()
elif unique_id:
sound_container = self.sound_global_currently_playing.get(unique_id, None)
if sound_container:
self.sound_global_currently_playing.pop(unique_id)[0].stop()
else:
for key in self.sound_global_currently_playing.keys():
if self.sound_loaded[name] == self.sound_global_currently_playing[key][0]:
self.sound_global_currently_playing.pop(key)[0].stop()

View file

@ -3,9 +3,9 @@ import pygame.image
from src.custom_AI import WolfAI from src.custom_AI import WolfAI
from src.engine.animation import Anim from src.engine.animation import Anim
from src.engine.engine import Engine from src.engine.engine import Engine
from src.engine.enums import GameState, EntityDeathResult from src.engine.enums import GameState
from src.engine.menu_manager import Menu, Label, Button, Image from src.engine.menu_manager import Menu, Label, Button
from pygame.locals import RESIZABLE, FULLSCREEN
class Game(Engine): class Game(Engine):
def __init__(self): def __init__(self):
@ -29,10 +29,6 @@ class Game(Engine):
self.event_handler.register_button_area((0, 0, 0.1, 0.1), lambda : print("salut"), 0) self.event_handler.register_button_area((0, 0, 0.1, 0.1), lambda : print("salut"), 0)
self.sound_manager.music_add_to_playlist(".\\assets\\OST\\Main Title (Y'as pas de boss la donc jpp le mettre pour un fight).mp3")
self.sound_manager.music_start_playlist()
self.setup_main_menu() self.setup_main_menu()
def start_game(self): def start_game(self):
@ -43,14 +39,10 @@ class Game(Engine):
self.renderer.fadeout(1, (0, 0, 0), 100, True, self.start_game) self.renderer.fadeout(1, (0, 0, 0), 100, True, self.start_game)
self.menu_manager.hide() self.menu_manager.hide()
self.sound_manager.music_remove_from_playlist(".\\assets\\OST\\Main Title (Y'as pas de boss la donc jpp le mettre pour un fight).mp3")
self.sound_manager.music_add_to_playlist(".\\assets\\OST\\Bruit de foret pour yannis.mp3")
self.sound_manager.music_next()
def setup_main_menu(self): def setup_main_menu(self):
"""Crée les éléments du menu principal.""" """Crée les éléments du menu principal."""
menu = Menu() menu = Menu()
menu.add_widget(Image(0, 0, 1, ".\\assets\\textures\\Title_Screen.png", "title_screen_image", False, 2)) menu.add_widget(Label(0.5, 0.1, "The Forest's Secret", 0.1, (0, 0, 0), "game_title", True, 0))
btn_base_image = pygame.image.load("assets/textures/GUI/button_1.png").convert_alpha() btn_base_image = pygame.image.load("assets/textures/GUI/button_1.png").convert_alpha()
btn_hover_image = pygame.image.load("assets/textures/GUI/button_2.png").convert_alpha() btn_hover_image = pygame.image.load("assets/textures/GUI/button_2.png").convert_alpha()
@ -59,42 +51,14 @@ class Game(Engine):
slider_hover_image = pygame.image.load("assets/textures/GUI/slider_cursor_2.png").convert_alpha() slider_hover_image = pygame.image.load("assets/textures/GUI/slider_cursor_2.png").convert_alpha()
slider_rail_image = pygame.image.load("assets/textures/GUI/slider_rail_1.png").convert_alpha() slider_rail_image = pygame.image.load("assets/textures/GUI/slider_rail_1.png").convert_alpha()
menu.add_widget(Button(0.5, 0.4, "Play", 0.08, (0, 0, 0), self.play_button_callback, btn_base_image, btn_hover_image, "play_button", True, 0)) menu.add_widget(Button(0.5, 0.3, "play", 0.08, (0, 0, 0), self.play_button_callback, btn_base_image, btn_hover_image, "play_button", True, 0))
self.menu_manager.register_menu(menu, "main") self.menu_manager.register_menu(menu, "main")
self.menu_manager.show("main") self.menu_manager.show("main")
self.create_boss_temple_area()
def setup_settings_menu(self):
"""Crée les éléments du menu de paramètre"""
menu = Menu()
menu.add_widget(Label(0, 0.3, "Paramètres", 0.05, (192,192,192), True, 0))
#base_image = pygame.image.load("assets\\textures\\GUI\\setting_menu.png")
#hover_image = pygame.image.load("assets\\textures\\GUI\\setting_menu_hovered.png")
def create_boss_temple_area(self):
"""Enregistre les zones d'entrées de boss fight."""
self.event_sheduler.register_area((3104, 608, 48, 16), lambda _: print("temple 1"), ["player"], True)
self.event_sheduler.register_area((4544, 592, 48, 16), lambda _: print("temple 2"), ["player"], True)
self.event_sheduler.register_area((5664, 688, 32, 16), lambda _: print("temple 3"), ["player"], True)
self.event_sheduler.register_area((6720, 720, 16, 32), lambda _: print("temple 4"), ["player"], True)
self.create_boss_temple_area()
def create_boss_temple_area(self):
"""Enregistre les zones d'entrées de boss fight."""
self.event_sheduler.register_area((3104, 608, 48, 16), lambda _: print("temple 1"), ["player"], True)
self.event_sheduler.register_area((4544, 592, 48, 16), lambda _: print("temple 2"), ["player"], True)
self.event_sheduler.register_area((5664, 688, 32, 16), lambda _: print("temple 3"), ["player"], True)
self.event_sheduler.register_area((6720, 720, 16, 32), lambda _: print("temple 4"), ["player"], True)
def create_player_entity(self): def create_player_entity(self):
"""Crée une entité joueur.""" """Crée une entité joueur."""
# On crée les animations
anim = Anim(0.5) anim = Anim(0.5)
anim.load_animation_from_directory("assets/textures/entities/player/none") anim.load_animation_from_directory("assets/textures/entities/player/none")
self.renderer.register_animation(anim, "player_none") self.renderer.register_animation(anim, "player_none")
@ -103,33 +67,18 @@ class Game(Engine):
anim.load_animation_from_directory("assets/textures/entities/player/walking") anim.load_animation_from_directory("assets/textures/entities/player/walking")
self.renderer.register_animation(anim, "player_walking") self.renderer.register_animation(anim, "player_walking")
# On crée l'entité
player = self.entity_manager.register_entity("player") player = self.entity_manager.register_entity("player")
player.link_animation("player_none") player.link_animation("player_none")
player.collision_rect = [-6, -7, 6, 16] player.collision_rect = [-6, -7, 6, 16]
player.death_result = EntityDeathResult.RESET_LIFE
player.death_callback = self.create_player_entity player.set_default_life(15)
player.max_speed = 64.0
self.entity_manager.set_player_entity("player") self.entity_manager.set_player_entity("player")
player.shadow = "player_shadow" player.shadow = "player_shadow"
self.renderer.register_shadow("assets/textures/entities/player/shadow.png", "player_shadow") self.renderer.register_shadow("assets/textures/entities/player/shadow.png", "player_shadow")
# On définit ses attributs
player.set_default_life(15)
player.max_speed = 64.0
player.x = 220.
player.y = 767.
# On place la caméra au niveau du joueur
self.camera.x = player.x
self.camera.y = player.y
self.camera.target_x = player.x
self.camera.target_y = player.y
# On enregistre l'entité
self.entity_manager.set_player_entity("player")
self.camera.follow_entity(player) self.camera.follow_entity(player)
def spawn_mobs(self): def spawn_mobs(self):