ecs #58
|
@ -7,11 +7,11 @@ from typing import Callable, Optional
|
|||
from engine.ecs import World
|
||||
|
||||
|
||||
class GlobalScene:
|
||||
class GlobalPlugin:
|
||||
"""
|
||||
Une scène globale du jeu.
|
||||
Un plugin global du jeu.
|
||||
|
||||
La scène sera executé avant et après la scène actuelle du jeu.
|
||||
Le plugin sera executé avant et après la scène courrante du jeu.
|
||||
Elle sera aussi executé au démarage et à l'arrêt du jeu.
|
||||
"""
|
||||
|
||||
|
@ -27,8 +27,8 @@ class GlobalScene:
|
|||
self.post_update_systems = post_update_systems
|
||||
self.stop_systems = stop_systems
|
||||
|
||||
def __add__(self, other: "GlobalScene") -> "GlobalScene":
|
||||
return GlobalScene(
|
||||
def __add__(self, other: "GlobalPlugin") -> "GlobalPlugin":
|
||||
return GlobalPlugin(
|
||||
self.init_systems + other.init_systems,
|
||||
self.pre_update_systems + other.pre_update_systems,
|
||||
self.post_update_systems + other.post_update_systems,
|
||||
|
@ -59,6 +59,17 @@ class Scene:
|
|||
)
|
||||
|
||||
|
||||
class Plugin(Scene):
|
||||
"""
|
||||
Un plugin peut être ajouté a une scène pour lui ajouter des fonctionnalitées.
|
||||
|
||||
Techniquement, un `Plugin` est une simple `Scène` et le nom `Plugin` est
|
||||
juste là pour indiquer qu'il s'agit d'un plugin. Et le fait de pouvoir ajouter
|
||||
le `Plugin` à une scène est due au fait que l'on peut combiner des scènes entre
|
||||
elles.
|
||||
"""
|
||||
|
||||
|
||||
class KeepAlive:
|
||||
"""
|
||||
Composant qui marque une entité comme n'étant pas détruit lors
|
||||
|
@ -82,7 +93,7 @@ class CurrentScene(KeepAlive):
|
|||
return False
|
||||
|
||||
|
||||
def start_game(global_scene: GlobalScene, scene: Optional[Scene]):
|
||||
def start_game(global_scene: GlobalPlugin, scene: Optional[Scene]):
|
||||
"""
|
||||
Lance un jeu.
|
||||
|
||||
|
|
|
@ -2,7 +2,14 @@
|
|||
Un plugin qui permet de jouer des animations de sprites.
|
||||
"""
|
||||
|
||||
from engine import GlobalScene
|
||||
from typing import Callable
|
||||
|
||||
import pygame
|
||||
from engine import GlobalPlugin
|
||||
from engine.ecs import Entity, World
|
||||
from plugins.assets import Assets
|
||||
from plugins.render import Sprite
|
||||
from plugins.timing import Delta
|
||||
|
||||
|
||||
class Animation:
|
||||
|
@ -11,13 +18,75 @@ class Animation:
|
|||
sur l'entité.
|
||||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
pass
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
fps: float = 60.0,
|
||||
loop: bool = False,
|
||||
callback: Callable[[World, Entity], object] = lambda _w, _e: None,
|
||||
) -> None:
|
||||
self.name = name
|
||||
self.fps = fps
|
||||
self.loop = loop
|
||||
self.callback = callback
|
||||
self.timer = 0.0
|
||||
|
||||
|
||||
PLUGIN = GlobalScene(
|
||||
[],
|
||||
def __update_sprite(entity: Entity, texture: pygame.Surface, assets: Assets):
|
||||
"""
|
||||
Change la texture de la `Sprite` d'une entité.
|
||||
|
||||
Si l'entité n'as pas de `Sprite`, une nouvelle `Sprite` sera ajoutée.
|
||||
Si la texture est la texture d'erreur, la texture de la `Sprite` ne
|
||||
sera pas changée.
|
||||
"""
|
||||
if texture is assets.error_texture:
|
||||
return
|
||||
if Sprite not in entity:
|
||||
entity[Sprite] = Sprite(texture)
|
||||
else:
|
||||
entity[Sprite].texture = texture
|
||||
|
||||
|
||||
def __update_animations(world: World) -> None:
|
||||
"""
|
||||
Met à jour les sprites des animations.
|
||||
"""
|
||||
assets = world[Assets]
|
||||
delta = world[Delta]
|
||||
for entity in world.query(Animation):
|
||||
animation = entity[Animation]
|
||||
animation.timer += delta
|
||||
|
||||
# On récupère la texture correspondante a la frame de l'animation
|
||||
frame_index = int(animation.timer * animation.fps)
|
||||
texture = assets.get_texture(f"{animation.name}/{frame_index:04d}")
|
||||
|
||||
# Si la texture n'existe pas, l'animation est finie
|
||||
if texture is assets.error_texture:
|
||||
if animation.loop:
|
||||
# Si l'animation est une boucle on met la première image de l'animation
|
||||
animation.timer = 0.0
|
||||
__update_sprite(
|
||||
entity, assets.get_texture(f"{animation.name}/0000"), assets
|
||||
)
|
||||
|
||||
# Et on appelle la fonction de callback
|
||||
animation.callback(world, entity)
|
||||
else:
|
||||
# Sinon on supprime le composant `Animation`
|
||||
del entity[Animation]
|
||||
|
||||
# Et on appelle la fonction de callback
|
||||
animation.callback(world, entity)
|
||||
else:
|
||||
# Si l'animation n'est pas finie, on met à jour la texture
|
||||
__update_sprite(entity, texture, assets)
|
||||
|
||||
|
||||
PLUGIN = GlobalPlugin(
|
||||
[],
|
||||
[__update_animations],
|
||||
[],
|
||||
[],
|
||||
)
|
||||
|
|
|
@ -4,7 +4,7 @@ Un plugin qui gère les ressources du jeu.
|
|||
|
||||
import glob
|
||||
import pygame
|
||||
from engine import CurrentScene, GlobalScene, KeepAlive, Scene
|
||||
from engine import CurrentScene, GlobalPlugin, KeepAlive, Scene
|
||||
from engine.ecs import World
|
||||
from plugins import render
|
||||
|
||||
|
@ -29,6 +29,15 @@ class Assets(KeepAlive):
|
|||
# Cache des ressources
|
||||
self.__textures: dict[str, pygame.Surface] = {}
|
||||
|
||||
@property
|
||||
def error_texture(self) -> pygame.Surface:
|
||||
"""
|
||||
La texture d'erreur.
|
||||
|
||||
Cette texture est utilisé lorsque la texture demandée n'existe pas.
|
||||
"""
|
||||
return self.__error_texture
|
||||
|
||||
@property
|
||||
def unloaded_texture(self) -> pygame.Surface:
|
||||
"""
|
||||
|
@ -56,6 +65,8 @@ class Assets(KeepAlive):
|
|||
def get_texture(self, name: str) -> pygame.Surface:
|
||||
"""
|
||||
Renvoie la texture demandée.
|
||||
|
||||
Si la texture n'existe pas dans le cache, la texture d'erreur sera renvoyée.
|
||||
"""
|
||||
return self.__textures.get(name, self.__error_texture)
|
||||
|
||||
|
@ -73,7 +84,7 @@ def __initialize(world: World):
|
|||
world.set(Assets())
|
||||
|
||||
|
||||
PLUGIN = GlobalScene(
|
||||
PLUGIN = GlobalPlugin(
|
||||
[__initialize],
|
||||
[],
|
||||
[],
|
||||
|
|
|
@ -2,7 +2,14 @@
|
|||
Plugin qui rassemple tous les plugins globaux.
|
||||
"""
|
||||
|
||||
from plugins import assets, display, inputs, render
|
||||
from plugins import animation, assets, display, inputs, render, timing
|
||||
|
||||
|
||||
PLUGIN = display.PLUGIN + assets.PLUGIN + inputs.PLUGIN + render.PLUGIN
|
||||
PLUGIN = (
|
||||
display.PLUGIN
|
||||
+ timing.PLUGIN
|
||||
+ assets.PLUGIN
|
||||
+ inputs.PLUGIN
|
||||
+ animation.PLUGIN
|
||||
+ render.PLUGIN
|
||||
)
|
||||
|
|
|
@ -5,7 +5,7 @@ Un plugin pour la gestion de la fenetre du jeu.
|
|||
|
||||
import pygame
|
||||
from engine.ecs import World
|
||||
from engine import GlobalScene
|
||||
from engine import GlobalPlugin
|
||||
|
||||
|
||||
def __initialize(_world: World):
|
||||
|
@ -23,7 +23,7 @@ def __terminate(_world: World):
|
|||
pygame.quit()
|
||||
|
||||
|
||||
PLUGIN = GlobalScene(
|
||||
PLUGIN = GlobalPlugin(
|
||||
[__initialize],
|
||||
[],
|
||||
[],
|
||||
|
|
|
@ -3,7 +3,7 @@ Un plugin permettant de gérer les entrées utilisateur du jeu.
|
|||
"""
|
||||
|
||||
import pygame
|
||||
from engine import CurrentScene, GlobalScene, KeepAlive
|
||||
from engine import CurrentScene, GlobalPlugin, KeepAlive
|
||||
from engine.ecs import World
|
||||
from engine.math import Vec2
|
||||
from plugins import render
|
||||
|
@ -78,7 +78,7 @@ def __update_input(world: World):
|
|||
)
|
||||
|
||||
|
||||
PLUGIN = GlobalScene(
|
||||
PLUGIN = GlobalPlugin(
|
||||
[__initialize],
|
||||
[__update_input],
|
||||
[],
|
||||
|
|
|
@ -4,7 +4,7 @@ Un plugin qui s'occupe de rendre des choses dans la fenetre.
|
|||
|
||||
from typing import Optional
|
||||
import pygame
|
||||
from engine import GlobalScene, KeepAlive
|
||||
from engine import GlobalPlugin, KeepAlive
|
||||
from engine.ecs import World
|
||||
from engine.math import Vec2
|
||||
|
||||
|
@ -42,20 +42,20 @@ class Sprite:
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
surface: pygame.Surface,
|
||||
texture: pygame.Surface,
|
||||
position: Vec2 = Vec2(0),
|
||||
order: float = -1.0,
|
||||
area: Optional[tuple[float, float, float, float]] = None,
|
||||
):
|
||||
self.surface = surface
|
||||
self.texture = texture
|
||||
self.position = position
|
||||
self.order = order
|
||||
if area is None:
|
||||
self.area = (
|
||||
0.0,
|
||||
0.0,
|
||||
float(surface.get_width()),
|
||||
float(surface.get_height()),
|
||||
float(texture.get_width()),
|
||||
float(texture.get_height()),
|
||||
)
|
||||
else:
|
||||
self.area = area
|
||||
|
@ -77,7 +77,7 @@ def __render(world: World):
|
|||
sprites = [entity[Sprite] for entity in world.query(Sprite)]
|
||||
for sprite in sorted(sprites, key=lambda sprite: sprite.order):
|
||||
surface.blit(
|
||||
sprite.surface,
|
||||
sprite.texture,
|
||||
(sprite.position.x, sprite.position.y),
|
||||
sprite.area,
|
||||
)
|
||||
|
@ -93,7 +93,7 @@ def __render(world: World):
|
|||
pygame.display.flip()
|
||||
|
||||
|
||||
PLUGIN = GlobalScene(
|
||||
PLUGIN = GlobalPlugin(
|
||||
[__initialize],
|
||||
[],
|
||||
[__render],
|
||||
|
|
52
src/plugins/timing.py
Normal file
52
src/plugins/timing.py
Normal file
|
@ -0,0 +1,52 @@
|
|||
"""
|
||||
Un plugin permettant de connaitre le temps depuis le
|
||||
lancement du jeu et le temps depuis la dernière frame.
|
||||
"""
|
||||
|
||||
|
||||
from time import time
|
||||
from engine import GlobalPlugin
|
||||
from engine.ecs import World
|
||||
|
||||
|
||||
class GlobalTime(float):
|
||||
"""
|
||||
Ressource qui représente le temps global de l'ordinateur sur lequel tourne le jeu.
|
||||
"""
|
||||
|
||||
|
||||
class Time(float):
|
||||
"""
|
||||
Ressource qui représente le temps depuis le lancement du jeu.
|
||||
"""
|
||||
|
||||
|
||||
class Delta(float):
|
||||
"""
|
||||
Ressource qui détermine le temps depuis la première frame.
|
||||
"""
|
||||
|
||||
|
||||
def __initialize(world: World):
|
||||
"""
|
||||
Initialise les ressources pour la gestion du temps.
|
||||
"""
|
||||
world.set(GlobalTime(time()), Time(0.0))
|
||||
|
||||
|
||||
def __update(world: World):
|
||||
"""
|
||||
Met à jour les ressources de temps.
|
||||
"""
|
||||
now = time()
|
||||
world[Delta] = delta = now - world[GlobalTime]
|
||||
world[GlobalTime] = now
|
||||
world[Time] += delta
|
||||
|
||||
|
||||
PLUGIN = GlobalPlugin(
|
||||
[__initialize],
|
||||
[__update],
|
||||
[],
|
||||
[],
|
||||
)
|
Loading…
Reference in a new issue