Collision
Pyxen utilise un système de collision basé sur une grille. Les corps de collision vivent sur une grille spatiale et le moteur détecte les chevauchements entre eux à chaque frame. Cela rend la détection de collision simple, rapide et déterministe.
Grid maps et grid bodies
Un GridMap définit le monde spatial — une grille de tiles avec une taille de cellule donnée. Un GridBody est un rectangle de collision qui vit à l’intérieur de cette grille.
L’entity possédant un GridMap doit être le parent des entités possédant un GridBody. Le moteur résout toutes les collisions au sein d’un même GridMap de manière indépendante, ce qui signifie que vous pouvez faire fonctionner plusieurs GridMaps différents dans le même monde sans qu’ils n’interagissent entre eux.
level = world.spawn(
map=GridMap(rows=20, columns=20, size=(16, 16), image="tileset")
)
player = world.spawn(
parent=level,
body=GridBody(pos=(32, 32), size=(16, 16), tag=1, mask=(2,))
)
Position de l’entity
La position de l’entity (x, y) est automatiquement dérivée de la résolution de collision du GridMap. Lorsque le moteur résout le mouvement d’un body, il met à jour le transform de l’entity pour correspondre à la position résolue du body. Vous ne définissez pas x/y manuellement sur les entités possédant un GridBody — c’est le système de collision qui contrôle leur position.
Déplacer les bodies
Pour déplacer une entity possédant un body, définissez la propriété move du body. Le moteur tentera le déplacement et résoudra les collisions :
def update():
player.body.move = (0, 0)
if input.keyboard.right.down:
player.body.move = (2, 0)
Le moteur déplace le body, vérifie les collisions et ajuste la position finale.
Tags et masks
Les tags et masks contrôlent quels bodies peuvent entrer en collision entre eux.
- Tag — un nombre qui identifie ce qu’est ce body (par ex. 1 = joueur, 2 = ennemi, 3 = mur)
- Mask — quels tags ce body doit détecter pour la collision
Lorsqu’un body en mouvement rencontre un autre body ou une tile dont le tag est dans son mask, il glisse contre lui au lieu de le traverser. Cela vous offre une collision solide avec un mouvement fluide le long des murs et des obstacles.
player = world.spawn(
parent=level,
body=GridBody(pos=(0, 0), size=(16, 16), tag=1, mask=(2, 3))
)
enemy = world.spawn(
parent=level,
body=GridBody(pos=(0, 0), size=(16, 16), tag=2, mask=(1,))
)
Le joueur entre en collision avec les tags 2 et 3 (ennemis et murs). L’ennemi entre en collision avec le tag 1 (le joueur). Les bodies avec le tag 0 ou sans mask correspondant se traversent mutuellement.
Callbacks de collision
Lorsqu’un body touche une tile, le moteur appelle on_hit_tile :
def on_hit_tile(entity, tile):
# l'entity a touché une tile solide
pass
Lorsque deux bodies se chevauchent, le moteur appelle on_hit_body :
def on_hit_body(entity, other):
if entity == player:
entity.health.value -= 1
Ces fonctions s’exécutent durant l’étape de collision, après update() et avant le rendu.
Collision avec la tilemap
Un GridMap définit une grille de tiles, et les tiles peuvent être marquées comme solides à l’aide de tags de tiles :
level.map.set(row=0, column=5, tile=(1, 0), tag=2)
Tout body dont le mask inclut ce tag glissera contre la tile.
Fonctionnement
Le système de collision est basé sur une grille, pas sur le pixel. Les bodies sont des rectangles alignés sur les axes qui se déplacent à l’intérieur de la grille. Les simulations sont isolées par GridMap — chaque entity GridMap exécute sa propre résolution de collision indépendante. Cela rend la collision :
- Déterministe — les mêmes entrées produisent toujours les mêmes collisions
- Rapide — les recherches sur la grille se font en temps constant
- Prévisible — pas de cas limites liés aux nombres flottants
- Isolée — plusieurs GridMaps n’interfèrent pas entre eux