Formas

Rect, Triangle, Circle, Line y Polyline son componentes de forma. Le das uno a una entidad al crearla, y la entidad dibuja esa forma en cada fotograma hasta que la destruyes.

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))

Una forma es una entidad real, así que se le aplica todo lo que pueden hacer las entidades: muévela con entity.x y entity.y, gírala con entity.rotation, dale un padre, anímala con un tween, ponla en una capa, ocúltala con entity.visible.


¿Formas o draw?

Pyxen ofrece las mismas cinco primitivas dos veces. En pantalla son idénticas y solo se diferencian por su duración. Consulta draw para la otra mitad.

Componente de formadraw
DuraciónVive hasta que destruyes la entidadUn fotograma
PosiciónPosición, rotación y escala de la entidadCoordenadas de mundo que tú pasas
CosteUna entidad completa: transform, capa, almacenamiento de componentesUnos pocos quads en el búfer del fotograma
Útil paraObjetos del juego: naves, muros, interfaz fijaGeometría procedural, depuración en pantalla, barras de interfaz, estelas

Usa una forma cuando la cosa es algo de tu juego. Usa draw cuando estés pintando la imagen de algo que ya controlas por tu cuenta.


Tres trampas habituales

Una forma se fija al crearla y después no se puede cambiar. No existe entity.shape: leerlo lanza ValueError: component schema does not exist. Esto es distinto de sprite y text, que sí son asignables. Para cambiar una forma, destruye la entidad y crea otra.

entity.color no tiñe una forma. Funciona con los sprites; una forma se dibuja con sus propios fill y stroke y lo ignora. Define el color en la propia forma.

El grosor del contorno tiene dos nombres. Rect, Triangle y Circle usan stroke_width; Line y Polyline usan width. Significan lo mismo.


Colores

Cada argumento de color acepta una tupla (r, g, b, a) con componentes de 0.0 a 1.0, o un Color.

Rect(40, 20, fill=(1, 0, 0, 1))        # rojo opaco
Rect(40, 20, fill=(1, 0, 0, 0.35))     # rojo al 35 %

Una forma sin fill ni stroke no dibuja nada. Ambos empiezan totalmente transparentes, así que Rect(40, 40) es una entidad válida e invisible: la sorpresa más frecuente aquí. Puedes pasar los dos para obtener una forma rellena con contorno.


Tipos

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

Un rectángulo.

ArgumentoTipoDescripción
width, heightfloatTamaño en píxeles.
filltuplaColor interior. Omítelo para no rellenar.
stroketuplaColor del contorno. Omítelo para no trazarlo.
stroke_widthfloatGrosor del contorno. Vale 1 por defecto.
pivottuplaEl punto al que se refiere la posición de la entidad, en píxeles de la forma. Por defecto la esquina; (width/2, height/2) lo centra.

Rect es la única forma con pivot, y es además el punto sobre el que gira la rotación.

def start():
    world.spawn(x=110, y=90, shape=Rect(48, 32, fill=(0.4, 0.7, 1.0, 1.0)))
    # Centrado en su propia posición, así que la rotación gira en el sitio.
    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 triángulo que pasa por tres puntos, dados en relación a la posición de la entidad.

ArgumentoTipoDescripción
x1, y1, x2, y2, x3, y3floatLos tres vértices, como desplazamiento desde la entidad.
filltuplaColor interior. Omítelo para no rellenar.
stroketuplaColor del contorno. Omítelo para no trazarlo.
stroke_widthfloatGrosor del contorno.
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 círculo centrado en la entidad.

ArgumentoTipoDescripción
radiusfloatRadio en píxeles.
filltuplaColor interior. Omítelo para no rellenar.
stroketuplaColor del contorno. Omítelo para no trazarlo.
stroke_widthfloatGrosor del contorno.
segmentsintSegmentos rectos que aproximan la curva. Vale 12 por defecto.

Un círculo es en realidad un polígono. Doce segmentos ya parecen redondos en tamaños pequeños; súbelo para círculos grandes y bájalo a propósito cuando quieras un polígono visible: segments=6 es un hexágono.

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)

Una línea recta entre dos puntos, en relación a la entidad.

ArgumentoTipoDescripción
x1, y1floatInicio, como desplazamiento desde la entidad.
x2, y2floatFinal.
stroketuplaColor de la línea.
widthfloatGrosor de la línea. Ojo: width, no 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)

Una serie de segmentos unidos.

ArgumentoTipoDescripción
pointstupla o FloatBufferSecuencia plana (x1, y1, x2, y2, …), no una lista de pares.
stroketuplaColor de la línea.
widthfloatGrosor de la línea. Ojo: width, no stroke_width.
closedboolSi es True, une el último punto con el primero.
filltuplaRellena el área encerrada. Sobre todo útil con closed=True.

Los puntos van planos a propósito: es la forma que ya tiene un FloatBuffer, de modo que un trazado calculado una vez puede pasarse tal cual a Polyline sin reconstruirlo.

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