diff --git a/src/plugins/writing.py b/src/plugins/writing.py new file mode 100644 index 0000000..aea5f2f --- /dev/null +++ b/src/plugins/writing.py @@ -0,0 +1,57 @@ +""" +Definit un plugin qui crée un texte avec les touches frappées +""" + +from engine import Scene, World +from plugins.inputs import Held, 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] + held = world[Held] + 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] + 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 6772dca..786dcb9 100644 --- a/src/scenes/game.py +++ b/src/scenes/game.py @@ -3,7 +3,7 @@ Le jeux principale. """ from enum import Enum -from engine import Plugin, Scene +from engine import CurrentScene, KeepAlive, Plugin, Scene from engine.ecs import Entity, World from engine.math import Vec2 from plugins import physics, render @@ -20,6 +20,8 @@ from plugins.render import ( from plugins.timing import Delta, Time import random +from scenes import game_over + class GameMode(Enum): """ @@ -84,7 +86,7 @@ class Speed(int): """ -class Player1Score(int): +class Player1Score(int, KeepAlive): """ Ressource qui represente le score du joueur 1. """ @@ -108,7 +110,13 @@ class StartAnimation(float): """ -def __spawn_ellements(world: World): +class Wall: + """ + Composant qui represente les mur du haut et du bas + """ + + +def __spawn_elements(world: World): """ La fonction permet de initializer les ellements de la scene. """ @@ -141,6 +149,9 @@ def __spawn_ellements(world: World): Scale(Vec2(render.WIDTH, 10)), Position(Vec2(0, render.HEIGHT)), physics.Solid(), + (Wall(), physics.CollisionHandler(__bounce_on_top_or_bot_wall)) + if world[GameMode] == GameMode.ONE + else None, ) # Mon mur du haut @@ -149,6 +160,9 @@ def __spawn_ellements(world: World): Scale(Vec2(render.WIDTH, 10)), Position(Vec2(0, 0)), physics.Solid(), + (Wall(), physics.CollisionHandler(__bounce_on_top_or_bot_wall)) + if world[GameMode] == GameMode.ONE + else None, ) # Joueur 1 @@ -188,16 +202,28 @@ def __spawn_ellements(world: World): # Initialisation des scores world.set(Player1Score(0), Player2Score(0)) - world.new_entity().set( - TextBundle( - "0 - 0", - 10, - 50, - position=Vec2(render.WIDTH / 2, 75), - origin=Vec2(0.5), - ), - Score(), - ) + 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_ball(world: World): @@ -238,6 +264,18 @@ def __bounce_on_player(a: Entity, b: Entity): a[physics.Velocity] = a[physics.Velocity].normalized * min( (speed * 1.1), 1000.0 ) + if Player1 in b and Ball in a: + if b.world[GameMode] == GameMode.ONE: + a.world[Player1Score] += 100 + __update_scores(a.world, b) + return True + + +def __bounce_on_top_or_bot_wall(a: Entity, b: Entity): + if Ball in b and Wall in a: + if b.world[GameMode] == GameMode.ONE: + a.world[Player1Score] += 20 + __update_scores(a.world, a) return True @@ -247,8 +285,12 @@ def __bounce_on_left_wall(a: Entity, b: Entity): """ if Ball in b: world = a.world - world[Player2Score] += 1 - __update_scores(world, b) + if world[GameMode] == GameMode.TWO: + world[Player2Score] += 1 + __update_scores(world, b) + else: + world[CurrentScene] = game_over.GAME_OVER + return False return True @@ -259,7 +301,10 @@ def __bounce_on_right_wall(a: Entity, b: Entity): """ if Ball in b: world = a.world - world[Player1Score] += 1 + if world[GameMode] == GameMode.TWO: + world[Player1Score] += 1 + else: + world[Player1Score] += 1000 __update_scores(world, b) return False return True @@ -376,11 +421,17 @@ def __update_scores(world: World, ball: Entity): La fontion permet de mettre a jour les scores. """ - # met a jour le score du joueur 1 et 2 - for panel in world.query(Score): - panel[Text] = f"{world[Player1Score]} - {world[Player2Score]}" + 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() + 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) @@ -421,7 +472,7 @@ def __update_animation(world: World): __SCENE = Scene( - [__spawn_ellements], + [__spawn_elements], [__update_move, __update_animation], [], ) diff --git a/src/scenes/game_over.py b/src/scenes/game_over.py new file mode 100644 index 0000000..57dfc12 --- /dev/null +++ b/src/scenes/game_over.py @@ -0,0 +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 = ["one_player", "two_player"] + 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 "one_player": + world[CurrentScene] = send_to_server.SEND + case "two_player": + 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 cd7bb9b..e39005b 100644 --- a/src/scenes/menu.py +++ b/src/scenes/menu.py @@ -11,7 +11,8 @@ from plugins import render from plugins.click import Clickable from plugins.hover import HoveredTexture from plugins.render import SpriteBundle -from scenes import game +from plugins.timing import Time +from scenes import game, send_to_server def __create_button(world: World, i: int, name: str): @@ -51,8 +52,8 @@ def __spawn_elements(world: World): """ Ajoute les éléments du menu dans le monde. """ - - world.new_entity().set(Sound("music.mp3"), KeepAlive(), Loop()) + if world[Time] < 1: + world.new_entity().set(Sound("music.mp3"), KeepAlive(), Loop()) world.new_entity().set(SpriteBundle("background_menu.png", -5)) diff --git a/src/scenes/send_to_server.py b/src/scenes/send_to_server.py new file mode 100644 index 0000000..7f9c268 --- /dev/null +++ b/src/scenes/send_to_server.py @@ -0,0 +1,86 @@ +from plugins import writing +from engine import 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.writing import Writing +import requests as rq +from scenes import game + +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) + 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, 650), + origin=Vec2(0.5), + ), + Writing( + "azertyuiopqsdfghjklmwxcvbn0123456789_-/", + 10, + "...", + ), + ) + + world.new_entity().set( + SpriteBundle( + f"button_one_player.png", + position=Vec2(render.WIDTH / 2, render.HEIGHT / 2), + order=1, + origin=Vec2(0.5), + ), + HoveredTexture( + f"button_one_player.png", + f"button_one_player_hover.png", + ), + Clickable(new_score), + ) + + +SEND = ( + Plugin( + [__spawn_elements], + [], + [], + ) + + writing.PLUGIN +) diff --git a/src/scenes/try_again.py b/src/scenes/try_again.py new file mode 100644 index 0000000..929643e --- /dev/null +++ b/src/scenes/try_again.py @@ -0,0 +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 "one_player": + world[CurrentScene] = menu.MENU + case "two_player": + 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 = ["one_player", "two_player"] + for i, name in enumerate(scenes_name): + __create_button(world, i, name) + + +TRY_AGAIN = Scene( + [__spawn_elements], + [], + [], +)