diff --git a/src/plugins/display.py b/src/plugins/display.py index cc0c1c2..220444b 100644 --- a/src/plugins/display.py +++ b/src/plugins/display.py @@ -13,7 +13,7 @@ def __initialize(_world: World): Initialise pygame et les ressources pour la gestion de la fenetre. """ pygame.init() - pygame.display.set_caption("Guess The Number") + pygame.display.set_caption("Ponguito") pygame.display.set_mode((800, 600), pygame.RESIZABLE) diff --git a/src/save_main.py b/src/save_main.py index 3e3c67c..dd727e8 100644 --- a/src/save_main.py +++ b/src/save_main.py @@ -207,27 +207,11 @@ def __update(world: World): bar.set(physics.Solid()) entity.destroy() - # for bar in world.query(Bar): - # bar.remove(physics.Solid) for entity in world.query(BallFollow): entity[Position] = Vec2(ball[Position]) entity[physics.Velocity] = Vec2(ball[physics.Velocity]) physics.move_entity(entity, entity[physics.Velocity] * entity[BallFollow] * 0.5) del entity[physics.Velocity] - # for bar in world.query(Bar): - # bar.set(physics.Solid()) - - # ball.set(Simulated()) - # for entity in world.query(Bar): - # entity.remove(physics.Solid) - # last_position = Vec2(ball[Position]) - # last_velocity = Vec2(ball[physics.Velocity]) - # physics.move_entity(ball, ball[physics.Velocity] * 5000) - # ball[Position] = last_position - # ball[physics.Velocity] = last_velocity - # for entity in world.query(Bar): - # entity.set(physics.Solid()) - # ball.remove(Simulated) MENU = Scene( diff --git a/src/scenes/game.py b/src/scenes/game.py index 81f7596..ed062bc 100644 --- a/src/scenes/game.py +++ b/src/scenes/game.py @@ -1,32 +1,69 @@ +""" +Le jeux principale. +""" + from enum import Enum +from math import e +import time from engine import Plugin, Scene from engine.ecs import Entity, World from engine.math import Vec2 -from plugins import render +from plugins import physics, render from plugins.inputs import Held -from plugins.timing import Delta -from plugins.sound import Sound -from plugins.render import Origin, Position, Scale, SpriteBundle, Text, TextBundle +from plugins.render import ( + Origin, + Position, + Scale, + SpriteBundle, + TextBundle, + Text, + TextSize, +) +from plugins.timing import Delta, Time class GameMode(Enum): """ - Definit un ressource represantant le mode de jeu actuel. + Ressource qui definit le game mode choisi par l'utilisateur. """ ONE = 0 TWO = 1 -class Player: +class RightWall: """ - Composant qui represente les joueurs. + Composant qui marque une entité comme etant le mur de droite. """ -class Bot: +class LeftWall: """ - Composant qui represente le bot. + 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 """ @@ -42,124 +79,181 @@ class DownKey(str): """ -class Ball: - """ - Composant qui represente la balle. - """ - - class Speed(int): """ Composant qui represente la vitesse de l'entité. """ -class Boxed: +class Player1Score(int): """ - Composant qui definit si l'entitée doit rebondir + Composant qui represente le score du joueur 1. """ -class Velocity(Vec2): +class Player2Score(int): """ - Composant qui definit le vecteur vitesse d'une entité + Composant qui represente le score du joueur 2. """ -class Blocked: +class Score: """ - Composant qui indique si l'entité est blockée par quelque chose dans son mouvement + Composant qui represente les scores affichés a l'ecran. """ -class ScorePlayer1(int): +class StartAnimation(float): """ - Ressource qui represente le score du joueur 1 - """ - - -class ScorePlayer2(int): - """ - Ressource qui represente le score du joueur 2 + Composant qui represente un le moment auxquel on a lancé l'animation """ def __spawn_elements(world: World): """ - Ajoute les éléments du menu dans le monde. + La fonction permet de initializer les ellements de la scene. """ - world.set(ScorePlayer1(0), ScorePlayer2(0)) + world.new_entity().set(SpriteBundle(("background.jpg"), -5)) - world.new_entity().set(SpriteBundle("background.jpg", -5)) + # Mon mur de gauche world.new_entity().set( - SpriteBundle(("player_1.png"), 0, Vec2(100, 200), Vec2(44, 250), Vec2(0.5)), - Player(), + Origin(Vec2(1, 0)), + Scale(Vec2(10, render.HEIGHT)), + Position(Vec2(70, 0)), + physics.Solid(), + LeftWall(), + physics.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)), + physics.Solid(), + RightWall(), + physics.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 - 50)), + physics.Solid(), + ) + + # Mon mur du haut + world.new_entity().set( + Origin(Vec2(0, 1)), + Scale(Vec2(render.WIDTH, 10)), + Position(Vec2(0, 50)), + physics.Solid(), + ) + + # Joueur 1 + world.new_entity().set( + SpriteBundle( + "player_1.png", + 0, + Vec2(100, render.HEIGHT / 2), + Vec2(44, 250), + Vec2(0.5), + ), + physics.Solid(), + Player1(), UpKey("z"), DownKey("s"), Speed(1000), - Boxed(), ) - if world[GameMode] == GameMode.TWO: - world.new_entity().set( - SpriteBundle( - ("player_2.png"), 0, Vec2(1340, 200), Vec2(44, 250), Vec2(0.5) - ), - Player(), - UpKey("up"), - DownKey("down"), - Speed(1000), - Boxed(), - ) + # Joueur 2 + world.new_entity().set( + SpriteBundle( + "player_2.png", + 0, + Vec2(render.WIDTH - 100, render.HEIGHT / 2), + Vec2(44, 250), + Vec2(0.5), + ), + physics.Solid(), + Player2(), + (UpKey("up"), DownKey("down"), Speed(1000)) + if world[GameMode] == GameMode.TWO + else None, + ) - else: - world.new_entity().set( - SpriteBundle( - ("player_2.png"), 0, Vec2(1340, 200), Vec2(44, 250), Vec2(0.5) - ), - Bot(), - smooth.Target(Vec2(1340, 200)), - Player(), - smooth.Speed(3), - Boxed(), - ) + __spawn_ball(world) + + # Initialisation des scores + world.set(Player1Score(0), Player2Score(0)) world.new_entity().set( TextBundle( - f"{world[ScorePlayer1]} - {world[ScorePlayer2]}", - position=Vec2(render.WIDTH / 2, 100), - order=5, + "0 - 0", + 10, + 50, + position=Vec2(render.WIDTH / 2, 75), origin=Vec2(0.5), ), + Score(), ) - __spawn_animation(world) - __spawn_ball(world) - def __spawn_ball(world: World): + # Balle world.new_entity().set( SpriteBundle( - ("ball.png"), - 2, + "ball.png", + 0, Vec2(render.WIDTH / 2, render.HEIGHT / 2), - origin=Vec2(0.5), + Vec2(40, 40), + Vec2(0.5), ), Ball(), - Velocity(Vec2(200, 30)), - Boxed(), + physics.Velocity(Vec2(-200, -100)), + physics.CollisionHandler(__bounce_on_player), ) -def __after_anim(world: World, entity: Entity): - entity.destroy() - __spawn_ball(world) +def __bounce_on_player(a: Entity, b: Entity): + 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 + ) + return True + + +def __bounce_on_player_simul(a: Entity, b: Entity): + __bounce_on_player(a, b) + return RightWall not in b + + +def __bounce_on_left_wall(a: Entity, b: Entity): + if Ball in b: + world = a.world + world[Player2Score] += 1 + __update_scores(world, b) + return False + return True + + +def __bounce_on_right_wall(a: Entity, b: Entity): + if Ball in b: + world = a.world + world[Player1Score] += 1 + __update_scores(world, b) + return False + return True def __move_up(world: World): """ - TODO + La fonction permet de faire bouger les entitees vers le haut. """ held = world[Held] for entity in world.query(UpKey): @@ -172,7 +266,7 @@ def __move_up(world: World): def __move_down(world: World): """ - TODO + La fonction permet de faire bouger les entitees vers le bas. """ held = world[Held] for entity in world.query(DownKey): @@ -183,162 +277,107 @@ def __move_down(world: World): ) -def __box(world: World): +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 _update_bot(world: World): + """ + Test. + """ + ball_query = world.query(Position, physics.Velocity, physics.CollisionHandler) + if ball_query == set(): + return None + + ball = max(ball_query, key=lambda entity: entity[Position].y) + for bar in world.query(Player2): + bar.remove(physics.Solid) + entity = world.new_entity() + entity.set( + Position(ball[Position]), + Scale(ball[Scale]), + physics.Velocity(ball[physics.Velocity]), + Origin(ball[Origin]), + physics.CollisionHandler(__bounce_on_player_simul), + ) + physics.move_entity(entity, entity[physics.Velocity] * 500) + target = entity[Position].y + for bar in world.query(Player2): + diff = target - bar[Position].y + + if abs(diff) > 10: + bar[Position].y += (diff / abs(diff)) * 300 * world[Delta] + # bar[Position].y += diff + bar.set(physics.Solid()) + entity.destroy() + + +def __update_scores(world: World, ball: Entity): + """ + La fontion permet de mettre a jour les scores. """ - bah box y vérifie si la prochaine j'ai oublié la suite ... si le Y balh position executé haut bah ruien pour - NIQUEZ VOUS - """ - gap = 50 - for entity in world.query(Boxed): - diff_up = gap - entity[Position].y - diff_down = entity[Position].y - (render.HEIGHT - gap) + # met a jour le score du joueur 1 et 2 + for panel in world.query(Score): + panel[Text] = f"{world[Player1Score]} - {world[Player2Score]}" - # Top - if entity[Position].y - (entity[Scale].y * entity[Origin].y) < gap: - entity[Position].y += entity[Scale].y * entity[Origin].y + diff_up - entity.set(Blocked()) + ball.destroy() - # Bottom - elif entity[Position].y + (entity[Scale].y * entity[Origin].y) > ( - render.HEIGHT - gap - ): - entity[Position].y -= entity[Scale].y * entity[Origin].y + diff_down - entity.set(Blocked()) + 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): + for animation in world.query(StartAnimation): + time = world[Time] - animation[StartAnimation] + + if animation[TextSize] > 700: + animation[TextSize] = 5000 / (25 * time + 1) else: - if Blocked in entity: - entity.remove(Blocked) - - -def __ball_movement(world: World): - for ball in world.query(Ball, Velocity): - if Blocked in ball: - ball[Velocity].y = -ball[Velocity].y - ball.remove(Blocked) - world.new_entity().set(Sound(("bound.mp3"))) - - for player in world.query(Player): - if __collision(ball, player): - if (render.WIDTH / 2 - ball[Position].x) * ball[Velocity].x < 0: - speed = ball[Velocity].length - ball[Velocity].x = -ball[Velocity].x - ball[Velocity].y = ball[Position].y - player[Position].y - ball[Velocity] = ball[Velocity].normalized * min( - (speed + 100), 2000 - ) - world.new_entity().set(Sound(("bound.mp3"))) - - ball[Position] += ball[Velocity] * world[Delta] - - -def __collision(ent1: Entity, ent2: Entity) -> bool: - origin1 = ent1[Origin] - position1 = ent1[Position] - largeur1 = ent1[Scale].x - hauteur1 = ent1[Scale].y - - origin2 = ent2[Origin] - position2 = ent2[Position] - largeur2 = ent2[Scale].x - hauteur2 = ent2[Scale].y - - left1, top1, right1, bottom1 = ( - position1.x - largeur1 * origin1.x, - position1.y - hauteur1 * origin1.y, - position1.x + largeur1 * origin1.x, - position1.y + hauteur1 * origin1.y, - ) - - left2, top2, right2, bottom2 = ( - position2.x - largeur2 * origin2.x, - position2.y - hauteur2 * origin2.y, - position2.x + largeur2 * origin2.x, - position2.y + hauteur2 * origin2.y, - ) - - return left1 < right2 and right1 > left2 and top1 < bottom2 and bottom1 > top2 - - -def __goal(world: World): - for ball in world.query(Ball): - if ball[Position].x - (ball[Scale].x * ball[Origin].x) < 0: - ball.destroy() - world[ScorePlayer2] += 1 - if len(world.query(Ball)) == 0: - __spawn_animation(world) - - elif ball[Position].x + (ball[Scale].x * ball[Origin].x) > render.WIDTH: - ball.destroy() - world[ScorePlayer1] += 1 - if len(world.query(Ball)) == 0: - __spawn_animation(world) - - -def __update_score(world: World): - for text in world.query(TextBundle): - text[Text] = f"{world[ScorePlayer1]} - {world[ScorePlayer2]}" - - -def __spawn_animation(world: World): - world.new_entity().set(Animation("countdown", 40, callback=__after_anim)) - - -def __update_bot_move(world: World): - bot = world.query(Bot).pop() - balls = world.query(Ball) - if balls == set(): - return - ball = balls.pop() - pos: Vec2 = Vec2(ball[Position]) - velocity = Vec2(ball[Velocity]) - - # calcul de la position de la balle avec la velocité - if velocity.x > 0: - while pos.x < bot[Position].x: - pos += velocity * 0.01 - - # rebond - gap = 50 - if pos.y - (ball[Scale].y * ball[Origin].y) < gap: - velocity.y = -velocity.y - - elif pos.y + (ball[Scale].y * ball[Origin].y) > (render.HEIGHT - gap): - velocity.y = -velocity.y - target = pos.y - - bot[smooth.Target].y = target + 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() __SCENE = Scene( [__spawn_elements], - [ - __goal, - __move_up, - __move_down, - __box, - __ball_movement, - __update_score, - ], + [__update_move, __update_animation], [], ) - ONE_PLAYER = ( Plugin( - # Modifie le GameMode en ONE a l'initialisation de la scene [lambda world: world.set(GameMode.ONE)], - [ - __update_bot_move, - ], + [_update_bot], [], ) + __SCENE ) - TWO_PLAYER = ( Plugin( - # Modifie le GameMode en TWO a l'initialisation de la scene [lambda world: world.set(GameMode.TWO)], [], [], diff --git a/src/scenes/menu.py b/src/scenes/menu.py index 3d588a5..cd7bb9b 100644 --- a/src/scenes/menu.py +++ b/src/scenes/menu.py @@ -3,7 +3,7 @@ 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 plugins.sound import Loop, Sound from engine import CurrentScene, KeepAlive, Scene from engine.ecs import Entity, World from engine.math import Vec2 @@ -39,10 +39,8 @@ def __on_click_butons(world: World, _entity: Entity, name: str): """ match name: case "one_player": - # TODO world[CurrentScene] = game.ONE_PLAYER case "two_player": - # TODO world[CurrentScene] = game.TWO_PLAYER case _: pass @@ -54,7 +52,7 @@ def __spawn_elements(world: World): Ajoute les éléments du menu dans le monde. """ - world.new_entity().set(Sound("music.mp3"), KeepAlive()) + world.new_entity().set(Sound("music.mp3"), KeepAlive(), Loop()) world.new_entity().set(SpriteBundle("background_menu.png", -5))