Formes

Rect, Triangle, Circle, Line et Polyline sont des composants de forme. Vous en donnez un à une entité au moment de la créer, et l’entité dessine cette forme à chaque frame jusqu’à ce que vous la détruisiez.

from pyxen import *

def start():
    world.spawn(x=110, y=90, shape=Rect(48, 32, fill=(0.4, 0.7, 1.0, 1.0)))
    world.spawn(x=210, y=90, shape=Circle(24, stroke=(1.0, 0.6, 0.3, 1.0), stroke_width=2))

Une forme est une véritable entité : tout ce que les entités savent faire s’applique. Déplacez-la avec entity.x et entity.y, faites-la tourner avec entity.rotation, donnez-lui un parent, animez-la avec un tween, placez-la sur un calque, masquez-la avec entity.visible.


Formes ou draw ?

Pyxen propose les mêmes cinq primitives deux fois. Elles sont identiques à l’écran et ne diffèrent que par leur durée de vie. Voir draw pour l’autre moitié.

Composant de formedraw
Durée de vieExiste jusqu’à la destruction de l’entitéUne frame
PositionPosition, rotation et échelle de l’entitéCoordonnées monde que vous passez
CoûtUne entité complète : transform, calque, stockage de composantsQuelques quads dans le tampon de frame
Utile pourLes objets du jeu — vaisseaux, murs, interface fixeGéométrie procédurale, affichage de débogage, barres d’interface, traînées

Choisissez une forme quand la chose est un élément de votre jeu. Choisissez draw quand vous peignez l’image de quelque chose que vous suivez déjà vous-même.


Trois pièges classiques

Une forme est définie à la création et ne peut plus changer ensuite. Il n’existe pas de entity.shape — le lire lève ValueError: component schema does not exist. C’est différent de sprite et text, qui, eux, sont modifiables. Pour changer une forme, détruisez l’entité et créez-en une nouvelle.

entity.color ne teinte pas une forme. Cela fonctionne pour les sprites ; une forme se dessine avec ses propres fill et stroke et l’ignore. Définissez la couleur sur la forme elle-même.

L’épaisseur du contour porte deux noms. Rect, Triangle et Circle prennent stroke_width ; Line et Polyline prennent width. Les deux désignent la même chose.


Couleurs

Chaque argument de couleur accepte un tuple (r, g, b, a) dont les composantes vont de 0.0 à 1.0, ou un Color.

Rect(40, 20, fill=(1, 0, 0, 1))        # rouge opaque
Rect(40, 20, fill=(1, 0, 0, 0.35))     # rouge à 35 %

Une forme sans fill ni stroke ne dessine rien. Les deux démarrent entièrement transparents : Rect(40, 40) est donc une entité valide et invisible — c’est la surprise la plus fréquente ici. Vous pouvez passer les deux pour obtenir une forme pleine avec un contour.


Types

Rect(width, height, fill=None, stroke=None, stroke_width=1, pivot=None)

Un rectangle.

ArgumentTypeDescription
width, heightfloatTaille en pixels.
filltupleCouleur intérieure. Omettez pour ne pas remplir.
stroketupleCouleur du contour. Omettez pour ne pas en tracer.
stroke_widthfloatÉpaisseur du contour. Vaut 1 par défaut.
pivottupleLe point auquel se rapporte la position de l’entité, en pixels de la forme. Par défaut le coin ; (width/2, height/2) le centre.

Rect est la seule forme dotée d’un pivot — c’est aussi le point autour duquel la rotation s’effectue.

def start():
    world.spawn(x=110, y=90, shape=Rect(48, 32, fill=(0.4, 0.7, 1.0, 1.0)))
    # Centré sur sa propre position : la rotation se fait sur place.
    world.spawn(name="spinner", x=210, y=90,
                shape=Rect(48, 32, stroke=(1.0, 0.6, 0.3, 1.0), stroke_width=2,
                           pivot=(24, 16)))

def update():
    world.get(name="spinner").rotation += 0.02

Triangle(x1, y1, x2, y2, x3, y3, fill=None, stroke=None, stroke_width=1)

Un triangle passant par trois points, donnés relativement à la position de l’entité.

ArgumentTypeDescription
x1, y1, x2, y2, x3, y3floatLes trois sommets, en décalage par rapport à l’entité.
filltupleCouleur intérieure. Omettez pour ne pas remplir.
stroketupleCouleur du contour. Omettez pour ne pas en tracer.
stroke_widthfloatÉpaisseur du contour.
world.spawn(x=160, y=90, shape=Triangle(0, -20, 18, 14, -18, 14, fill=(1, 1, 0.3, 1)))

Circle(radius, fill=None, stroke=None, stroke_width=1, segments=12)

Un cercle centré sur l’entité.

ArgumentTypeDescription
radiusfloatRayon en pixels.
filltupleCouleur intérieure. Omettez pour ne pas remplir.
stroketupleCouleur du contour. Omettez pour ne pas en tracer.
stroke_widthfloatÉpaisseur du contour.
segmentsintNombre de segments droits approximant la courbe. Vaut 12 par défaut.

Un cercle est en réalité un polygone. Douze segments suffisent à paraître rond en petite taille ; augmentez la valeur pour les grands cercles, et baissez-la volontairement quand vous voulez un polygone visible — segments=6 donne un hexagone.

world.spawn(x=110, y=90, shape=Circle(28, fill=(0.5, 1.0, 0.7, 1.0), segments=6))
world.spawn(x=210, y=90, shape=Circle(28, fill=(1.0, 0.5, 0.7, 1.0), segments=32))

Line(x1, y1, x2, y2, stroke=None, width=1)

Une ligne droite entre deux points, relativement à l’entité.

ArgumentTypeDescription
x1, y1floatDépart, en décalage par rapport à l’entité.
x2, y2floatArrivée.
stroketupleCouleur du trait.
widthfloatÉpaisseur du trait. Attention : width, et non stroke_width.
world.spawn(x=60, y=90, shape=Line(0, 0, 80, -40, stroke=(0.3, 1, 0.5, 1), width=2))

Polyline(points, stroke=None, width=1, closed=False, fill=None)

Une suite de segments reliés entre eux.

ArgumentTypeDescription
pointstuple ou FloatBufferSéquence à plat (x1, y1, x2, y2, …) — pas une liste de paires.
stroketupleCouleur du trait.
widthfloatÉpaisseur du trait. Attention : width, et non stroke_width.
closedboolSi True, relie le dernier point au premier.
filltupleRemplit la zone délimitée. Surtout utile avec closed=True.

Les points sont à plat volontairement : c’est déjà la forme d’un FloatBuffer, si bien qu’un tracé calculé une fois peut être passé tel quel à Polyline sans le reconstruire.

world.spawn(x=250, y=90,
            shape=Polyline((0, 0, 30, -25, 60, 0), stroke=(1, 0.9, 0.2, 1), width=3))