Recode de tous le jeux en ecs friendly

This commit is contained in:
Raphaël 2024-01-04 17:18:39 +01:00
parent 01668c922f
commit c3ce3fdcbf
4 changed files with 249 additions and 228 deletions

View file

@ -13,7 +13,7 @@ def __initialize(_world: World):
Initialise pygame et les ressources pour la gestion de la fenetre. Initialise pygame et les ressources pour la gestion de la fenetre.
""" """
pygame.init() pygame.init()
pygame.display.set_caption("Guess The Number") pygame.display.set_caption("Ponguito")
pygame.display.set_mode((800, 600), pygame.RESIZABLE) pygame.display.set_mode((800, 600), pygame.RESIZABLE)

View file

@ -207,27 +207,11 @@ def __update(world: World):
bar.set(physics.Solid()) bar.set(physics.Solid())
entity.destroy() entity.destroy()
# for bar in world.query(Bar):
# bar.remove(physics.Solid)
for entity in world.query(BallFollow): for entity in world.query(BallFollow):
entity[Position] = Vec2(ball[Position]) entity[Position] = Vec2(ball[Position])
entity[physics.Velocity] = Vec2(ball[physics.Velocity]) entity[physics.Velocity] = Vec2(ball[physics.Velocity])
physics.move_entity(entity, entity[physics.Velocity] * entity[BallFollow] * 0.5) physics.move_entity(entity, entity[physics.Velocity] * entity[BallFollow] * 0.5)
del entity[physics.Velocity] 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( MENU = Scene(

View file

@ -1,32 +1,69 @@
"""
Le jeux principale.
"""
from enum import Enum from enum import Enum
from math import e
import time
from engine import Plugin, Scene from engine import Plugin, Scene
from engine.ecs import Entity, World from engine.ecs import Entity, World
from engine.math import Vec2 from engine.math import Vec2
from plugins import render from plugins import physics, render
from plugins.inputs import Held from plugins.inputs import Held
from plugins.timing import Delta from plugins.render import (
from plugins.sound import Sound Origin,
from plugins.render import Origin, Position, Scale, SpriteBundle, Text, TextBundle Position,
Scale,
SpriteBundle,
TextBundle,
Text,
TextSize,
)
from plugins.timing import Delta, Time
class GameMode(Enum): class GameMode(Enum):
""" """
Definit un ressource represantant le mode de jeu actuel. Ressource qui definit le game mode choisi par l'utilisateur.
""" """
ONE = 0 ONE = 0
TWO = 1 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): class Speed(int):
""" """
Composant qui represente la vitesse de l'entité. 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 Composant qui represente un le moment auxquel on a lancé l'animation
"""
class ScorePlayer2(int):
"""
Ressource qui represente le score du joueur 2
""" """
def __spawn_elements(world: World): 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( world.new_entity().set(
SpriteBundle(("player_1.png"), 0, Vec2(100, 200), Vec2(44, 250), Vec2(0.5)), Origin(Vec2(1, 0)),
Player(), 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"), UpKey("z"),
DownKey("s"), DownKey("s"),
Speed(1000), Speed(1000),
Boxed(),
) )
if world[GameMode] == GameMode.TWO: # Joueur 2
world.new_entity().set( world.new_entity().set(
SpriteBundle( SpriteBundle(
("player_2.png"), 0, Vec2(1340, 200), Vec2(44, 250), Vec2(0.5) "player_2.png",
), 0,
Player(), Vec2(render.WIDTH - 100, render.HEIGHT / 2),
UpKey("up"), Vec2(44, 250),
DownKey("down"), Vec2(0.5),
Speed(1000), ),
Boxed(), physics.Solid(),
) Player2(),
(UpKey("up"), DownKey("down"), Speed(1000))
if world[GameMode] == GameMode.TWO
else None,
)
else: __spawn_ball(world)
world.new_entity().set(
SpriteBundle( # Initialisation des scores
("player_2.png"), 0, Vec2(1340, 200), Vec2(44, 250), Vec2(0.5) world.set(Player1Score(0), Player2Score(0))
),
Bot(),
smooth.Target(Vec2(1340, 200)),
Player(),
smooth.Speed(3),
Boxed(),
)
world.new_entity().set( world.new_entity().set(
TextBundle( TextBundle(
f"{world[ScorePlayer1]} - {world[ScorePlayer2]}", "0 - 0",
position=Vec2(render.WIDTH / 2, 100), 10,
order=5, 50,
position=Vec2(render.WIDTH / 2, 75),
origin=Vec2(0.5), origin=Vec2(0.5),
), ),
Score(),
) )
__spawn_animation(world)
__spawn_ball(world)
def __spawn_ball(world: World): def __spawn_ball(world: World):
# Balle
world.new_entity().set( world.new_entity().set(
SpriteBundle( SpriteBundle(
("ball.png"), "ball.png",
2, 0,
Vec2(render.WIDTH / 2, render.HEIGHT / 2), Vec2(render.WIDTH / 2, render.HEIGHT / 2),
origin=Vec2(0.5), Vec2(40, 40),
Vec2(0.5),
), ),
Ball(), Ball(),
Velocity(Vec2(200, 30)), physics.Velocity(Vec2(-200, -100)),
Boxed(), physics.CollisionHandler(__bounce_on_player),
) )
def __after_anim(world: World, entity: Entity): def __bounce_on_player(a: Entity, b: Entity):
entity.destroy() if Player1 in b or Player2 in b:
__spawn_ball(world) 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): def __move_up(world: World):
""" """
TODO La fonction permet de faire bouger les entitees vers le haut.
""" """
held = world[Held] held = world[Held]
for entity in world.query(UpKey): for entity in world.query(UpKey):
@ -172,7 +266,7 @@ def __move_up(world: World):
def __move_down(world: World): def __move_down(world: World):
""" """
TODO La fonction permet de faire bouger les entitees vers le bas.
""" """
held = world[Held] held = world[Held]
for entity in world.query(DownKey): 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 # met a jour le score du joueur 1 et 2
NIQUEZ VOUS for panel in world.query(Score):
""" panel[Text] = f"{world[Player1Score]} - {world[Player2Score]}"
gap = 50
for entity in world.query(Boxed):
diff_up = gap - entity[Position].y
diff_down = entity[Position].y - (render.HEIGHT - gap)
# Top ball.destroy()
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())
# Bottom if world.query(Ball) == set():
elif entity[Position].y + (entity[Scale].y * entity[Origin].y) > ( __animation(world, 3)
render.HEIGHT - gap
):
entity[Position].y -= entity[Scale].y * entity[Origin].y + diff_down def __animation(world: World, number: int):
entity.set(Blocked()) 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: else:
if Blocked in entity: animation[TextSize] -= 1000 * world[Delta]
entity.remove(Blocked) if animation[TextSize] < 0:
if int(animation[Text]) > 1 or "space" in world[Held]:
__animation(world, int(animation[Text]) - 1)
def __ball_movement(world: World): else:
for ball in world.query(Ball, Velocity): # creation de la balle
if Blocked in ball: __spawn_ball(world)
ball[Velocity].y = -ball[Velocity].y animation.destroy()
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
__SCENE = Scene( __SCENE = Scene(
[__spawn_elements], [__spawn_elements],
[ [__update_move, __update_animation],
__goal,
__move_up,
__move_down,
__box,
__ball_movement,
__update_score,
],
[], [],
) )
ONE_PLAYER = ( ONE_PLAYER = (
Plugin( Plugin(
# Modifie le GameMode en ONE a l'initialisation de la scene
[lambda world: world.set(GameMode.ONE)], [lambda world: world.set(GameMode.ONE)],
[ [_update_bot],
__update_bot_move,
],
[], [],
) )
+ __SCENE + __SCENE
) )
TWO_PLAYER = ( TWO_PLAYER = (
Plugin( Plugin(
# Modifie le GameMode en TWO a l'initialisation de la scene
[lambda world: world.set(GameMode.TWO)], [lambda world: world.set(GameMode.TWO)],
[], [],
[], [],

View file

@ -3,7 +3,7 @@ La scène du menu principal du jeu.
Dans cette scène nous pouvons choisir le mode de 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 import CurrentScene, KeepAlive, Scene
from engine.ecs import Entity, World from engine.ecs import Entity, World
from engine.math import Vec2 from engine.math import Vec2
@ -39,10 +39,8 @@ def __on_click_butons(world: World, _entity: Entity, name: str):
""" """
match name: match name:
case "one_player": case "one_player":
# TODO
world[CurrentScene] = game.ONE_PLAYER world[CurrentScene] = game.ONE_PLAYER
case "two_player": case "two_player":
# TODO
world[CurrentScene] = game.TWO_PLAYER world[CurrentScene] = game.TWO_PLAYER
case _: case _:
pass pass
@ -54,7 +52,7 @@ def __spawn_elements(world: World):
Ajoute les éléments du menu dans le monde. 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)) world.new_entity().set(SpriteBundle("background_menu.png", -5))