pyxen.draw

The draw module draws shapes straight to the screen for one frame. Call it from update(); whatever you draw is cleared at the end of the frame, so you draw it again next frame or it disappears.

from pyxen import *

def update():
    draw.circle(64, 64, 20, fill=(1, 0.2, 0.3, 1))
    draw.line(0, 0, 128, 128, color=(1, 1, 1, 1))

Nothing is spawned and nothing persists — there is no entity to keep a handle on and nothing to destroy.


draw or a Shape component?

Pyxen gives you the same primitives twice. They look identical on screen and differ only in lifetime.

Shape componentdraw
LifetimeLives until you destroy the entityOne frame
PositionEntity position, rotation, scaleWorld coordinates you pass in
CostA full entity: transform, layer, component storageA few quads in the frame buffer
Good forGame objects — ships, walls, UI that stays putProcedural geometry, debug overlays, HUD bars, trails

Reach for a Shape when the thing is something in your game. Reach for draw when you are painting a picture of something you already track yourself.


Colours

Every colour argument takes an (r, g, b, a) tuple with components from 0.0 to 1.0, or a Color.

draw.rect(10, 10, 40, 20, fill=(1, 0, 0, 1))        # opaque red
draw.rect(10, 40, 40, 20, fill=(1, 0, 0, 0.35))     # 35% red

The filled shapes draw nothing by default. draw.rect, draw.triangle and draw.circle start with both fill and stroke fully transparent, so a call that passes neither is invisible — that is the single most common surprise with this module. draw.line and draw.polyline default to opaque white instead, so they always show up.


Functions

draw.line(x1, y1, x2, y2, color=(1,1,1,1), width=1)

A straight line between two points.

ArgumentTypeDescription
x1, y1floatStart point, in world coordinates.
x2, y2floatEnd point.
colortupleLine colour. Defaults to opaque white.
widthfloatLine thickness in pixels. Defaults to 1.
def update():
    draw.line(0, 64, 128, 64, color=(0.3, 1, 0.5, 1), width=2)

draw.polyline(points, color=(1,1,1,1), width=1, closed=False)

A run of connected line segments.

ArgumentTypeDescription
pointstuple or FloatBufferFlat sequence (x1, y1, x2, y2, …) — not a list of pairs.
colortupleLine colour. Defaults to opaque white.
widthfloatLine thickness in pixels.
closedboolWhen True, joins the last point back to the first.
def update():
    draw.polyline((10, 10, 40, 60, 80, 20, 110, 70),
                  color=(1, 0.8, 0.2, 1), width=2)

Points are flat on purpose: it is the shape a FloatBuffer already has, so a path you compute once can be handed straight to draw.polyline every frame without rebuilding it.


draw.rect(x, y, width, height, fill=None, stroke=None, stroke_width=1)

An axis-aligned rectangle. x, y is its corner, not its centre.

ArgumentTypeDescription
x, yfloatCorner position.
width, heightfloatSize in pixels.
filltupleInterior colour. Omit for no fill.
stroketupleOutline colour. Omit for no outline.
stroke_widthfloatOutline thickness. Defaults to 1.
def update():
    # A health bar: dark backing, bright fill, thin outline.
    draw.rect(4, 4, 60, 6, fill=(0.1, 0.1, 0.1, 1))
    draw.rect(4, 4, 60 * health / max_health, 6, fill=(0.2, 1, 0.4, 1))
    draw.rect(4, 4, 60, 6, stroke=(1, 1, 1, 0.5))

draw.triangle(x1, y1, x2, y2, x3, y3, fill=None, stroke=None, stroke_width=1)

A triangle through three points.

ArgumentTypeDescription
x1, y1, x2, y2, x3, y3floatThe three corners.
filltupleInterior colour. Omit for no fill.
stroketupleOutline colour. Omit for no outline.
stroke_widthfloatOutline thickness.
def update():
    draw.triangle(64, 20, 84, 60, 44, 60, fill=(1, 1, 0.3, 1))

draw.circle(x, y, radius, fill=None, stroke=None, stroke_width=1, segments=12)

A circle around a centre point.

ArgumentTypeDescription
x, yfloatCentre position.
radiusfloatRadius in pixels.
filltupleInterior colour. Omit for no fill.
stroketupleOutline colour. Omit for no outline.
stroke_widthfloatOutline thickness.
segmentsintStraight segments approximating the curve. Defaults to 12.

A circle is really a polygon. Twelve segments reads as round at small sizes; raise it for large circles and lower it when you want a visible polygon.

def update():
    draw.circle(64, 64, 24, fill=(0.2, 0.4, 1, 1), segments=32)
    draw.circle(64, 64, 30, stroke=(1, 1, 1, 0.4), segments=32)

Notes

  • draw calls belong in update(). Calling them from start() draws for a single frame and then vanishes.
  • Drawing happens in world coordinates, so the camera moves it. For a HUD that stays put, draw relative to camera or keep the HUD on an unmoved camera.
  • Everything drawn in a frame lands above the sprites drawn that frame.