Docs › game library

game.plot()

Stamp a dot that stays on the screen. It is the right tool whenever you want lots of marks: fractals, trails, paintings, starfields. A quarter of a million dots still runs at full speed.

How to write it

game.plot(x, y, color="#ffffff", size=2)
x, y
Where the dot goes, in game coordinates: x from the left, y from the top (y grows downward).
color
Any CSS colour: a name like "red", a hex code like "#22d3a5", or "rgb(255, 120, 0)". White if you leave it out.
size
How wide the dot is, in pixels. It is round. 1 is a fine grain, 2 (the default) is easy to see.

The dot appears at the next game.frame(), and then it stays until you rub it out with game.wipe() or game.fade().

A full example: the Sierpinski triangle

This is the "chaos game". Start anywhere, pick one of three corners at random, jump halfway towards it, plot a dot, repeat. Out of pure randomness, a perfect fractal appears:

import game
import random

game.window(480, 420, background="#0b1020")

corners = [(240, 20), (20, 400), (460, 400)]
colors = ["#ff4d6d", "#4dabf7", "#69db7c"]
x, y = 240, 200
dots = 0
board = game.label("Dots: 0", 70, 20, size=16, color="#ffffff")

while game.playing():
    for i in range(500):                  # 500 dots every frame
        c = random.randint(0, 2)
        cx, cy = corners[c]
        x = (x + cx) / 2                  # jump halfway to the corner
        y = (y + cy) / 2
        game.plot(x, y, colors[c], size=1)
    dots = dots + 500
    board.content = "Dots: " + str(dots)
    game.frame()

Why not just use sprites?

You could make every dot a game.sprite() or a game.circle(). It is perfectly good Python, and it works for the first few hundred. Then it slows down. Then it crawls.

That is because sprites are redrawn from scratch every frame. That's what lets you move them, spin them and check what they touch. With 5,000 sprites on screen, every single frame draws 5,000 things, even though none of them moved.

game.plot() is drawn once. The dot is stamped onto an ink layer under your sprites, and after that it is just pixels: it costs nothing to keep it there. So the 100th dot and the 100,000th dot are just as cheap.

The rule of thumb: if a thing needs to move, collide or be clicked, make it a sprite. If it just needs to be there, plot it.

The rest of the ink family

game.plot() has a few relatives that all draw on the same ink layer:

  • game.line(x1, y1, x2, y2, color, width=2) stamps a straight line. Use it for trails behind something fast: a dot every frame leaves gaps, a line from the old position to the new one doesn't.
  • game.fade(0.05) rubs out a little of the ink each time you call it, so trails die away like a comet tail. Call it once a frame.
  • game.wipe() rubs out all the ink at once and leaves the sprites alone.
  • game.save_image("ink") saves just the drawing as a PNG, with no score or sprites on top.
game.line(old_x, old_y, ship.x, ship.y, "#4ea8ff")   # a trail behind the ship
old_x, old_y = ship.x, ship.y
game.fade(0.03)                                       # that slowly fades away
game.frame()

Why isn't my dot showing?

  • There's no game.frame() after it. Dots are stamped when the frame is drawn. A program that plots and then ends without a frame shows nothing.
  • It's off the screen. Dots outside the window are drawn, but you can't see them. Print x and y to check.
  • It's the same colour as the background, or so small you can't see it. Try size=4 and "red" while testing.
  • A sprite is on top of it. Ink sits underneath every sprite and label.
  • Something calls game.wipe() or game.fade() every frame, so the dot is rubbed out as fast as it's drawn.