diff --git a/src/plugins/timing.py b/src/plugins/timing.py index 7be3474..5cf6ff9 100644 --- a/src/plugins/timing.py +++ b/src/plugins/timing.py @@ -1,71 +1,71 @@ -""" -Un plugin permettant de connaitre le temps depuis le -lancement du jeu et le temps depuis la dernière frame. -""" - - -from time import time -from typing import Callable -from engine import GlobalPlugin, KeepAlive -from engine.ecs import Entity, World - - -class GlobalTime(KeepAlive, float): - """ - Ressource qui représente le temps global de l'ordinateur sur lequel tourne le jeu. - """ - - -class Time(KeepAlive, float): - """ - Ressource qui représente le temps depuis le lancement du jeu. - """ - - -class Delta(KeepAlive, float): - """ - Ressource qui détermine le temps depuis la première frame. - """ - - -def __initialize(world: World): - """ - Initialise les ressources pour la gestion du temps. - """ - world.set(GlobalTime(time()), Time(0.0)) - - -class TimedEvent: - """ - Composant permettant d'executer un callback après un certain temps. - """ - - def __init__(self, timer: float, callback: Callable[[World, Entity], object]): - self.timer = timer - self.callback = callback - - -def __update(world: World): - """ - Met à jour les ressources de temps. - """ - now = time() - world[Delta] = delta = now - world[GlobalTime] - world[GlobalTime] = now - world[Time] += delta - - # On met à jour les `TimedEvent` - for entity in world.query(TimedEvent): - event = entity[TimedEvent] - event.timer -= delta - if event.timer <= 0: - del entity[TimedEvent] - event.callback(world, entity) - - -PLUGIN = GlobalPlugin( - [__initialize], - [__update], - [], - [], -) +""" +Un plugin permettant de connaitre le temps depuis le +lancement du jeu et le temps depuis la dernière frame. +""" + + +from time import time +from typing import Callable +from engine import GlobalPlugin, KeepAlive +from engine.ecs import Entity, World + + +class GlobalTime(KeepAlive, float): + """ + Ressource qui représente le temps global de l'ordinateur sur lequel tourne le jeu. + """ + + +class Time(KeepAlive, float): + """ + Ressource qui représente le temps depuis le lancement du jeu. + """ + + +class Delta(KeepAlive, float): + """ + Ressource qui détermine le temps depuis la première frame. + """ + + +def __initialize(world: World): + """ + Initialise les ressources pour la gestion du temps. + """ + world.set(GlobalTime(time()), Time(0.0)) + + +class TimedEvent: + """ + Composant permettant d'executer un callback après un certain temps. + """ + + def __init__(self, timer: float, callback: Callable[[World, Entity], object]): + self.timer = timer + self.callback = callback + + +def __update(world: World): + """ + Met à jour les ressources de temps. + """ + now = time() + world[Delta] = delta = now - world[GlobalTime] + world[GlobalTime] = now + world[Time] += delta + + # On met à jour les `TimedEvent` + for entity in world.query(TimedEvent): + event = entity[TimedEvent] + event.timer -= delta + if event.timer <= 0: + del entity[TimedEvent] + event.callback(world, entity) + + +PLUGIN = GlobalPlugin( + [__initialize], + [__update], + [], + [], +) diff --git a/src/plugins/writing.py b/src/plugins/writing.py index 0be2540..f9cbbbc 100644 --- a/src/plugins/writing.py +++ b/src/plugins/writing.py @@ -1,63 +1,63 @@ -""" -Definit un plugin qui crée un texte avec les touches frappées -""" - -from engine import Scene, World -from plugins.inputs import Pressed -from plugins.render import Text -from plugins.sound import Sound - - -class Writing: - """ - Marque une entité comme un texte qui s'ecrit en fonction du clavier - """ - - def __init__( - self, accepted_chars: str, max_chars: int = 10, base_text: str = "" - ) -> None: - self.accepted_chars = accepted_chars - self.max_chars = max_chars - self.base_text = base_text - - -def __update(world: World): - """ - Met a jour les entitées contenant le composant Typing - """ - pressed = world[Pressed] - for entity in world.query(Writing, Text): - writing = entity[Writing] - for key in pressed: - if key == "backspace" and entity[Text] != writing.base_text: - entity[Text] = entity[Text][:-1] - world.new_entity().set(Sound("click.wav")) - if entity[Text] == "": - entity[Text] = writing.base_text - if key.startswith("["): # pavé numerique - key = key[1] - match key: - case "6": - key = "-" - case "8": - key = "_" - case _: - pass - if key in writing.accepted_chars and ( - entity[Text] == writing.base_text - or len(entity[Text]) < writing.max_chars - ): - if entity[Text] == writing.base_text: - entity[Text] = key - else: - entity[Text] += key - world.new_entity().set(Sound("click.wav")) - if entity[Text] == "": - entity[Text] = writing.base_text - - -PLUGIN = Scene( - [], - [__update], - [], -) +""" +Definit un plugin qui crée un texte avec les touches frappées +""" + +from engine import Scene, World +from plugins.inputs import Pressed +from plugins.render import Text +from plugins.sound import Sound + + +class Writing: + """ + Marque une entité comme un texte qui s'ecrit en fonction du clavier + """ + + def __init__( + self, accepted_chars: str, max_chars: int = 10, base_text: str = "" + ) -> None: + self.accepted_chars = accepted_chars + self.max_chars = max_chars + self.base_text = base_text + + +def __update(world: World): + """ + Met a jour les entitées contenant le composant Typing + """ + pressed = world[Pressed] + for entity in world.query(Writing, Text): + writing = entity[Writing] + for key in pressed: + if key == "backspace" and entity[Text] != writing.base_text: + entity[Text] = entity[Text][:-1] + world.new_entity().set(Sound("click.wav")) + if entity[Text] == "": + entity[Text] = writing.base_text + if key.startswith("["): # pavé numerique + key = key[1] + match key: + case "6": + key = "-" + case "8": + key = "_" + case _: + pass + if key in writing.accepted_chars and ( + entity[Text] == writing.base_text + or len(entity[Text]) < writing.max_chars + ): + if entity[Text] == writing.base_text: + entity[Text] = key + else: + entity[Text] += key + world.new_entity().set(Sound("click.wav")) + if entity[Text] == "": + entity[Text] = writing.base_text + + +PLUGIN = Scene( + [], + [__update], + [], +) diff --git a/src/scenes/game.py b/src/scenes/game.py index 1e3a5e3..1a6a493 100644 --- a/src/scenes/game.py +++ b/src/scenes/game.py @@ -1,686 +1,686 @@ -""" -Le jeux principale. -""" - -from enum import Enum -from engine import CurrentScene, KeepAlive, Plugin, Scene -from engine.ecs import Entity, World -from engine.math import Vec2 -from plugins import render -from plugins import physics -from plugins.inputs import Held -from plugins.render import ( - Origin, - Position, - Scale, - SpriteBundle, - TextBundle, - Text, - TextSize, -) -from plugins.timing import Delta, Time -import random -from plugins.physics import CollisionHandler, Solid, Velocity - -from scenes import game_over - - -class GameMode(Enum): - """ - Ressource qui definit le game mode choisi par l'utilisateur. - """ - - ONE = 0 - TWO = 1 - - -class RightWall: - """ - Composant qui marque une entité comme etant le mur de droite. - """ - - -class LeftWall: - """ - Composant qui marque une entité comme etant le mur de gauche. - """ - - -class Player1: - """ - Composant qui marque une entité comme etant le joeuur 1. - """ - - -class Player2: - """ - Composant qui marque une entité comme etant le joeuur 2. - """ - - -class Ball: - """ - Composant qui marque une entité comme etant une balle. - """ - - -class Bounce: - """ - Composant qui marque une entité qui peux faire rebondir - """ - - -class UpKey(str): - """ - Composant qui indique la touche pour faire monter le joueur - """ - - -class DownKey(str): - """ - Composant qui indique la touche pour faire descender le joueur - """ - - -class Speed(int): - """ - Composant qui represente la vitesse de l'entité. - """ - - -class Player1Score(int, KeepAlive): - """ - Ressource qui represente le score du joueur 1. - """ - - -class Player2Score(int): - """ - Ressource qui represente le score du joueur 2. - """ - - -class Score: - """ - Composant qui marque l'entité comme étant l'affichage du score. - """ - - -class StartAnimation(float): - """ - Composant qui represente un le moment auxquel on a lancé l'animation du compte a rebours - """ - - -class Wall: - """ - Composant qui represente les mur du haut et du bas - """ - - -class TimeUntilBonus: - """ - ressource qui represente le temps restant avant d'avoir le bonus - """ - - def __init__(self, time: float, world: World): - self.time = time - self.started_time = int(world[Time]) - - def is_ended(self, world: World): - return world[Time] - self.started_time >= self.time - - def start(self, world: World): - self.started_time = world[Time] - - -class LastPlayerTurn: - """ - un composant qui represente le dernier joueur qui a joué. - """ - - -class HasBonus: - """ - un composant qui represente si l'entité a un bonus - """ - - def __init__(self, bonus: "Bonus", time: float, world: World): - self.bonus = bonus - self.time = time - - self.start_time = world[Time] - - def is_ended(self, world: World): - return world[Time] - self.start_time >= self.time - - def suppr_bonus_from_entity(self, entity: Entity): - match self.bonus: - case Bonus.MULTI: - pass - case Bonus.BIG: - entity[Scale] /= 2 - case Bonus.FAST: - entity[Speed] /= 1.5 - case Bonus.REVERSE: - entity[UpKey], entity[DownKey] = entity[DownKey], entity[UpKey] - - -class Bonus(Enum): - MULTI = 0 - BIG = 1 - FAST = 2 - REVERSE = 3 - - @staticmethod - def aleatoire(): - type = random.randint(0, 3) - match type: - case 0: - return Bonus.MULTI - case 1: - return Bonus.BIG - case 2: - return Bonus.FAST - case _: - return Bonus.REVERSE - - @staticmethod - def get_texture(bonus: "Bonus"): - match bonus: - case Bonus.MULTI: - return "multi.png" - case Bonus.BIG: - return "big.png" - case Bonus.FAST: - return "fast.png" - case _: - return "reverse.png" - - -def __spawn_ellements(world: World): - """ - La fonction permet de initializer les ellements de la scene. - """ - - world.new_entity().set(SpriteBundle(("background.jpg"), -5)) - - world.set( - TimeUntilBonus(5, world), - ) - - # Mon mur de gauche - world.new_entity().set( - Origin(Vec2(1, 0)), - Scale(Vec2(10, render.HEIGHT)), - Position(Vec2(70, 0)), - Solid(), - LeftWall(), - CollisionHandler(__bounce_on_left_wall), - ) - - # Mon mur du RN - world.new_entity().set( - Origin(Vec2(0, 0)), - Scale(Vec2(10, render.HEIGHT)), - Position(Vec2(render.WIDTH - 70, 0)), - Solid(), - RightWall(), - CollisionHandler(__bounce_on_right_wall), - ) - - # Mon mur du bas - world.new_entity().set( - Origin(Vec2(0, 0)), - Scale(Vec2(render.WIDTH, 10)), - Position(Vec2(0, render.HEIGHT)), - (Wall(), physics.CollisionHandler(__bounce_on_top_or_bot_wall)) - if world[GameMode] == GameMode.ONE - else None, - Solid(), - ) - - # Mon mur du haut - world.new_entity().set( - Origin(Vec2(0, 1)), - Scale(Vec2(render.WIDTH, 10)), - Position(Vec2(0, 0)), - (Wall(), physics.CollisionHandler(__bounce_on_top_or_bot_wall)) - if world[GameMode] == GameMode.ONE - else None, - Solid(), - ) - - # Joueur 1 - world.new_entity().set( - SpriteBundle( - "player_1.png", - 0, - Vec2(100, render.HEIGHT / 2), - Vec2(44, 250), - Vec2(0.5), - ), - Solid(), - Player1(), - UpKey("z"), - DownKey("s"), - Speed(1000), - LastPlayerTurn(), - ) - - # Joueur 2 - world.new_entity().set( - SpriteBundle( - "player_2.png", - 0, - Vec2(render.WIDTH - 100, render.HEIGHT / 2), - Vec2(44, 250), - Vec2(0.5), - ), - Solid(), - Player2(), - (UpKey("up"), DownKey("down"), Speed(1000)) - if world[GameMode] == GameMode.TWO - else Speed(300), - ) - - __spawn_ball(world) - - # Initialisation des scores - world.set(Player1Score(0), Player2Score(0)) - - # Creation du texte d'affichage en fonction du mode de jeu - if world[GameMode] == GameMode.TWO: - world.new_entity().set( - TextBundle( - "0 - 0", - 10, - 50, - position=Vec2(render.WIDTH / 2, 75), - origin=Vec2(0.5), - ), - Score(), - ) - else: - world.new_entity().set( - TextBundle( - "0", - 10, - 50, - position=Vec2(render.WIDTH / 2, 75), - origin=Vec2(0.5), - ), - Score(), - ) - - -def __spawn_bonus(world: World): - bonus = Bonus.aleatoire() - world.new_entity().set( - SpriteBundle( - Bonus.get_texture(bonus), - 3, - Vec2( - random.randint(200, render.WIDTH - 200), - random.randint(100, render.HEIGHT - 100), - ), - Vec2(70), - Vec2(0.5), - ), - bonus, - ) - - -def __spawn_ball(world: World): - """ - Fonction qui fait apparaitre une balle avec une velocitée aleatoire - """ - # random velocité - velocity = Vec2(2 * random.randint(100, 200), random.randint(100, 200)) - - # mouvement a droite ou a gauche - if random.randint(0, 1) == 0: - velocity.x = -velocity.x - - # Balle - world.new_entity().set( - SpriteBundle( - "ball.png", - 0, - Vec2(render.WIDTH / 2, render.HEIGHT / 2), - Vec2(40, 40), - Vec2(0.5), - ), - Ball(), - Velocity(velocity), - CollisionHandler(__collision_with_ball), - ) - - -def __collision_with_ball(a: Entity, b: Entity): - if Player1 in b or Player2 in b: - for player in a.world.query(LastPlayerTurn): - del player[LastPlayerTurn] - b.set(LastPlayerTurn()) - return __bounce_on_player(a, b) - return True - - -def __bonus_touched(ball: Entity, bonus: Entity): - player = ball.world.query(LastPlayerTurn).pop() - match bonus[Bonus]: - case Bonus.MULTI: - __spawn_ball(bonus.world) - __spawn_ball(bonus.world) - ball.world[TimeUntilBonus].start(ball.world) - case Bonus.BIG: - player[Scale] *= 2 - player.set(HasBonus(Bonus.BIG, 10, bonus.world)) - case Bonus.FAST: - player[Speed] *= 1.5 - player.set(HasBonus(Bonus.FAST, 10, bonus.world)) - case Bonus.REVERSE: - for entity in ball.world.query(UpKey): - if LastPlayerTurn in entity: - continue - entity[UpKey], entity[DownKey] = entity[DownKey], entity[UpKey] - - entity.set(HasBonus(Bonus.REVERSE, 10, bonus.world)) - - bonus.destroy() - return False - - -def __bounce_on_player(a: Entity, b: Entity): - """ - Fonction qui decrit se qui se passe lorque la ball entre en collision avec un joueur - """ - # Si l'objet rencontré est un joueur - if Player1 in b or Player2 in b: - speed = a[physics.Velocity].length - a[physics.Velocity] = a[physics.Velocity].normalized - a[physics.Velocity].y = (a[Position].y - b[Position].y) * 0.005 - a[physics.Velocity] = a[physics.Velocity].normalized * min( - (speed * 1.1), 1000.0 - ) - # Si il s'agit du joueur 1 et que l'on est dans le mode 1 joueur - if Player1 in b and Ball in a: - if b.world[GameMode] == GameMode.ONE: - # Modification du score - a.world[Player1Score] += 100 - __update_scores(a.world, b) - return True - - -def __bounce_on_top_or_bot_wall(a: Entity, b: Entity): - # Si une balle touceh un mur du haut ou du bas et que l'on est dans le mode 1 joueur - # Il est important de verifier qu'il s'agit de la balle, - # Car des simulation de balle sont faites et ont le meme - # Comportment qu'une balle mais n'ont pas le composant Ball - if Ball in b and Wall in a: - if b.world[GameMode] == GameMode.ONE: - # Modification du score - a.world[Player1Score] += 20 - __update_scores(a.world, a) - return True - - -def __bounce_on_left_wall(a: Entity, b: Entity): - """ - Fonction qui decrit se qui se passe lorque la ball entre en collision avec le mur de gauche - """ - if Ball in b: - world = a.world - if world[GameMode] == GameMode.TWO: - world[Player2Score] += 1 - __update_scores(world, b) - else: - world[CurrentScene] = game_over.GAME_OVER - - return False - return True - - -def __bounce_on_right_wall(a: Entity, b: Entity): - """ - Fonction qui decrit se qui se passe lorque la ball entre en collision avec le mur de droite - """ - if Ball in b: - world = a.world - if world[GameMode] == GameMode.TWO: - world[Player1Score] += 1 - else: - world[Player1Score] += 1000 - __update_scores(world, b) - return False - return True - - -def __move_up(world: World): - """ - La fonction permet de faire bouger les entitees qui possedent UpKey vers le haut. - """ - held = world[Held] - for entity in world.query(UpKey): - if entity[UpKey] in held: - entity[Position] = Vec2( - entity[Position].x, - (entity[Position].y - entity[Speed] * world[Delta]), - ) - - -def __move_down(world: World): - """ - La fonction permet de faire bouger les entitees qui possedent DownKey vers le bas. - """ - held = world[Held] - for entity in world.query(DownKey): - if entity[DownKey] in held: - entity[Position] = Vec2( - entity[Position].x, - (entity[Position].y + entity[Speed] * world[Delta]), - ) - - -def __update_move(world: World): - """ - La fontion permet de faire bouger les entitees vers le haut ou vers le bas. - """ - __move_down(world) - __move_up(world) - - -def __simulate_wall_position(entity: Entity, component_type: type): - """ - Simule une entité afin de trouver lorsqu'elle entrera en collision avec une entité contenant un certain composant. - """ - simulation_entity = entity.world.new_entity() - - def __collision_handler(a: Entity, b: Entity): - entity[CollisionHandler].callback(a, b) - return component_type not in b - - simulation_entity.set( - Position(entity[Position]), - Scale(entity[Scale]), - Velocity(entity[Velocity]), - Origin(entity[Origin]), - CollisionHandler(__collision_handler), - ) - physics.move_entity(simulation_entity, entity[Velocity] * 500) - return simulation_entity - - -def _update_bot(world: World): - """ - Fonction qui update les mouvement du bot - """ - # On récupère la balle la plus proche du bot - ball_query = world.query(Position, Velocity, CollisionHandler) - if ball_query == set(): - return None - ball = max(ball_query, key=lambda entity: entity[Position].y) - - # On récupère le bot et le joueur - bot = world.query(Player2).pop() - player = world.query(Player1).pop() - - # On trouve l'endroit ou la balle va arriver sur le mur de droite - bot.remove(Solid) - right_wall_ball = __simulate_wall_position(ball, RightWall) - right_touch_height = right_wall_ball[Position].y - right_wall_ball.destroy() - bot.set(Solid()) - - # On teste différentes possitions pour voir laquelle la plus éloigné du joueur - # Mais seulement si la balle vas vers la droite car sinon elle touchera le mur - # de gauche sans intervention du bot - if ball[Velocity].x > 0: - bot_base_y = bot[Position].y - target: float = right_touch_height - better_distance = None - for offset in [-100, -50, 0, 50, 100]: - bot[Position].y = right_touch_height + offset - player.remove(Solid) - left_wall_ball = __simulate_wall_position(ball, LeftWall) - player.set(Solid()) - left_touch_height = left_wall_ball[Position].y - left_wall_ball.destroy() - if ( - better_distance is None - or abs(left_touch_height - player[Position].y) > better_distance - ): - better_distance = abs(left_touch_height - player[Position].y) - target = right_touch_height + offset - bot[Position].y = bot_base_y - else: - target = right_touch_height - - # On se déplace vers la meilleure option - diff = target - bot[Position].y - if abs(diff) > 10: - bot[Position].y += (diff / abs(diff)) * bot[Speed] * world[Delta] - - -def __check_bonus_collision(world: World): - """ - Fonction qui permet de voir si un bonus est entrée en collision avec une entité. - """ - - def __collision_handler(a: Entity, b: Entity): - if Bonus in b: - __bonus_touched(a, b) - return False - return True - - for entity in world.query(Bonus): - entity.set(Solid()) - for entity in world.query(Ball): - simulated_ball = world.new_entity() - simulated_ball.set( - Position(entity[Position]), - Scale(entity[Scale]), - Velocity(entity[Velocity]), - Origin(entity[Origin]), - CollisionHandler(__collision_handler), - ) - physics.move_entity(simulated_ball, entity[Velocity] * world[Delta]) - simulated_ball.destroy() - for entity in world.query(Bonus): - entity.remove(Solid) - - -def __update_scores(world: World, ball: Entity): - """ - La fontion permet de mettre a jour les scores. - """ - - if world[GameMode] == GameMode.TWO: - # met a jour le score du joueur 1 et 2 - for panel in world.query(Score): - panel[Text] = f"{world[Player1Score]} - {world[Player2Score]}" - - ball.destroy() - else: - for panel in world.query(Score): - panel[Text] = f"{world[Player1Score]}" - if Ball in ball: - ball.destroy() - - if world.query(Ball) == set(): - __animation(world, 3) - - -def __animation(world: World, number: int): - world.new_entity().set( - TextBundle( - str(number), - 2, - 5000, - position=Vec2(render.WIDTH / 2, render.HEIGHT / 2), - origin=Vec2(0.5), - ), - StartAnimation(world[Time]), - ) - - -def __update_animation(world: World): - """ - Fonction qui permet de mettre a jour l'animation du compte a rebours. - """ - - for animation in world.query(StartAnimation): - time = world[Time] - animation[StartAnimation] - - if animation[TextSize] > 700: - animation[TextSize] = 5000 / (25 * time + 1) - else: - animation[TextSize] -= 1000 * world[Delta] - if animation[TextSize] < 0: - if int(animation[Text]) > 1 or "space" in world[Held]: - __animation(world, int(animation[Text]) - 1) - else: - # creation de la balle - __spawn_ball(world) - animation.destroy() - - -def __update_bonus_time(world: World): - """ - Fonction qui permet de mettre à jour les bonus. - """ - for player in world.query(HasBonus): - if not player[HasBonus].is_ended(world): - return None - player[HasBonus].suppr_bonus_from_entity(player) - del player[HasBonus] - world[TimeUntilBonus].start(world) - - if world.query(Bonus) == set() and world.query(HasBonus) == set(): - if world[TimeUntilBonus].is_ended(world): - __spawn_bonus(world) - - -__SCENE = Scene( - [__spawn_ellements], - [__update_move, __check_bonus_collision, __update_animation, __update_bonus_time], - [], -) - -ONE_PLAYER = ( - Plugin( - [lambda world: world.set(GameMode.ONE)], - [_update_bot], - [], - ) - + __SCENE -) - -TWO_PLAYER = ( - Plugin( - [lambda world: world.set(GameMode.TWO)], - [], - [], - ) - + __SCENE -) +""" +Le jeux principale. +""" + +from enum import Enum +from engine import CurrentScene, KeepAlive, Plugin, Scene +from engine.ecs import Entity, World +from engine.math import Vec2 +from plugins import render +from plugins import physics +from plugins.inputs import Held +from plugins.render import ( + Origin, + Position, + Scale, + SpriteBundle, + TextBundle, + Text, + TextSize, +) +from plugins.timing import Delta, Time +import random +from plugins.physics import CollisionHandler, Solid, Velocity + +from scenes import game_over + + +class GameMode(Enum): + """ + Ressource qui definit le game mode choisi par l'utilisateur. + """ + + ONE = 0 + TWO = 1 + + +class RightWall: + """ + Composant qui marque une entité comme etant le mur de droite. + """ + + +class LeftWall: + """ + Composant qui marque une entité comme etant le mur de gauche. + """ + + +class Player1: + """ + Composant qui marque une entité comme etant le joeuur 1. + """ + + +class Player2: + """ + Composant qui marque une entité comme etant le joeuur 2. + """ + + +class Ball: + """ + Composant qui marque une entité comme etant une balle. + """ + + +class Bounce: + """ + Composant qui marque une entité qui peux faire rebondir + """ + + +class UpKey(str): + """ + Composant qui indique la touche pour faire monter le joueur + """ + + +class DownKey(str): + """ + Composant qui indique la touche pour faire descender le joueur + """ + + +class Speed(int): + """ + Composant qui represente la vitesse de l'entité. + """ + + +class Player1Score(int, KeepAlive): + """ + Ressource qui represente le score du joueur 1. + """ + + +class Player2Score(int): + """ + Ressource qui represente le score du joueur 2. + """ + + +class Score: + """ + Composant qui marque l'entité comme étant l'affichage du score. + """ + + +class StartAnimation(float): + """ + Composant qui represente un le moment auxquel on a lancé l'animation du compte a rebours + """ + + +class Wall: + """ + Composant qui represente les mur du haut et du bas + """ + + +class TimeUntilBonus: + """ + ressource qui represente le temps restant avant d'avoir le bonus + """ + + def __init__(self, time: float, world: World): + self.time = time + self.started_time = int(world[Time]) + + def is_ended(self, world: World): + return world[Time] - self.started_time >= self.time + + def start(self, world: World): + self.started_time = world[Time] + + +class LastPlayerTurn: + """ + un composant qui represente le dernier joueur qui a joué. + """ + + +class HasBonus: + """ + un composant qui represente si l'entité a un bonus + """ + + def __init__(self, bonus: "Bonus", time: float, world: World): + self.bonus = bonus + self.time = time + + self.start_time = world[Time] + + def is_ended(self, world: World): + return world[Time] - self.start_time >= self.time + + def suppr_bonus_from_entity(self, entity: Entity): + match self.bonus: + case Bonus.MULTI: + pass + case Bonus.BIG: + entity[Scale] /= 2 + case Bonus.FAST: + entity[Speed] /= 1.5 + case Bonus.REVERSE: + entity[UpKey], entity[DownKey] = entity[DownKey], entity[UpKey] + + +class Bonus(Enum): + MULTI = 0 + BIG = 1 + FAST = 2 + REVERSE = 3 + + @staticmethod + def aleatoire(): + type = random.randint(0, 3) + match type: + case 0: + return Bonus.MULTI + case 1: + return Bonus.BIG + case 2: + return Bonus.FAST + case _: + return Bonus.REVERSE + + @staticmethod + def get_texture(bonus: "Bonus"): + match bonus: + case Bonus.MULTI: + return "multi.png" + case Bonus.BIG: + return "big.png" + case Bonus.FAST: + return "fast.png" + case _: + return "reverse.png" + + +def __spawn_ellements(world: World): + """ + La fonction permet de initializer les ellements de la scene. + """ + + world.new_entity().set(SpriteBundle(("background.jpg"), -5)) + + world.set( + TimeUntilBonus(5, world), + ) + + # Mon mur de gauche + world.new_entity().set( + Origin(Vec2(1, 0)), + Scale(Vec2(10, render.HEIGHT)), + Position(Vec2(70, 0)), + Solid(), + LeftWall(), + CollisionHandler(__bounce_on_left_wall), + ) + + # Mon mur du RN + world.new_entity().set( + Origin(Vec2(0, 0)), + Scale(Vec2(10, render.HEIGHT)), + Position(Vec2(render.WIDTH - 70, 0)), + Solid(), + RightWall(), + CollisionHandler(__bounce_on_right_wall), + ) + + # Mon mur du bas + world.new_entity().set( + Origin(Vec2(0, 0)), + Scale(Vec2(render.WIDTH, 10)), + Position(Vec2(0, render.HEIGHT)), + (Wall(), physics.CollisionHandler(__bounce_on_top_or_bot_wall)) + if world[GameMode] == GameMode.ONE + else None, + Solid(), + ) + + # Mon mur du haut + world.new_entity().set( + Origin(Vec2(0, 1)), + Scale(Vec2(render.WIDTH, 10)), + Position(Vec2(0, 0)), + (Wall(), physics.CollisionHandler(__bounce_on_top_or_bot_wall)) + if world[GameMode] == GameMode.ONE + else None, + Solid(), + ) + + # Joueur 1 + world.new_entity().set( + SpriteBundle( + "player_1.png", + 0, + Vec2(100, render.HEIGHT / 2), + Vec2(44, 250), + Vec2(0.5), + ), + Solid(), + Player1(), + UpKey("z"), + DownKey("s"), + Speed(1000), + LastPlayerTurn(), + ) + + # Joueur 2 + world.new_entity().set( + SpriteBundle( + "player_2.png", + 0, + Vec2(render.WIDTH - 100, render.HEIGHT / 2), + Vec2(44, 250), + Vec2(0.5), + ), + Solid(), + Player2(), + (UpKey("up"), DownKey("down"), Speed(1000)) + if world[GameMode] == GameMode.TWO + else Speed(300), + ) + + __spawn_ball(world) + + # Initialisation des scores + world.set(Player1Score(0), Player2Score(0)) + + # Creation du texte d'affichage en fonction du mode de jeu + if world[GameMode] == GameMode.TWO: + world.new_entity().set( + TextBundle( + "0 - 0", + 10, + 50, + position=Vec2(render.WIDTH / 2, 75), + origin=Vec2(0.5), + ), + Score(), + ) + else: + world.new_entity().set( + TextBundle( + "0", + 10, + 50, + position=Vec2(render.WIDTH / 2, 75), + origin=Vec2(0.5), + ), + Score(), + ) + + +def __spawn_bonus(world: World): + bonus = Bonus.aleatoire() + world.new_entity().set( + SpriteBundle( + Bonus.get_texture(bonus), + 3, + Vec2( + random.randint(200, render.WIDTH - 200), + random.randint(100, render.HEIGHT - 100), + ), + Vec2(70), + Vec2(0.5), + ), + bonus, + ) + + +def __spawn_ball(world: World): + """ + Fonction qui fait apparaitre une balle avec une velocitée aleatoire + """ + # random velocité + velocity = Vec2(2 * random.randint(100, 200), random.randint(100, 200)) + + # mouvement a droite ou a gauche + if random.randint(0, 1) == 0: + velocity.x = -velocity.x + + # Balle + world.new_entity().set( + SpriteBundle( + "ball.png", + 0, + Vec2(render.WIDTH / 2, render.HEIGHT / 2), + Vec2(40, 40), + Vec2(0.5), + ), + Ball(), + Velocity(velocity), + CollisionHandler(__collision_with_ball), + ) + + +def __collision_with_ball(a: Entity, b: Entity): + if Player1 in b or Player2 in b: + for player in a.world.query(LastPlayerTurn): + del player[LastPlayerTurn] + b.set(LastPlayerTurn()) + return __bounce_on_player(a, b) + return True + + +def __bonus_touched(ball: Entity, bonus: Entity): + player = ball.world.query(LastPlayerTurn).pop() + match bonus[Bonus]: + case Bonus.MULTI: + __spawn_ball(bonus.world) + __spawn_ball(bonus.world) + ball.world[TimeUntilBonus].start(ball.world) + case Bonus.BIG: + player[Scale] *= 2 + player.set(HasBonus(Bonus.BIG, 10, bonus.world)) + case Bonus.FAST: + player[Speed] *= 1.5 + player.set(HasBonus(Bonus.FAST, 10, bonus.world)) + case Bonus.REVERSE: + for entity in ball.world.query(UpKey): + if LastPlayerTurn in entity: + continue + entity[UpKey], entity[DownKey] = entity[DownKey], entity[UpKey] + + entity.set(HasBonus(Bonus.REVERSE, 10, bonus.world)) + + bonus.destroy() + return False + + +def __bounce_on_player(a: Entity, b: Entity): + """ + Fonction qui decrit se qui se passe lorque la ball entre en collision avec un joueur + """ + # Si l'objet rencontré est un joueur + if Player1 in b or Player2 in b: + speed = a[physics.Velocity].length + a[physics.Velocity] = a[physics.Velocity].normalized + a[physics.Velocity].y = (a[Position].y - b[Position].y) * 0.005 + a[physics.Velocity] = a[physics.Velocity].normalized * min( + (speed * 1.1), 1000.0 + ) + # Si il s'agit du joueur 1 et que l'on est dans le mode 1 joueur + if Player1 in b and Ball in a: + if b.world[GameMode] == GameMode.ONE: + # Modification du score + a.world[Player1Score] += 100 + __update_scores(a.world, b) + return True + + +def __bounce_on_top_or_bot_wall(a: Entity, b: Entity): + # Si une balle touceh un mur du haut ou du bas et que l'on est dans le mode 1 joueur + # Il est important de verifier qu'il s'agit de la balle, + # Car des simulation de balle sont faites et ont le meme + # Comportment qu'une balle mais n'ont pas le composant Ball + if Ball in b and Wall in a: + if b.world[GameMode] == GameMode.ONE: + # Modification du score + a.world[Player1Score] += 20 + __update_scores(a.world, a) + return True + + +def __bounce_on_left_wall(a: Entity, b: Entity): + """ + Fonction qui decrit se qui se passe lorque la ball entre en collision avec le mur de gauche + """ + if Ball in b: + world = a.world + if world[GameMode] == GameMode.TWO: + world[Player2Score] += 1 + __update_scores(world, b) + else: + world[CurrentScene] = game_over.GAME_OVER + + return False + return True + + +def __bounce_on_right_wall(a: Entity, b: Entity): + """ + Fonction qui decrit se qui se passe lorque la ball entre en collision avec le mur de droite + """ + if Ball in b: + world = a.world + if world[GameMode] == GameMode.TWO: + world[Player1Score] += 1 + else: + world[Player1Score] += 1000 + __update_scores(world, b) + return False + return True + + +def __move_up(world: World): + """ + La fonction permet de faire bouger les entitees qui possedent UpKey vers le haut. + """ + held = world[Held] + for entity in world.query(UpKey): + if entity[UpKey] in held: + entity[Position] = Vec2( + entity[Position].x, + (entity[Position].y - entity[Speed] * world[Delta]), + ) + + +def __move_down(world: World): + """ + La fonction permet de faire bouger les entitees qui possedent DownKey vers le bas. + """ + held = world[Held] + for entity in world.query(DownKey): + if entity[DownKey] in held: + entity[Position] = Vec2( + entity[Position].x, + (entity[Position].y + entity[Speed] * world[Delta]), + ) + + +def __update_move(world: World): + """ + La fontion permet de faire bouger les entitees vers le haut ou vers le bas. + """ + __move_down(world) + __move_up(world) + + +def __simulate_wall_position(entity: Entity, component_type: type): + """ + Simule une entité afin de trouver lorsqu'elle entrera en collision avec une entité contenant un certain composant. + """ + simulation_entity = entity.world.new_entity() + + def __collision_handler(a: Entity, b: Entity): + entity[CollisionHandler].callback(a, b) + return component_type not in b + + simulation_entity.set( + Position(entity[Position]), + Scale(entity[Scale]), + Velocity(entity[Velocity]), + Origin(entity[Origin]), + CollisionHandler(__collision_handler), + ) + physics.move_entity(simulation_entity, entity[Velocity] * 500) + return simulation_entity + + +def _update_bot(world: World): + """ + Fonction qui update les mouvement du bot + """ + # On récupère la balle la plus proche du bot + ball_query = world.query(Position, Velocity, CollisionHandler) + if ball_query == set(): + return None + ball = max(ball_query, key=lambda entity: entity[Position].y) + + # On récupère le bot et le joueur + bot = world.query(Player2).pop() + player = world.query(Player1).pop() + + # On trouve l'endroit ou la balle va arriver sur le mur de droite + bot.remove(Solid) + right_wall_ball = __simulate_wall_position(ball, RightWall) + right_touch_height = right_wall_ball[Position].y + right_wall_ball.destroy() + bot.set(Solid()) + + # On teste différentes possitions pour voir laquelle la plus éloigné du joueur + # Mais seulement si la balle vas vers la droite car sinon elle touchera le mur + # de gauche sans intervention du bot + if ball[Velocity].x > 0: + bot_base_y = bot[Position].y + target: float = right_touch_height + better_distance = None + for offset in [-100, -50, 0, 50, 100]: + bot[Position].y = right_touch_height + offset + player.remove(Solid) + left_wall_ball = __simulate_wall_position(ball, LeftWall) + player.set(Solid()) + left_touch_height = left_wall_ball[Position].y + left_wall_ball.destroy() + if ( + better_distance is None + or abs(left_touch_height - player[Position].y) > better_distance + ): + better_distance = abs(left_touch_height - player[Position].y) + target = right_touch_height + offset + bot[Position].y = bot_base_y + else: + target = right_touch_height + + # On se déplace vers la meilleure option + diff = target - bot[Position].y + if abs(diff) > 10: + bot[Position].y += (diff / abs(diff)) * bot[Speed] * world[Delta] + + +def __check_bonus_collision(world: World): + """ + Fonction qui permet de voir si un bonus est entrée en collision avec une entité. + """ + + def __collision_handler(a: Entity, b: Entity): + if Bonus in b: + __bonus_touched(a, b) + return False + return True + + for entity in world.query(Bonus): + entity.set(Solid()) + for entity in world.query(Ball): + simulated_ball = world.new_entity() + simulated_ball.set( + Position(entity[Position]), + Scale(entity[Scale]), + Velocity(entity[Velocity]), + Origin(entity[Origin]), + CollisionHandler(__collision_handler), + ) + physics.move_entity(simulated_ball, entity[Velocity] * world[Delta]) + simulated_ball.destroy() + for entity in world.query(Bonus): + entity.remove(Solid) + + +def __update_scores(world: World, ball: Entity): + """ + La fontion permet de mettre a jour les scores. + """ + + if world[GameMode] == GameMode.TWO: + # met a jour le score du joueur 1 et 2 + for panel in world.query(Score): + panel[Text] = f"{world[Player1Score]} - {world[Player2Score]}" + + ball.destroy() + else: + for panel in world.query(Score): + panel[Text] = f"{world[Player1Score]}" + if Ball in ball: + ball.destroy() + + if world.query(Ball) == set(): + __animation(world, 3) + + +def __animation(world: World, number: int): + world.new_entity().set( + TextBundle( + str(number), + 2, + 5000, + position=Vec2(render.WIDTH / 2, render.HEIGHT / 2), + origin=Vec2(0.5), + ), + StartAnimation(world[Time]), + ) + + +def __update_animation(world: World): + """ + Fonction qui permet de mettre a jour l'animation du compte a rebours. + """ + + for animation in world.query(StartAnimation): + time = world[Time] - animation[StartAnimation] + + if animation[TextSize] > 700: + animation[TextSize] = 5000 / (25 * time + 1) + else: + animation[TextSize] -= 1000 * world[Delta] + if animation[TextSize] < 0: + if int(animation[Text]) > 1 or "space" in world[Held]: + __animation(world, int(animation[Text]) - 1) + else: + # creation de la balle + __spawn_ball(world) + animation.destroy() + + +def __update_bonus_time(world: World): + """ + Fonction qui permet de mettre à jour les bonus. + """ + for player in world.query(HasBonus): + if not player[HasBonus].is_ended(world): + return None + player[HasBonus].suppr_bonus_from_entity(player) + del player[HasBonus] + world[TimeUntilBonus].start(world) + + if world.query(Bonus) == set() and world.query(HasBonus) == set(): + if world[TimeUntilBonus].is_ended(world): + __spawn_bonus(world) + + +__SCENE = Scene( + [__spawn_ellements], + [__update_move, __check_bonus_collision, __update_animation, __update_bonus_time], + [], +) + +ONE_PLAYER = ( + Plugin( + [lambda world: world.set(GameMode.ONE)], + [_update_bot], + [], + ) + + __SCENE +) + +TWO_PLAYER = ( + Plugin( + [lambda world: world.set(GameMode.TWO)], + [], + [], + ) + + __SCENE +) diff --git a/src/scenes/game_over.py b/src/scenes/game_over.py index 9f82074..d9f6409 100644 --- a/src/scenes/game_over.py +++ b/src/scenes/game_over.py @@ -1,81 +1,81 @@ -from engine import CurrentScene, KeepAlive, Scene -from engine.ecs import Entity, World -from engine.math import Vec2 -from plugins import render -from plugins.click import Clickable -from plugins.hover import HoveredTexture -from plugins.render import ( - SpriteBundle, - TextBundle, -) -from plugins.sound import Sound -from scenes import game, send_to_server, try_again - - -def __spawn_elements(world: World): - world.new_entity().set( - TextBundle( - "Game Over", 0, 100, position=Vec2(render.WIDTH / 2, 250), origin=Vec2(0.5) - ) - ) - world.new_entity().set( - TextBundle( - "Voulez vous enregistrer votre Score ?", - 0, - 50, - position=Vec2(render.WIDTH / 2, 350), - origin=Vec2(0.5), - ) - ) - world.new_entity().set( - TextBundle( - f"{world[game.Player1Score]}", - 0, - 50, - position=Vec2(render.WIDTH / 2, 450), - origin=Vec2(0.5), - ) - ) - button_name = ["yes", "no"] - for i, name in enumerate(button_name): - __create_button(world, i, name) - - -def __create_button(world: World, i: int, name: str): - """ - Ajoute un bouton au monde. - """ - world.new_entity().set( - SpriteBundle( - f"button_{name}.png", - position=Vec2(450 + 540 * i, render.HEIGHT / 2 + render.HEIGHT / 8), - order=1, - origin=Vec2(0.5), - ), - HoveredTexture( - f"button_{name}.png", - f"button_{name}_hover.png", - ), - Clickable(lambda world, entity: __on_click_butons(world, entity, name)), - ) - - -def __on_click_butons(world: World, _entity: Entity, name: str): - """ - Fonction qui s'execute quand on clique sur un bouton. - """ - match name: - case "yes": - world[CurrentScene] = send_to_server.SEND - case "no": - world[CurrentScene] = try_again.TRY_AGAIN - case _: - pass - world.new_entity().set(KeepAlive(), Sound("click.wav")) - - -GAME_OVER = Scene( - [__spawn_elements], - [], - [], -) +from engine import CurrentScene, KeepAlive, Scene +from engine.ecs import Entity, World +from engine.math import Vec2 +from plugins import render +from plugins.click import Clickable +from plugins.hover import HoveredTexture +from plugins.render import ( + SpriteBundle, + TextBundle, +) +from plugins.sound import Sound +from scenes import game, send_to_server, try_again + + +def __spawn_elements(world: World): + world.new_entity().set( + TextBundle( + "Game Over", 0, 100, position=Vec2(render.WIDTH / 2, 250), origin=Vec2(0.5) + ) + ) + world.new_entity().set( + TextBundle( + "Voulez vous enregistrer votre Score ?", + 0, + 50, + position=Vec2(render.WIDTH / 2, 350), + origin=Vec2(0.5), + ) + ) + world.new_entity().set( + TextBundle( + f"{world[game.Player1Score]}", + 0, + 50, + position=Vec2(render.WIDTH / 2, 450), + origin=Vec2(0.5), + ) + ) + button_name = ["yes", "no"] + for i, name in enumerate(button_name): + __create_button(world, i, name) + + +def __create_button(world: World, i: int, name: str): + """ + Ajoute un bouton au monde. + """ + world.new_entity().set( + SpriteBundle( + f"button_{name}.png", + position=Vec2(450 + 540 * i, render.HEIGHT / 2 + render.HEIGHT / 8), + order=1, + origin=Vec2(0.5), + ), + HoveredTexture( + f"button_{name}.png", + f"button_{name}_hover.png", + ), + Clickable(lambda world, entity: __on_click_butons(world, entity, name)), + ) + + +def __on_click_butons(world: World, _entity: Entity, name: str): + """ + Fonction qui s'execute quand on clique sur un bouton. + """ + match name: + case "yes": + world[CurrentScene] = send_to_server.SEND + case "no": + world[CurrentScene] = try_again.TRY_AGAIN + case _: + pass + world.new_entity().set(KeepAlive(), Sound("click.wav")) + + +GAME_OVER = Scene( + [__spawn_elements], + [], + [], +) diff --git a/src/scenes/menu.py b/src/scenes/menu.py index 0c88bd3..3a04447 100644 --- a/src/scenes/menu.py +++ b/src/scenes/menu.py @@ -1,107 +1,107 @@ -""" -La scène du menu principal du jeu. - -Dans cette scène nous pouvons choisir le mode de jeu. -""" -from plugins.sound import Loop, Sound -from engine import CurrentScene, KeepAlive, Scene -from engine.ecs import Entity, World -from engine.math import Vec2 -from plugins import render -from plugins.click import Clickable -from plugins.hover import HoveredTexture -from plugins.render import SpriteBundle, TextBundle -from plugins.timing import Time -from scenes import game -import requests as rq - -IP = "pong.cocosol.fr" - - -def get_scores() -> list[tuple[int, str]]: - try: - return rq.get(f"https://{IP}/data").json() - except: - print("Error with the serveur") - return [(1, "")] - - -def __create_button(world: World, i: int, name: str): - """ - Ajoute un bouton au monde. - """ - world.new_entity().set( - SpriteBundle( - f"button_{name}.png", - position=Vec2(450 + 540 * i, 11 * render.HEIGHT / 16), - order=1, - origin=Vec2(0.5), - ), - HoveredTexture( - f"button_{name}.png", - f"button_{name}_hover.png", - ), - Clickable(lambda world, entity: __on_click_butons(world, entity, name)), - ) - - -def __on_click_butons(world: World, _entity: Entity, name: str): - """ - Fonction qui s'execute quand on clique sur un bouton. - """ - match name: - case "one_player": - world[CurrentScene] = game.ONE_PLAYER - case "two_player": - world[CurrentScene] = game.TWO_PLAYER - case _: - pass - world.new_entity().set(KeepAlive(), Sound("click.wav")) - - -def __spawn_elements(world: World): - """ - Ajoute les éléments du menu dans le monde. - """ - if world[Time] < 1: - world.new_entity().set(Sound("music.mp3"), KeepAlive(), Loop()) - - world.new_entity().set(SpriteBundle("background_menu.png", -5)) - - scenes_name = ["one_player", "two_player"] - for i, name in enumerate(scenes_name): - __create_button(world, i, name) - - __spawn_score(world) - - -def __spawn_score(world: World): - """ - Ajoute le score dans le monde. - """ - print(get_scores()) - for i, (score, name) in enumerate(get_scores()): - world.new_entity().set( - TextBundle( - f"{name}", - position=Vec2(render.WIDTH / 2 - 350, 325 + 50 * i), - origin=Vec2(0), - order=1, - ) - ) - - world.new_entity().set( - TextBundle( - f"{score}", - position=Vec2(render.WIDTH / 2 + 350, 325 + 50 * i), - origin=Vec2(1, 0), - order=1, - ) - ) - - -MENU = Scene( - [__spawn_elements], - [], - [], -) +""" +La scène du menu principal du jeu. + +Dans cette scène nous pouvons choisir le mode de jeu. +""" +from plugins.sound import Loop, Sound +from engine import CurrentScene, KeepAlive, Scene +from engine.ecs import Entity, World +from engine.math import Vec2 +from plugins import render +from plugins.click import Clickable +from plugins.hover import HoveredTexture +from plugins.render import SpriteBundle, TextBundle +from plugins.timing import Time +from scenes import game +import requests as rq + +IP = "pong.cocosol.fr" + + +def get_scores() -> list[tuple[int, str]]: + try: + return rq.get(f"https://{IP}/data").json() + except: + print("Error with the serveur") + return [(1, "")] + + +def __create_button(world: World, i: int, name: str): + """ + Ajoute un bouton au monde. + """ + world.new_entity().set( + SpriteBundle( + f"button_{name}.png", + position=Vec2(450 + 540 * i, 11 * render.HEIGHT / 16), + order=1, + origin=Vec2(0.5), + ), + HoveredTexture( + f"button_{name}.png", + f"button_{name}_hover.png", + ), + Clickable(lambda world, entity: __on_click_butons(world, entity, name)), + ) + + +def __on_click_butons(world: World, _entity: Entity, name: str): + """ + Fonction qui s'execute quand on clique sur un bouton. + """ + match name: + case "one_player": + world[CurrentScene] = game.ONE_PLAYER + case "two_player": + world[CurrentScene] = game.TWO_PLAYER + case _: + pass + world.new_entity().set(KeepAlive(), Sound("click.wav")) + + +def __spawn_elements(world: World): + """ + Ajoute les éléments du menu dans le monde. + """ + if world[Time] < 1: + world.new_entity().set(Sound("music.mp3"), KeepAlive(), Loop()) + + world.new_entity().set(SpriteBundle("background_menu.png", -5)) + + scenes_name = ["one_player", "two_player"] + for i, name in enumerate(scenes_name): + __create_button(world, i, name) + + __spawn_score(world) + + +def __spawn_score(world: World): + """ + Ajoute le score dans le monde. + """ + print(get_scores()) + for i, (score, name) in enumerate(get_scores()): + world.new_entity().set( + TextBundle( + f"{name}", + position=Vec2(render.WIDTH / 2 - 350, 325 + 50 * i), + origin=Vec2(0), + order=1, + ) + ) + + world.new_entity().set( + TextBundle( + f"{score}", + position=Vec2(render.WIDTH / 2 + 350, 325 + 50 * i), + origin=Vec2(1, 0), + order=1, + ) + ) + + +MENU = Scene( + [__spawn_elements], + [], + [], +) diff --git a/src/scenes/send_to_server.py b/src/scenes/send_to_server.py index 9fb555c..50cb51c 100644 --- a/src/scenes/send_to_server.py +++ b/src/scenes/send_to_server.py @@ -1,93 +1,93 @@ -from plugins import writing -from engine import CurrentScene, Plugin -from engine.ecs import Entity, World -from engine.math import Vec2 -from plugins import render -from plugins.click import Clickable -from plugins.hover import HoveredTexture -from plugins.render import SpriteBundle, Text, TextBundle -from plugins.timing import TimedEvent -from plugins.writing import Writing -import requests as rq -from scenes import game, thanks - -IP = "pong.cocosol.fr" - - -def new_score(world: World, e: Entity): - e.remove(Clickable) - name = world.query(Writing).pop() - - try: - post = {"name": name[Text], "score": world[game.Player1Score]} - print(post) - rq.post(f"https://{IP}/new_score", post) - world.new_entity().set( - TimedEvent( - 1, - lambda world, entity: world.set(CurrentScene(thanks.THANKS)), - ) - ) - except: - print("Error with the serveur") - - -def get_scores(): - try: - return rq.get(f"https://{IP}/data").json() - except: - print("Error with the serveur") - - -def __spawn_elements(world: World): - """ - Ajoute les éléments du menu dans le monde. - """ - - world.new_entity().set(SpriteBundle("background.jpg", -5)) - world.new_entity().set( - TextBundle( - "Quel est votre pseudo ?", - 0, - position=Vec2(render.WIDTH / 2, 350), - origin=Vec2(0.5), - ), - ) - world.new_entity().set( - TextBundle( - "...", - 0, - 50, - position=Vec2(render.WIDTH / 2, 475), - origin=Vec2(0.5), - ), - Writing( - "azertyuiopqsdfghjklmwxcvbn0123456789_-/", - 16, - "...", - ), - ) - - world.new_entity().set( - SpriteBundle( - f"button_one_player.png", - position=Vec2(render.WIDTH / 2, 600), - order=1, - origin=Vec2(0.5), - ), - HoveredTexture( - f"button_submit.png", - f"button_submit_hover.png", - ), - Clickable(new_score), - ) - - -SEND = ( - Plugin( - [__spawn_elements], - [], - [], - ) - + writing.PLUGIN -) +from plugins import writing +from engine import CurrentScene, Plugin +from engine.ecs import Entity, World +from engine.math import Vec2 +from plugins import render +from plugins.click import Clickable +from plugins.hover import HoveredTexture +from plugins.render import SpriteBundle, Text, TextBundle +from plugins.timing import TimedEvent +from plugins.writing import Writing +import requests as rq +from scenes import game, thanks + +IP = "pong.cocosol.fr" + + +def new_score(world: World, e: Entity): + e.remove(Clickable) + name = world.query(Writing).pop() + + try: + post = {"name": name[Text], "score": world[game.Player1Score]} + print(post) + rq.post(f"https://{IP}/new_score", post) + world.new_entity().set( + TimedEvent( + 1, + lambda world, entity: world.set(CurrentScene(thanks.THANKS)), + ) + ) + except: + print("Error with the serveur") + + +def get_scores(): + try: + return rq.get(f"https://{IP}/data").json() + except: + print("Error with the serveur") + + +def __spawn_elements(world: World): + """ + Ajoute les éléments du menu dans le monde. + """ + + world.new_entity().set(SpriteBundle("background.jpg", -5)) + world.new_entity().set( + TextBundle( + "Quel est votre pseudo ?", + 0, + position=Vec2(render.WIDTH / 2, 350), + origin=Vec2(0.5), + ), + ) + world.new_entity().set( + TextBundle( + "...", + 0, + 50, + position=Vec2(render.WIDTH / 2, 475), + origin=Vec2(0.5), + ), + Writing( + "azertyuiopqsdfghjklmwxcvbn0123456789_-/", + 16, + "...", + ), + ) + + world.new_entity().set( + SpriteBundle( + f"button_one_player.png", + position=Vec2(render.WIDTH / 2, 600), + order=1, + origin=Vec2(0.5), + ), + HoveredTexture( + f"button_submit.png", + f"button_submit_hover.png", + ), + Clickable(new_score), + ) + + +SEND = ( + Plugin( + [__spawn_elements], + [], + [], + ) + + writing.PLUGIN +) diff --git a/src/scenes/thanks.py b/src/scenes/thanks.py index 0d58cf5..6b89809 100644 --- a/src/scenes/thanks.py +++ b/src/scenes/thanks.py @@ -1,37 +1,37 @@ -from engine import CurrentScene, Scene -from engine.ecs import World -from engine.math import Vec2 -from plugins import render -from plugins.render import SpriteBundle, TextBundle -from plugins.timing import TimedEvent -from scenes import menu - - -def __spawn_elements(world: World): - world.new_entity().set(SpriteBundle("background.jpg", -5)) - world.new_entity().set( - TextBundle( - "Merci,", - 0, - 150, - position=Vec2(render.WIDTH / 2, render.HEIGHT / 2 - 75), - origin=Vec2(0.5), - ), - TimedEvent(3, lambda world, entity: world.set(CurrentScene(menu.MENU))), - ) - world.new_entity().set( - TextBundle( - "Votre score a bien été envoyé !", - 0, - 100, - position=Vec2(render.WIDTH / 2, render.HEIGHT / 2 + 75), - origin=Vec2(0.5), - ), - ) - - -THANKS = Scene( - [__spawn_elements], - [], - [], -) +from engine import CurrentScene, Scene +from engine.ecs import World +from engine.math import Vec2 +from plugins import render +from plugins.render import SpriteBundle, TextBundle +from plugins.timing import TimedEvent +from scenes import menu + + +def __spawn_elements(world: World): + world.new_entity().set(SpriteBundle("background.jpg", -5)) + world.new_entity().set( + TextBundle( + "Merci,", + 0, + 150, + position=Vec2(render.WIDTH / 2, render.HEIGHT / 2 - 75), + origin=Vec2(0.5), + ), + TimedEvent(3, lambda world, entity: world.set(CurrentScene(menu.MENU))), + ) + world.new_entity().set( + TextBundle( + "Votre score a bien été envoyé !", + 0, + 100, + position=Vec2(render.WIDTH / 2, render.HEIGHT / 2 + 75), + origin=Vec2(0.5), + ), + ) + + +THANKS = Scene( + [__spawn_elements], + [], + [], +) diff --git a/src/scenes/try_again.py b/src/scenes/try_again.py index f1f4220..06b9768 100644 --- a/src/scenes/try_again.py +++ b/src/scenes/try_again.py @@ -1,73 +1,73 @@ -""" -La scène du menu principal du jeu. - -Dans cette scène nous pouvons choisir le mode de jeu. -""" -from plugins.sound import Sound -from engine import CurrentScene, KeepAlive, Scene -from engine.ecs import Entity, World -from engine.math import Vec2 -from plugins import render -from plugins.click import Clickable -from plugins.hover import HoveredTexture -from plugins.render import SpriteBundle, TextBundle -from scenes import game, menu - - -def __create_button(world: World, i: int, name: str): - """ - Ajoute un bouton au monde. - """ - world.new_entity().set( - SpriteBundle( - f"button_{name}.png", - position=Vec2(450 + 540 * i, render.HEIGHT / 2), - order=1, - origin=Vec2(0.5), - ), - HoveredTexture( - f"button_{name}.png", - f"button_{name}_hover.png", - ), - Clickable(lambda world, entity: __on_click_butons(world, entity, name)), - ) - - -def __on_click_butons(world: World, _entity: Entity, name: str): - """ - Fonction qui s'execute quand on clique sur un bouton. - """ - match name: - case "yes": - world[CurrentScene] = menu.MENU - case "no": - world[CurrentScene] = game.ONE_PLAYER - case _: - pass - world.new_entity().set(KeepAlive(), Sound("click.wav")) - - -def __spawn_elements(world: World): - """ - Ajoute les éléments du menu dans le monde. - """ - - world.new_entity().set(SpriteBundle("background.jpg", -5)) - world.new_entity().set( - TextBundle( - "Voulez vous changer\nde mode de jeu ?", - 0, - position=Vec2(render.WIDTH / 2, 350), - origin=Vec2(0.5), - ), - ) - scenes_name = ["yes", "no"] - for i, name in enumerate(scenes_name): - __create_button(world, i, name) - - -TRY_AGAIN = Scene( - [__spawn_elements], - [], - [], -) +""" +La scène du menu principal du jeu. + +Dans cette scène nous pouvons choisir le mode de jeu. +""" +from plugins.sound import Sound +from engine import CurrentScene, KeepAlive, Scene +from engine.ecs import Entity, World +from engine.math import Vec2 +from plugins import render +from plugins.click import Clickable +from plugins.hover import HoveredTexture +from plugins.render import SpriteBundle, TextBundle +from scenes import game, menu + + +def __create_button(world: World, i: int, name: str): + """ + Ajoute un bouton au monde. + """ + world.new_entity().set( + SpriteBundle( + f"button_{name}.png", + position=Vec2(450 + 540 * i, render.HEIGHT / 2), + order=1, + origin=Vec2(0.5), + ), + HoveredTexture( + f"button_{name}.png", + f"button_{name}_hover.png", + ), + Clickable(lambda world, entity: __on_click_butons(world, entity, name)), + ) + + +def __on_click_butons(world: World, _entity: Entity, name: str): + """ + Fonction qui s'execute quand on clique sur un bouton. + """ + match name: + case "yes": + world[CurrentScene] = menu.MENU + case "no": + world[CurrentScene] = game.ONE_PLAYER + case _: + pass + world.new_entity().set(KeepAlive(), Sound("click.wav")) + + +def __spawn_elements(world: World): + """ + Ajoute les éléments du menu dans le monde. + """ + + world.new_entity().set(SpriteBundle("background.jpg", -5)) + world.new_entity().set( + TextBundle( + "Voulez vous changer\nde mode de jeu ?", + 0, + position=Vec2(render.WIDTH / 2, 350), + origin=Vec2(0.5), + ), + ) + scenes_name = ["yes", "no"] + for i, name in enumerate(scenes_name): + __create_button(world, i, name) + + +TRY_AGAIN = Scene( + [__spawn_elements], + [], + [], +)