ecs #58
|
@ -7,11 +7,11 @@ from typing import Callable, Optional
|
||||||
from engine.ecs import World
|
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.
|
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.post_update_systems = post_update_systems
|
||||||
self.stop_systems = stop_systems
|
self.stop_systems = stop_systems
|
||||||
|
|
||||||
def __add__(self, other: "GlobalScene") -> "GlobalScene":
|
def __add__(self, other: "GlobalPlugin") -> "GlobalPlugin":
|
||||||
return GlobalScene(
|
return GlobalPlugin(
|
||||||
self.init_systems + other.init_systems,
|
self.init_systems + other.init_systems,
|
||||||
self.pre_update_systems + other.pre_update_systems,
|
self.pre_update_systems + other.pre_update_systems,
|
||||||
self.post_update_systems + other.post_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:
|
class KeepAlive:
|
||||||
"""
|
"""
|
||||||
Composant qui marque une entité comme n'étant pas détruit lors
|
Composant qui marque une entité comme n'étant pas détruit lors
|
||||||
|
@ -82,7 +93,7 @@ class CurrentScene(KeepAlive):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def start_game(global_scene: GlobalScene, scene: Optional[Scene]):
|
def start_game(global_scene: GlobalPlugin, scene: Optional[Scene]):
|
||||||
"""
|
"""
|
||||||
Lance un jeu.
|
Lance un jeu.
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,14 @@
|
||||||
Un plugin qui permet de jouer des animations de sprites.
|
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:
|
class Animation:
|
||||||
|
@ -11,13 +18,75 @@ class Animation:
|
||||||
sur l'entité.
|
sur l'entité.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(
|
||||||
pass
|
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 glob
|
||||||
import pygame
|
import pygame
|
||||||
from engine import CurrentScene, GlobalScene, KeepAlive, Scene
|
from engine import CurrentScene, GlobalPlugin, KeepAlive, Scene
|
||||||
from engine.ecs import World
|
from engine.ecs import World
|
||||||
from plugins import render
|
from plugins import render
|
||||||
|
|
||||||
|
@ -29,6 +29,15 @@ class Assets(KeepAlive):
|
||||||
# Cache des ressources
|
# Cache des ressources
|
||||||
self.__textures: dict[str, pygame.Surface] = {}
|
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
|
@property
|
||||||
def unloaded_texture(self) -> pygame.Surface:
|
def unloaded_texture(self) -> pygame.Surface:
|
||||||
"""
|
"""
|
||||||
|
@ -56,6 +65,8 @@ class Assets(KeepAlive):
|
||||||
def get_texture(self, name: str) -> pygame.Surface:
|
def get_texture(self, name: str) -> pygame.Surface:
|
||||||
"""
|
"""
|
||||||
Renvoie la texture demandée.
|
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)
|
return self.__textures.get(name, self.__error_texture)
|
||||||
|
|
||||||
|
@ -73,7 +84,7 @@ def __initialize(world: World):
|
||||||
world.set(Assets())
|
world.set(Assets())
|
||||||
|
|
||||||
|
|
||||||
PLUGIN = GlobalScene(
|
PLUGIN = GlobalPlugin(
|
||||||
[__initialize],
|
[__initialize],
|
||||||
[],
|
[],
|
||||||
[],
|
[],
|
||||||
|
|
|
@ -2,7 +2,14 @@
|
||||||
Plugin qui rassemple tous les plugins globaux.
|
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
|
import pygame
|
||||||
from engine.ecs import World
|
from engine.ecs import World
|
||||||
from engine import GlobalScene
|
from engine import GlobalPlugin
|
||||||
|
|
||||||
|
|
||||||
def __initialize(_world: World):
|
def __initialize(_world: World):
|
||||||
|
@ -23,7 +23,7 @@ def __terminate(_world: World):
|
||||||
pygame.quit()
|
pygame.quit()
|
||||||
|
|
||||||
|
|
||||||
PLUGIN = GlobalScene(
|
PLUGIN = GlobalPlugin(
|
||||||
[__initialize],
|
[__initialize],
|
||||||
[],
|
[],
|
||||||
[],
|
[],
|
||||||
|
|
|
@ -3,7 +3,7 @@ Un plugin permettant de gérer les entrées utilisateur du jeu.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import pygame
|
import pygame
|
||||||
from engine import CurrentScene, GlobalScene, KeepAlive
|
from engine import CurrentScene, GlobalPlugin, KeepAlive
|
||||||
from engine.ecs import World
|
from engine.ecs import World
|
||||||
from engine.math import Vec2
|
from engine.math import Vec2
|
||||||
from plugins import render
|
from plugins import render
|
||||||
|
@ -78,7 +78,7 @@ def __update_input(world: World):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
PLUGIN = GlobalScene(
|
PLUGIN = GlobalPlugin(
|
||||||
[__initialize],
|
[__initialize],
|
||||||
[__update_input],
|
[__update_input],
|
||||||
[],
|
[],
|
||||||
|
|
|
@ -4,7 +4,7 @@ Un plugin qui s'occupe de rendre des choses dans la fenetre.
|
||||||
|
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
import pygame
|
import pygame
|
||||||
from engine import GlobalScene, KeepAlive
|
from engine import GlobalPlugin, KeepAlive
|
||||||
from engine.ecs import World
|
from engine.ecs import World
|
||||||
from engine.math import Vec2
|
from engine.math import Vec2
|
||||||
|
|
||||||
|
@ -42,20 +42,20 @@ class Sprite:
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
surface: pygame.Surface,
|
texture: pygame.Surface,
|
||||||
position: Vec2 = Vec2(0),
|
position: Vec2 = Vec2(0),
|
||||||
order: float = -1.0,
|
order: float = -1.0,
|
||||||
area: Optional[tuple[float, float, float, float]] = None,
|
area: Optional[tuple[float, float, float, float]] = None,
|
||||||
):
|
):
|
||||||
self.surface = surface
|
self.texture = texture
|
||||||
self.position = position
|
self.position = position
|
||||||
self.order = order
|
self.order = order
|
||||||
if area is None:
|
if area is None:
|
||||||
self.area = (
|
self.area = (
|
||||||
0.0,
|
0.0,
|
||||||
0.0,
|
0.0,
|
||||||
float(surface.get_width()),
|
float(texture.get_width()),
|
||||||
float(surface.get_height()),
|
float(texture.get_height()),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.area = area
|
self.area = area
|
||||||
|
@ -77,7 +77,7 @@ def __render(world: World):
|
||||||
sprites = [entity[Sprite] for entity in world.query(Sprite)]
|
sprites = [entity[Sprite] for entity in world.query(Sprite)]
|
||||||
for sprite in sorted(sprites, key=lambda sprite: sprite.order):
|
for sprite in sorted(sprites, key=lambda sprite: sprite.order):
|
||||||
surface.blit(
|
surface.blit(
|
||||||
sprite.surface,
|
sprite.texture,
|
||||||
(sprite.position.x, sprite.position.y),
|
(sprite.position.x, sprite.position.y),
|
||||||
sprite.area,
|
sprite.area,
|
||||||
)
|
)
|
||||||
|
@ -93,7 +93,7 @@ def __render(world: World):
|
||||||
pygame.display.flip()
|
pygame.display.flip()
|
||||||
|
|
||||||
|
|
||||||
PLUGIN = GlobalScene(
|
PLUGIN = GlobalPlugin(
|
||||||
[__initialize],
|
[__initialize],
|
||||||
[],
|
[],
|
||||||
[__render],
|
[__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