Entités et components

Pyxen utilise un Entity-Component System (ECS). Si vous avez déjà utilisé des moteurs de jeu avec des hiérarchies de classes — où un Player hérite de Character qui hérite de GameObject — c’est différent. Dans Pyxen, il n’y a pas d’héritage. Tout repose sur la composition.

Entités

Une entity est un objet de jeu. Ce peut être un joueur, un mur, un projectile, une particule — n’importe quoi. Sous le capot, une entity est simplement un identifiant. Elle ne contient aucune donnée par elle-même. À la place, vous lui attachez des components.

player = world.spawn(name="player", x=100, y=50)

Cela crée une entity à la position (100, 50) avec un nom. L’entity existe dans le monde et sera affichée si elle possède un sprite.

Components

Les components sont des données attachées à une entity. Pyxen en propose deux types :

Components intégrés

Ceux-ci sont fournis par le moteur :

ComponentFonction
TransformPosition (x, y), rotation, échelle
SpriteApparence visuelle — image, tile, pivot, couleur
CameraViewport avec zoom
GridBodyCorps de collision sur la grille
GridMapTilemap avec lignes, colonnes et données de tiles
SoundLecture d’effets sonores
MusicLecture de flux musical
NameIdentifiant textuel pour la recherche
LayerCouche de rendu (0–255)
Parent / ChildrenHiérarchie de scène

Vous définissez les components intégrés via les propriétés de l’entity ou au moment de la création :

e = world.spawn(
    x=50, y=80,
    sprite=Sprite("hero"),
    name="player"
)

# plus tard
e.x = 100
e.sprite = Sprite("hero", tile=(16, 0, 16, 16))

Components personnalisés

Vous pouvez attacher vos propres components à n’importe quelle entity. Un component personnalisé est un dictionnaire avec des champs typés :

player.health = {"value": 100, "max": 100}
player.speed = {"value": 2.5}

Une fois attaché, vous accédez directement aux champs :

player.health.value -= 10

Vous pouvez aussi utiliser des components marqueurs — des components sans données qui servent d’étiquettes :

player.alive = True
enemy.boss = True

C’est utile pour les requêtes : vous pouvez trouver toutes les entités possédant un marqueur donné.

Types de champs

Les champs de components peuvent être :

TypeExempleNotes
int42Entier 32 bits
float3.14Flottant 32 bits
boolTrueBooléen
str"hello"31 caractères maximum
EntityplayerRéférence vers une autre entity

Ces contraintes existent car les components sont stockés dans un format compact et optimisé pour le cache à l’intérieur du moteur C++. C’est ce qui rend les requêtes rapides.

Rechercher des entités

Le monde vous permet de trouver des entités par leurs components :

# toutes les entités avec un component "health"
for e in world.all("health"):
    if e.health.value <= 0:
        world.destroy(e)

# combiner : possède "enemy", ne possède pas "dead"
for e in world.all("enemy", without=("dead",)):
    e.x += e.speed.value

Vous pouvez aussi effectuer des requêtes sur les components intégrés comme "sprite", "body", "camera", "sound", "music" et "map" :

# toutes les entités avec un sprite
for e in world.all("sprite"):
    e.color = (1, 1, 1, 1)

# entités ayant à la fois un sprite et le component personnalisé "enemy"
for e in world.all("sprite", "enemy"):
    e.color = (1, 0, 0, 1)

Les requêtes sont la principale façon d’écrire la logique de jeu dans Pyxen. Au lieu que chaque objet se mette à jour lui-même, vous écrivez des systèmes qui parcourent les entités possédant des components spécifiques.

Consultez l’API complète : world.all(), Entity

Pourquoi l’ECS ?

Si vous êtes habitué à la programmation orientée objet pour les jeux, l’ECS peut sembler inhabituel au début. Ses avantages :