diff --git a/assets/krita/classique_arrow.kra b/assets/krita/classique_arrow.kra new file mode 100644 index 0000000..9dd55a9 Binary files /dev/null and b/assets/krita/classique_arrow.kra differ diff --git a/assets/krita/classique_background.kra b/assets/krita/classique_background.kra new file mode 100644 index 0000000..80c9500 Binary files /dev/null and b/assets/krita/classique_background.kra differ diff --git a/assets/krita/classique_button.kra b/assets/krita/classique_button.kra new file mode 100644 index 0000000..9e5e80b Binary files /dev/null and b/assets/krita/classique_button.kra differ diff --git a/assets/krita/search_bar.kra b/assets/krita/search_bar.kra new file mode 100644 index 0000000..1dce59c Binary files /dev/null and b/assets/krita/search_bar.kra differ diff --git a/assets/krita/valider.kra b/assets/krita/valider.kra new file mode 100644 index 0000000..5059a44 Binary files /dev/null and b/assets/krita/valider.kra differ diff --git a/assets/sounds/click.wav b/assets/sounds/click.wav deleted file mode 100644 index 2797a50..0000000 Binary files a/assets/sounds/click.wav and /dev/null differ diff --git a/assets/sounds/click/click0.wav b/assets/sounds/click/click0.wav new file mode 100644 index 0000000..db905d2 Binary files /dev/null and b/assets/sounds/click/click0.wav differ diff --git a/assets/sounds/click/click1.wav b/assets/sounds/click/click1.wav new file mode 100644 index 0000000..e4b267e Binary files /dev/null and b/assets/sounds/click/click1.wav differ diff --git a/assets/sounds/click/click2.wav b/assets/sounds/click/click2.wav new file mode 100644 index 0000000..5881f78 Binary files /dev/null and b/assets/sounds/click/click2.wav differ diff --git a/assets/sounds/lose_sound.wav b/assets/sounds/lose_sound.wav new file mode 100644 index 0000000..f324b3f Binary files /dev/null and b/assets/sounds/lose_sound.wav differ diff --git a/assets/sounds/menu_click.wav b/assets/sounds/menu_click.wav new file mode 100644 index 0000000..a92759a Binary files /dev/null and b/assets/sounds/menu_click.wav differ diff --git a/assets/sounds/win_sound.wav b/assets/sounds/win_sound.wav new file mode 100644 index 0000000..b80f922 Binary files /dev/null and b/assets/sounds/win_sound.wav differ diff --git a/assets/textures/classique/arrow.png b/assets/textures/classique/arrow.png new file mode 100644 index 0000000..26ffa24 Binary files /dev/null and b/assets/textures/classique/arrow.png differ diff --git a/assets/textures/classique/arrow_hover.png b/assets/textures/classique/arrow_hover.png new file mode 100644 index 0000000..7fa65a4 Binary files /dev/null and b/assets/textures/classique/arrow_hover.png differ diff --git a/assets/textures/classique/background.png b/assets/textures/classique/background.png new file mode 100644 index 0000000..1e2509e Binary files /dev/null and b/assets/textures/classique/background.png differ diff --git a/assets/textures/classique/play_again.png b/assets/textures/classique/play_again.png new file mode 100644 index 0000000..1848bba Binary files /dev/null and b/assets/textures/classique/play_again.png differ diff --git a/assets/textures/classique/play_again_hover.png b/assets/textures/classique/play_again_hover.png new file mode 100644 index 0000000..5ac69df Binary files /dev/null and b/assets/textures/classique/play_again_hover.png differ diff --git a/assets/textures/classique/valider.png b/assets/textures/classique/valider.png new file mode 100644 index 0000000..b3ae357 Binary files /dev/null and b/assets/textures/classique/valider.png differ diff --git a/assets/textures/classique/valider_hover.png b/assets/textures/classique/valider_hover.png new file mode 100644 index 0000000..9e3a40a Binary files /dev/null and b/assets/textures/classique/valider_hover.png differ diff --git a/src/engine.py b/src/engine.py index 5365097..c604f32 100644 --- a/src/engine.py +++ b/src/engine.py @@ -6,6 +6,7 @@ Un moteur de jeu inspiré de bevy. import json import math import os +import random from typing import Callable, Optional, Sequence, SupportsFloat, TypeVar, Union from time import time import pygame @@ -593,6 +594,12 @@ class Sound: stop_on_remove: bool = False, ) -> None: self.name = name + + if os.path.isdir(f"assets/sounds/{name}"): + list_files = os.listdir(f"assets/sounds/{name}") + random_file = random.choice(list_files) + self.name = f"{name}/{random_file}" + self.volume = volume self.loop = loop self.callback = callback @@ -763,7 +770,7 @@ def start_game( del channels[entity] # Ajout des sons non gérés - for entity in sound_entities: + for entity in world.query(Sound): if entity not in channels: entity_sound = entity[Sound] sound = assets.get_sound(entity_sound.name) diff --git a/src/main.py b/src/main.py index 13a8888..d1af8d6 100644 --- a/src/main.py +++ b/src/main.py @@ -4,13 +4,14 @@ Example de l'utilisation du moteur de jeu. from engine import start_game -from scenes import directory_search, menu +from scenes import directory_search, menu, classique start_game( { "menu": menu.SCENE, "directory_search": directory_search.SCENE, + "classique": classique.SCENE, }, "directory_search", title="Guess The Number", diff --git a/src/plugins/typing.py b/src/plugins/typing.py new file mode 100644 index 0000000..6379dd3 --- /dev/null +++ b/src/plugins/typing.py @@ -0,0 +1,37 @@ +""" +Definit un plugin qui crée un texte avec les touches frappées +""" + +from engine import Keyboard, Scene, Sound, Text, World + + +class Typing(str): + """ + Marque une entité comme un texte qui s'ecrit en fonction du clavier + """ + + +def __update(world: World): + """ + Met a jour les entitées contenant le composant Typing + """ + keyboard = world[Keyboard] + for entity in world.query(Typing, Text): + text = entity[Text] + for key in keyboard.pressed: + if key == "backspace": + world.create_entity(Sound("click")) + text = text[:-1] + if key.startswith("["): # pavé numerique + key = key[1] + if key in entity[Typing]: + world.create_entity(Sound("click")) + text += key + entity[Text] = Text(text) + + +PLUGIN = Scene( + [], + [__update], + [], +) diff --git a/src/scenes/classique.py b/src/scenes/classique.py new file mode 100644 index 0000000..de6d51d --- /dev/null +++ b/src/scenes/classique.py @@ -0,0 +1,227 @@ +""" +Définis la scène du jeu classique, sans variante. +""" + +import random +from plugins import typing +from engine import ( + Centered, + Clickable, + Color, + Display, + Entity, + Game, + HoveredTexture, + Keyboard, + Order, + Position, + Scene, + Sound, + Text, + TextSize, + Texture, + World, +) + +COLOR_TEXT = Color(66, 39, 148) + + +class RandomNumber(int): + """ + La ressource qui est le nombre a deviner. + """ + + +class TextDialogue: + """ + Le component qui declare l'entitee Text qui affiche le plus petit ou le plus grand + """ + + +class NombreEssai(int): + """ + Le component qui declare le nombre d'essai + """ + + +class NombreEssaiText: + """ + Le component qui affiche le nombre d'essai + """ + + +class IsRunning: + """ + Le component qui indique si le jeu est en cours + """ + + +def __initialize_world(world: World): + """ + Initialise le monde du menu. + """ + + # Fond d'ecran + world.create_entity( + Position(), + Order(0), + Texture("classique/background.png"), + ) + + # Bouton valider/rejouer + world.create_entity( + Position(Display.WIDTH / 2, 875), + Order(1), + Centered(), + Texture("classique/valider.png"), + HoveredTexture("classique/valider_hover.png"), + Clickable(lambda world, _: _update(world)), + ) + + # Zone de saisie + world.create_entity( + Position(Display.WIDTH / 2, 750), + Order(2), + Centered(), + typing.Typing("1234567890"), + Text(""), + COLOR_TEXT, + TextSize(150), + ) + + # Text qui dit si ton nombre et trop grand ou trop petit + world.create_entity( + Position(Display.WIDTH / 2, 500), + Order(3), + Centered(), + TextDialogue(), + TextSize(150), + COLOR_TEXT, + Text("Devine le nombre..."), + ) + + # Text qui affiche le nombre d'essai + world.create_entity( + Position(Display.WIDTH / 2 - 100, 150), + Order(4), + TextSize(100), + NombreEssaiText(), + COLOR_TEXT, + Text("il reste : 7 essais"), + ) + + # Bouton pour revenir au menu + world.create_entity( + Order(11), + Position(150, 150), + Texture("classique/arrow.png"), + Clickable(on_menu_button), + HoveredTexture("classique/arrow_hover.png"), + ) + + # Les ressources. + world[NombreEssai] = NombreEssai(7) + world[RandomNumber] = RandomNumber(random.randint(0, 99)) + world[IsRunning] = IsRunning() + + +def on_menu_button(world: World, entity: Entity): + """ + Fonction qui s'execute quand on clique sur un bouton. + """ + world[Game].change_scene("menu") + entity[Sound] = Sound("click") + + +def _update(world: World): + """ + Verifie si le nombre donné est le meme que celui que l'on a choisi. + Boucle du jeu. + """ + + world.create_entity(Sound("menu_click.wav")) + + # si le jeu s'est arrete. + if IsRunning not in world: + # on relance le jeu. + world[Game].change_scene("classique") + + for entity in world.query(typing.Typing, Text): + # One efface le nombre. + number: str = entity[Text] + entity[Text] = Text("") + + # On gere le l'input de l'utilisateur. + for entity_text in world.query(TextDialogue): + if number == "": # si il a rien evoyé. + entity_text[Text] = Text("tu doit entrer un nombre !") + return + if world[RandomNumber] == int(number): # si il a trouve le nombre. + end_game(world, "Gagné") + return + elif world[NombreEssai] <= 1: # si il n'a plus d'essai. + end_game(world, "Perdu") + return + elif world[RandomNumber] > int(number): # si le nombre est trop petit. + entity_text[Text] = Text("Plus grand...") + else: # si le nombre est trop grand. + entity_text[Text] = Text("Plus petit...") + + # on update l'affichage du nombre d'essai. + world[NombreEssai] = NombreEssai(world[NombreEssai] - 1) + for entity in world.query(NombreEssaiText): + entity[Text] = Text( + f"il reste : {world[NombreEssai]} essai{'s' if world[NombreEssai] != 1 else ''}" + ) + + +def end_game(world: World, state: str): + """ + fonction applé quand le jeu est fini. + """ + del world[IsRunning] # le jeu est fini. + + # On joue le son + if state == "Gagné": + world.create_entity(Sound("win_sound.wav")) + else: + world.create_entity(Sound("lose_sound.wav")) + + # On affiche le message de fin. + for entity_text in world.query(TextDialogue): + entity_text[Text] = Text(f"{state} !") + + # On empeche de pourvoir continuer le jeu. + for entity in world.query(typing.Typing, Text): + del entity[typing.Typing] + + if state == "Gagné": + for entity in world.query(NombreEssaiText): + entity[Text] = Text("") + else: + for entity in world.query(NombreEssaiText): + entity[Text] = Text(" plus d'essais") + + # on change la texture du button submit. + for entity in world.query(Clickable, Centered): + entity[Texture] = Texture("classique/play_again.png") + entity[HoveredTexture] = HoveredTexture("classique/play_again_hover.png") + + +def _check_return(world: World): + """ + Verifie si la touche entrée est appuyée. + """ + keyboard = world[Keyboard] + if keyboard.is_key_pressed("return") or keyboard.is_key_pressed("enter"): + _update(world) + + +SCENE = ( + Scene( + [__initialize_world], + [_check_return], + [], + ) + + typing.PLUGIN +) diff --git a/src/scenes/menu.py b/src/scenes/menu.py index 0f60cd4..1fb3d80 100644 --- a/src/scenes/menu.py +++ b/src/scenes/menu.py @@ -36,7 +36,7 @@ def on_click_butons(world: World, entity: Entity, name: str): """ Fonction qui s'execute quand on clique sur un bouton. """ - entity[Sound] = Sound("click.wav") + entity[Sound] = Sound("click") world[Game].change_scene(name)