Adaptation au nouvel ecs #3

Merged
tipragot merged 6 commits from ecs-friendly into main 2024-01-05 16:26:33 +00:00
4 changed files with 249 additions and 228 deletions
Showing only changes of commit c3ce3fdcbf - Show all commits

View file

@ -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)

View file

@ -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(

View file

@ -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.
"""
raphael marked this conversation as resolved
Review

C'est une ressource

C'est une ressource
class Velocity(Vec2):
class Player2Score(int):
"""
Composant qui definit le vecteur vitesse d'une entité
Composant qui represente le score du joueur 2.
"""
raphael marked this conversation as resolved
Review

C'est une ressource

C'est une ressource
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.
"""
raphael marked this conversation as resolved
Review

Plutot: marque l'entité comme étant l'affichage du score

Plutot: marque l'entité comme étant l'affichage du score
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
"""
raphael marked this conversation as resolved
Review

Préciser de quel animation on parle

Préciser de quel animation on parle
def __spawn_elements(world: World):
"""
Ajoute les éléments du menu dans le monde.
La fonction permet de initializer les ellements de la scene.
"""
raphael marked this conversation as resolved
Review

elllllllllements

elllllllllements
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:
# Joueur 2
world.new_entity().set(
SpriteBundle(
("player_2.png"), 0, Vec2(1340, 200), Vec2(44, 250), Vec2(0.5)
"player_2.png",
0,
Vec2(render.WIDTH - 100, render.HEIGHT / 2),
Vec2(44, 250),
Vec2(0.5),
),
Player(),
UpKey("up"),
DownKey("down"),
Speed(1000),
Boxed(),
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:
raphael marked this conversation as resolved
Review

Manque de doc

Manque de doc
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)],
[],
[],

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.
"""
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))