Ajout de score en ligne #9

Merged
tipragot merged 8 commits from score into main 2024-01-07 07:32:54 +00:00
24 changed files with 1211 additions and 744 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.3 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

View file

@ -5,8 +5,9 @@ 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 World
from engine.ecs import Entity, World
class GlobalTime(KeepAlive, float):
@ -34,6 +35,16 @@ def __initialize(world: World):
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.
@ -43,6 +54,14 @@ def __update(world: World):
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],

63
src/plugins/writing.py Normal file
View file

@ -0,0 +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],
[],
)

View file

@ -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 render
@ -22,6 +22,8 @@ from plugins.timing import Delta, Time
import random
from plugins.physics import CollisionHandler, Solid, Velocity
from scenes import game_over
class GameMode(Enum):
"""
@ -86,7 +88,7 @@ class Speed(int):
"""
class Player1Score(int):
class Player1Score(int, KeepAlive):
"""
Ressource qui represente le score du joueur 1.
"""
@ -110,6 +112,12 @@ class StartAnimation(float):
"""
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
@ -226,6 +234,9 @@ def __spawn_ellements(world: World):
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(),
)
@ -234,6 +245,9 @@ def __spawn_ellements(world: World):
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(),
)
@ -275,16 +289,29 @@ 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(),
)
# 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):
@ -368,11 +395,33 @@ 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[Velocity].length
a[Velocity] = a[Velocity].normalized
a[Velocity].y = (a[Position].y - b[Position].y) * 0.005
a[Velocity] = a[Velocity].normalized * min((speed * 1.1), 1000.0)
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
@ -382,8 +431,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
@ -394,7 +447,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
@ -402,7 +458,7 @@ def __bounce_on_right_wall(a: Entity, b: Entity):
def __move_up(world: World):
"""
La fonction permet de faire bouger les entitees vers le haut.
La fonction permet de faire bouger les entitees qui possedent UpKey vers le haut.
"""
held = world[Held]
for entity in world.query(UpKey):
@ -415,7 +471,7 @@ def __move_up(world: World):
def __move_down(world: World):
"""
La fonction permet de faire bouger les entitees vers le bas.
La fonction permet de faire bouger les entitees qui possedent DownKey vers le bas.
"""
held = world[Held]
for entity in world.query(DownKey):
@ -539,11 +595,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)

81
src/scenes/game_over.py Normal file
View file

@ -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 = ["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],
[],
[],
)

View file

@ -10,8 +10,20 @@ from engine.math import Vec2
from plugins import render
from plugins.click import Clickable
from plugins.hover import HoveredTexture
from plugins.render import SpriteBundle
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):
@ -21,7 +33,7 @@ def __create_button(world: World, i: int, name: str):
world.new_entity().set(
SpriteBundle(
f"button_{name}.png",
position=Vec2(450 + 540 * i, render.HEIGHT / 2),
position=Vec2(450 + 540 * i, 11 * render.HEIGHT / 16),
order=1,
origin=Vec2(0.5),
),
@ -51,8 +63,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))
@ -60,6 +72,33 @@ def __spawn_elements(world: World):
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],

View file

@ -0,0 +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
)

37
src/scenes/thanks.py Normal file
View file

@ -0,0 +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],
[],
[],
)

73
src/scenes/try_again.py Normal file
View file

@ -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 "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],
[],
[],
)