Building Ghost Chase

Play it first → Coins are scattered around the screen and Bean runs about with the arrow keys picking them up. Two ghosts drift after Bean the whole time. Grab every coin and you win. Let a ghost touch you and you lose.

This is how it was built, a step at a time. Every numbered step below is a whole program: copy it into the playground, press Run, and it works. Each step is the one before it with something added, so you can build the game the way it was built. Then break something on purpose and see what changes. That teaches you more than reading does.

It is the easiest game on the site, and it is written for someone who has done the first five Learn Python lessons and not the sixth. It uses variables, if, a for loop and a list, and nothing you have to write a function for. After it, try Bomb Dodge, which does need functions.

The one big idea: the @ lines are recipes

You will see blocks like this all through the game:

@onKeyDown("left")
def move_left():
    bean.move(-BEAN_SPEED, 0)

Read it as a sentence: while the left arrow is held down, do the indented lines. The @ line says when. The def line gives the block a name, ends with a colon, and that is all it does for now. The indented lines are what happens, and they are ordinary Python: variables, if, anything you know.

You don't need to understand def yet to use this, the same way you used print() long before you knew how it worked. Copy the shape, change the key or the name, and it works. When you get to Lesson 6 you will find out what def really is, and then Lesson 7 explains the @.

The other big idea is that kaypy does a lot of the work for you. Nothing in this game moves the ghosts: one word in their list, follow(), makes them chase Bean for ever. Nothing checks whether Bean is touching a coin, either: area() does that, and tells you when it happens.

Step 1 — Bean runs

from kaypy import *

kaypy(width=800, height=600, background=[40, 44, 70])

loadSprite("bean", "images/bean.png")

BEAN_SPEED = 260       # how fast Bean runs, in pixels per second

# anchor("center") means pos() is the middle of the picture.
bean = add([sprite("bean"), pos(center()), anchor("center"), area()])


@onKeyDown("left")
def move_left():
    bean.move(-BEAN_SPEED, 0)


@onKeyDown("right")
def move_right():
    bean.move(BEAN_SPEED, 0)


@onKeyDown("up")
def move_up():
    bean.move(0, -BEAN_SPEED)


@onKeyDown("down")
def move_down():
    bean.move(0, BEAN_SPEED)


# Holding the mouse down -- or a finger, on a phone -- runs Bean towards it.
@onMouseDown
def move_to_mouse():
    bean.moveTo(mousePos(), BEAN_SPEED)


# Every frame, put Bean back inside the window if it has gone past an
# edge. 32 is half of Bean's width, and 27 is half its height.
@onUpdate
def stay_on_screen():
    bean.pos.x = clamp(bean.pos.x, 32, width() - 32)
    bean.pos.y = clamp(bean.pos.y, 27, height() - 27)

Hold the arrow keys and Bean runs about. Hold two at once, like up and right, and Bean runs diagonally. Run into an edge and Bean stops there. Hold the mouse down somewhere and Bean runs towards it. On a phone, a finger does the same thing.

  • BEAN_SPEED = 260 is a variable, and it is in capitals because it is a setting: something you set once at the top and might want to change. It is used four times below, so changing it here changes all four.
  • pos(center()) puts Bean in the middle of the window, and anchor("center") means pos() is the middle of the picture, rather than its top-left corner. area() gives Bean a collision box. Nothing bumps into Bean yet, but by step 3 the coins will.
  • @onKeyDown("left") runs the lines under it every frame the left arrow is held down, about sixty times a second, so Bean keeps running until you let go.
  • bean.move(-BEAN_SPEED, 0) moves Bean left at BEAN_SPEED pixels per second. The first number is across (minus is left) and the second is down (minus is up). kaypy works out how far that is for one frame, so Bean runs at the same speed on a fast computer and a slow one.
  • @onMouseDown runs the lines under it every frame the mouse button is held, or a finger is on the screen. bean.moveTo(mousePos(), BEAN_SPEED) moves Bean towards wherever the mouse is, at the same speed as the arrow keys, and stops when it gets there.
  • @onUpdate runs the lines under it every single frame, whatever is happening.

stay_on_screen stops Bean at the edges. clamp(bean.pos.x, 32, width() - 32) gives back bean.pos.x, unless it is less than 32 (then it gives 32) or more than 768 (then it gives 768). Putting that back into bean.pos.x means Bean can never be further left than 32 or further right than 768. Bean is 64 pixels wide, so 32 is half of Bean, and Bean stops with its side touching the edge. The second line does the same for up and down: Bean is 54 pixels tall, and half of that is 27.

Two things to break.

Delete the @onUpdate line above stay_on_screen and hold left. There's no error message. Bean runs off the edge of the window and keeps going: three seconds of holding left took it to x = −385. Without the @ line, kaypy is never told to run those lines, so they never do.

Write @onKeyDown without the ("left"). There's no error message either, and the left arrow does nothing at all. kaypy needs to be told which key; without it, the block is never connected to the keyboard.

Step 2 — coins

Twenty coins appear in random places. Run it a few times: they are somewhere different every time.

from kaypy import *

kaypy(width=800, height=600, background=[40, 44, 70])

loadSprite("bean", "images/bean.png")
loadSprite("coin", "images/coin.png")

BEAN_SPEED = 260       # how fast Bean runs, in pixels per second
COINS = 20             # how many coins there are to grab

# anchor("center") means pos() is the middle of the picture.
bean = add([sprite("bean"), pos(center()), anchor("center"), area()])


@onKeyDown("left")
def move_left():
    bean.move(-BEAN_SPEED, 0)


@onKeyDown("right")
def move_right():
    bean.move(BEAN_SPEED, 0)


@onKeyDown("up")
def move_up():
    bean.move(0, -BEAN_SPEED)


@onKeyDown("down")
def move_down():
    bean.move(0, BEAN_SPEED)


# Holding the mouse down -- or a finger, on a phone -- runs Bean towards it.
@onMouseDown
def move_to_mouse():
    bean.moveTo(mousePos(), BEAN_SPEED)


# Every frame, put Bean back inside the window if it has gone past an
# edge. 32 is half of Bean's width, and 27 is half its height.
@onUpdate
def stay_on_screen():
    bean.pos.x = clamp(bean.pos.x, 32, width() - 32)
    bean.pos.y = clamp(bean.pos.y, 27, height() - 27)


# A for loop puts COINS coins in random places. rand() picks a number
# between the two you give it. The top 80 pixels are left for the words.
for i in range(COINS):
    x = rand(40, width() - 40)
    y = rand(100, height() - 40)
    add([sprite("coin"), pos(x, y), anchor("center"), area(), "coin"])
  • for i in range(COINS): runs the indented lines COINS times, which is 20. That is the whole reason there are twenty coins and not one.
  • rand(40, width() - 40) picks a random number between 40 and 760, so every time round the loop, x is somewhere new across the window. y starts at 100 rather than 40, to leave the top of the window clear for the words in step 3.
  • "coin" at the end of the list is a tag: a label stuck on the coin. It doesn't change how the coin looks. It is how, in step 3, we will ask "is Bean touching a coin?" and "how many coins are left?"

Walk Bean over a coin. Nothing happens yet. That's the next step.

Break it. Take the four spaces off the front of the add(...) line, so it is no longer inside the loop. There's no error message. The loop still runs twenty times, picking twenty xs and twenty ys, but only the last one is used: the add runs once, after the loop has finished, and there is one coin. In Python the indent is what says which lines are inside the loop.

Step 3 — grabbing coins

Now Bean picks up any coin it touches, with a beep, and the words at the top count down how many are left.

from kaypy import *

kaypy(width=800, height=600, background=[40, 44, 70])

loadSprite("bean", "images/bean.png")
loadSprite("coin", "images/coin.png")
loadSound("beep", "sounds/small_beep.wav")

BEAN_SPEED = 260       # how fast Bean runs, in pixels per second
COINS = 20             # how many coins there are to grab

# anchor("center") means pos() is the middle of the picture.
bean = add([sprite("bean"), pos(center()), anchor("center"), area()])


@onKeyDown("left")
def move_left():
    bean.move(-BEAN_SPEED, 0)


@onKeyDown("right")
def move_right():
    bean.move(BEAN_SPEED, 0)


@onKeyDown("up")
def move_up():
    bean.move(0, -BEAN_SPEED)


@onKeyDown("down")
def move_down():
    bean.move(0, BEAN_SPEED)


# Holding the mouse down -- or a finger, on a phone -- runs Bean towards it.
@onMouseDown
def move_to_mouse():
    bean.moveTo(mousePos(), BEAN_SPEED)


# Every frame, put Bean back inside the window if it has gone past an
# edge. 32 is half of Bean's width, and 27 is half its height.
@onUpdate
def stay_on_screen():
    bean.pos.x = clamp(bean.pos.x, 32, width() - 32)
    bean.pos.y = clamp(bean.pos.y, 27, height() - 27)


# A for loop puts COINS coins in random places. rand() picks a number
# between the two you give it. The top 80 pixels are left for the words.
for i in range(COINS):
    x = rand(40, width() - 40)
    y = rand(100, height() - 40)
    add([sprite("coin"), pos(x, y), anchor("center"), area(), "coin"])

label = add([text("Coins left: " + str(COINS), size=28),
             pos(width() / 2, 30), anchor("center"), z(10)])


# This runs when Bean touches anything tagged "coin", and the coin it
# touched is handed in as `coin`.
@bean.onCollide("coin")
def grab(coin):
    coin.destroy()
    play("beep")

    # get("coin") is a list of every coin still in the game.
    coins_left = len(get("coin"))
    label.text = "Coins left: " + str(coins_left)
  • label = add([text(...), ...]) puts words on the screen and keeps hold of them in a variable, so we can change them later. z(10) draws them in front of everything else.
  • @bean.onCollide("coin") runs the lines under it the moment Bean touches anything tagged "coin". Both Bean and the coin need area() for that to work.
  • def grab(coin): has something between its brackets. That is how kaypy hands you the coin Bean touched: inside the block, coin is that one coin and no other. coin.destroy() takes it out of the game.
  • get("coin") gives back a list of every coin still in the game, and len() tells you how long a list is. So len(get("coin")) is how many coins are left. The coin we just destroyed is not in it any more.
  • label.text = ... changes the words on the screen. str() turns the number into text, because you can only + text to text.

Every so often a coin lands right where Bean starts. Bean is touching it from the very first frame, so it goes straight away, with a beep, and the count starts at 19. That isn't a mistake in your code: it's the game doing exactly what you told it.

Two things to break.

Take the str() off, so the line is "Coins left: " + coins_left. The game starts as normal, and the moment Bean touches a coin it stops with TypeError: can only concatenate str (not "int") to str. "Can only concatenate str" means "you can only + text to text", and coins_left is a number.

Take area() out of the coin's list. There's no error message, and Bean walks straight over every coin. A coin without area() has no collision box, so as far as kaypy knows nothing is ever touching it. This is the commonest reason a collision "doesn't work".

Step 4 — winning

Three lines, at the end of grab: when the last coin goes, you've won.

from kaypy import *

kaypy(width=800, height=600, background=[40, 44, 70])

loadSprite("bean", "images/bean.png")
loadSprite("coin", "images/coin.png")
loadSound("beep", "sounds/small_beep.wav")
loadSound("win", "sounds/rising_beep.wav")

BEAN_SPEED = 260       # how fast Bean runs, in pixels per second
COINS = 20             # how many coins there are to grab

# anchor("center") means pos() is the middle of the picture.
bean = add([sprite("bean"), pos(center()), anchor("center"), area()])


@onKeyDown("left")
def move_left():
    bean.move(-BEAN_SPEED, 0)


@onKeyDown("right")
def move_right():
    bean.move(BEAN_SPEED, 0)


@onKeyDown("up")
def move_up():
    bean.move(0, -BEAN_SPEED)


@onKeyDown("down")
def move_down():
    bean.move(0, BEAN_SPEED)


# Holding the mouse down -- or a finger, on a phone -- runs Bean towards it.
@onMouseDown
def move_to_mouse():
    bean.moveTo(mousePos(), BEAN_SPEED)


# Every frame, put Bean back inside the window if it has gone past an
# edge. 32 is half of Bean's width, and 27 is half its height.
@onUpdate
def stay_on_screen():
    bean.pos.x = clamp(bean.pos.x, 32, width() - 32)
    bean.pos.y = clamp(bean.pos.y, 27, height() - 27)


# A for loop puts COINS coins in random places. rand() picks a number
# between the two you give it. The top 80 pixels are left for the words.
for i in range(COINS):
    x = rand(40, width() - 40)
    y = rand(100, height() - 40)
    add([sprite("coin"), pos(x, y), anchor("center"), area(), "coin"])

label = add([text("Coins left: " + str(COINS), size=28),
             pos(width() / 2, 30), anchor("center"), z(10)])


# This runs when Bean touches anything tagged "coin", and the coin it
# touched is handed in as `coin`.
@bean.onCollide("coin")
def grab(coin):
    coin.destroy()
    play("beep")

    # get("coin") is a list of every coin still in the game.
    coins_left = len(get("coin"))
    label.text = "Coins left: " + str(coins_left)

    if coins_left == 0:
        play("win")
        label.text = "You got them all!"
  • if coins_left == 0: is indented to line up with the lines above it, so it is part of grab. It is asked every time a coin is grabbed, and it is only true once: when that was the last one.
  • == asks whether two things are equal. A single = stores something in a variable. They are easy to mix up.
  • The new label.text replaces the "Coins left: 0" that was put there two lines earlier, so you never see that.

Break it. Write if coins_left = 0:, with one =. Nothing runs at all: Python reads the whole program before it starts, and stops on that line with SyntaxError: invalid syntax. Maybe you meant '==' or ':=' instead of '='? The error is right. You did mean ==.

Step 5 — a ghost

A ghost starts in the top-left corner and drifts after Bean. If it touches Bean, Bean explodes and the game is over. Stand still and see how long it takes: about three and a half seconds.

from kaypy import *

kaypy(width=800, height=600, background=[40, 44, 70])

loadSprite("bean", "images/bean.png")
loadSprite("coin", "images/coin.png")
loadSprite("ghosty", "images/ghosty.png")
loadSound("beep", "sounds/small_beep.wav")
loadSound("boom", "sounds/small_boom.wav")
loadSound("win", "sounds/rising_beep.wav")

BEAN_SPEED = 260       # how fast Bean runs, in pixels per second
GHOST_SPEED = 100      # how fast the ghost chases -- try 200!
COINS = 20             # how many coins there are to grab

# anchor("center") means pos() is the middle of the picture.
bean = add([sprite("bean"), pos(center()), anchor("center"), area()])


@onKeyDown("left")
def move_left():
    bean.move(-BEAN_SPEED, 0)


@onKeyDown("right")
def move_right():
    bean.move(BEAN_SPEED, 0)


@onKeyDown("up")
def move_up():
    bean.move(0, -BEAN_SPEED)


@onKeyDown("down")
def move_down():
    bean.move(0, BEAN_SPEED)


# Holding the mouse down -- or a finger, on a phone -- runs Bean towards it.
@onMouseDown
def move_to_mouse():
    bean.moveTo(mousePos(), BEAN_SPEED)


# Every frame, put Bean back inside the window if it has gone past an
# edge. 32 is half of Bean's width, and 27 is half its height.
@onUpdate
def stay_on_screen():
    bean.pos.x = clamp(bean.pos.x, 32, width() - 32)
    bean.pos.y = clamp(bean.pos.y, 27, height() - 27)


# A for loop puts COINS coins in random places. rand() picks a number
# between the two you give it. The top 80 pixels are left for the words.
for i in range(COINS):
    x = rand(40, width() - 40)
    y = rand(100, height() - 40)
    add([sprite("coin"), pos(x, y), anchor("center"), area(), "coin"])

# follow(bean, speed=GHOST_SPEED) is the whole ghost: it moves itself
# towards Bean, every frame, for ever. No code of ours moves it.
add([sprite("ghosty"), pos(60, 60), anchor("center"), area(),
     follow(bean, speed=GHOST_SPEED), "ghost"])

label = add([text("Coins left: " + str(COINS), size=28),
             pos(width() / 2, 30), anchor("center"), z(10)])


# This runs when Bean touches anything tagged "coin", and the coin it
# touched is handed in as `coin`.
@bean.onCollide("coin")
def grab(coin):
    coin.destroy()
    play("beep")

    # get("coin") is a list of every coin still in the game.
    coins_left = len(get("coin"))
    label.text = "Coins left: " + str(coins_left)

    if coins_left == 0:
        play("win")
        destroyAll("ghost")
        label.text = "You got them all!"


@bean.onCollide("ghost")
def caught(ghost):
    play("boom")
    shake(12)
    addKaboom(bean.pos)
    bean.destroy()
    label.text = "Caught!"
  • follow(bean, speed=GHOST_SPEED) is the whole ghost. It moves the ghost towards Bean, at GHOST_SPEED pixels a second, every frame, for ever. There is no code of ours moving it, and that is why it is the easiest enemy there is.
  • Bean is faster than the ghost, 260 to 100, so you can always run away. The trouble is that the coins aren't always where the ghost isn't.
  • @bean.onCollide("ghost") is the same recipe as grabbing a coin, with a different tag. shake(12) shakes the screen, addKaboom(bean.pos) draws an explosion where Bean is, and bean.destroy() takes Bean out of the game. With nothing left to follow, the ghost stops where it is.
  • Winning now does one more thing: destroyAll("ghost") takes away every ghost, so one can't catch you after you've won.

Two things to break.

Leave the speed out: follow(bean). There's no error message, and you lose before you can press anything: caught after 0.08 seconds. Without a speed, follow() doesn't chase — it puts the ghost exactly where Bean is, every frame. That is what you would want for a name tag that hangs over a player, and not for a ghost.

Put quotes round it: follow("bean", speed=GHOST_SPEED). Nothing runs, and the message says what went wrong: TypeError: follow('bean') — follow() takes a game object to follow, the one add() gave back. "bean" is the name of a picture. bean, with no quotes, is the variable holding Bean itself.

Step 6 — the whole game

This is the game exactly as it is on the games page. It adds three things to step 5:

  • A second ghost, in the top-right corner. It is the same add line with a different pos.
  • SPACE plays again. This is the one big change. Every line that makes the game is now indented under @scene("game") and def game():, and the very last line is go("game"), which runs them. Pressing space runs go("game") again: kaypy throws away everything in the game — Bean, coins, ghosts, words, and the key handlers too — and runs the scene from the top, so you get new coins in new places. To do this to your own step 5, add the two scene lines above the bean = add(...) line, select everything from there to the end, and press Tab: the playground indents all of it at once.
  • A click plays again too, so a phone with no space bar can. But a click is also how you move Bean, so @onClick only starts again once the game is over: if not bean.exists() or len(get("coin")) == 0:. Caught means Bean has been destroyed, so bean.exists() is False; won means there are no coins left. While you're still playing, neither is true and the click just moves Bean.

It also has a note at the top saying how to play, the settings in one place, and comments that explain why each part is there. The COINS loop, len(get("coin")) and both onCollide blocks are exactly as they were.

"""Ghost Chase -- grab every coin before the ghosts grab you.

    arrow keys      move
    or hold the mouse (or a finger) where you want Bean to go
    SPACE           start again, or click once the game is over

The ghosts never stop coming, but Bean is faster than they are. Get every
coin and you win. Let a ghost touch you and you lose.

HOW THIS FILE IS PUT TOGETHER

    1. the window, the pictures and the sounds
    2. the settings
    3. the game: Bean, the coins, the ghosts, winning and losing
    4. start the game

This is the easiest game on the site. It uses variables, if, a for loop and
a list -- nothing you have to write a function for. The @ lines are recipes:
copy one, change the key or the tag, and it works.
"""

from kaypy import *

# ----------------------------------------------------------------- 1. setup

kaypy(width=800, height=600, background=[40, 44, 70])

loadSprite("bean", "images/bean.png")
loadSprite("coin", "images/coin.png")
loadSprite("ghosty", "images/ghosty.png")
loadSound("beep", "sounds/small_beep.wav")
loadSound("boom", "sounds/small_boom.wav")
loadSound("win", "sounds/rising_beep.wav")


# -------------------------------------------------------------- 2. settings
#
# Change one, press Run, and play it.

BEAN_SPEED = 260       # how fast Bean runs, in pixels per second
GHOST_SPEED = 100      # how fast the ghosts chase -- try 200!
COINS = 20             # how many coins there are to grab


# --------------------------------------------------------------- 3. the game
#
# Everything in the game is inside this scene, so that go("game") at the
# bottom can throw it all away and start again.

@scene("game")
def game():

    # ------------------------------------------------------------- Bean
    #
    # anchor("center") means pos() is the middle of the picture.

    bean = add([sprite("bean"), pos(center()), anchor("center"), area()])

    @onKeyDown("left")
    def move_left():
        bean.move(-BEAN_SPEED, 0)

    @onKeyDown("right")
    def move_right():
        bean.move(BEAN_SPEED, 0)

    @onKeyDown("up")
    def move_up():
        bean.move(0, -BEAN_SPEED)

    @onKeyDown("down")
    def move_down():
        bean.move(0, BEAN_SPEED)

    # Holding the mouse down -- or a finger, on a phone -- runs Bean
    # towards it.
    @onMouseDown
    def move_to_mouse():
        bean.moveTo(mousePos(), BEAN_SPEED)

    # Every frame, put Bean back inside the window if it has gone past an
    # edge. clamp(number, smallest, biggest) keeps a number between two
    # others. 32 is half of Bean's width, and 27 is half its height.
    @onUpdate
    def stay_on_screen():
        bean.pos.x = clamp(bean.pos.x, 32, width() - 32)
        bean.pos.y = clamp(bean.pos.y, 27, height() - 27)

    # ------------------------------------------------------------ coins
    #
    # A for loop puts COINS coins in random places. rand() picks a number
    # between the two you give it. The top 80 pixels are left for the words.

    for i in range(COINS):
        x = rand(40, width() - 40)
        y = rand(100, height() - 40)
        add([sprite("coin"), pos(x, y), anchor("center"), area(), "coin"])

    label = add([text("Coins left: " + str(COINS), size=28),
                 pos(width() / 2, 30), anchor("center"), z(10)])

    # ----------------------------------------------------------- ghosts
    #
    # follow(bean, speed=GHOST_SPEED) is the whole ghost: it moves itself
    # towards Bean, every frame, for ever. No code of ours moves it.

    add([sprite("ghosty"), pos(60, 60), anchor("center"), area(),
         follow(bean, speed=GHOST_SPEED), "ghost"])
    add([sprite("ghosty"), pos(width() - 60, 60), anchor("center"), area(),
         follow(bean, speed=GHOST_SPEED), "ghost"])

    # ---------------------------------------------------- grabbing a coin
    #
    # This runs when Bean touches anything tagged "coin", and the coin it
    # touched is handed in as `coin`.

    @bean.onCollide("coin")
    def grab(coin):
        coin.destroy()
        play("beep")

        # get("coin") is a list of every coin still in the game.
        coins_left = len(get("coin"))
        label.text = "Coins left: " + str(coins_left)

        if coins_left == 0:
            play("win")
            destroyAll("ghost")
            label.text = "You got them all! SPACE or click to play again"

    # -------------------------------------------------------- getting caught

    @bean.onCollide("ghost")
    def caught(ghost):
        play("boom")
        shake(12)
        addKaboom(bean.pos)
        bean.destroy()
        label.text = "Caught! SPACE or click to play again"

    # ------------------------------------------------------- play again
    #
    # go("game") throws everything away and runs the scene from the top.

    @onKeyPress("space")
    def play_again():
        go("game")

    # A click starts again too, but only once the game is over: Bean has
    # been caught (so Bean no longer exists), or there are no coins left.
    # Otherwise a click to move Bean would start a new game.
    @onClick
    def click_to_play_again():
        if not bean.exists() or len(get("coin")) == 0:
            go("game")


# ------------------------------------------------------- 4. start the game

go("game")

Two things to break.

Delete the last line, go("game"). There's no error message, and you get an empty window. @scene("game") only names the lines under it, ready for later; go("game") is what runs them.

Take the if out of click_to_play_again, so a click always runs go("game"). There's no error message, but you can't play with the mouse any more: the first click to move Bean throws the game away and starts a new one, with the coins somewhere else.

Make it yours

Open the whole game in the playground → It goes straight into the editor, ready to change and run.

  • Change the numbers. Make GHOST_SPEED 200 and the ghosts are nearly as fast as Bean. Make COINS 50 and there are coins everywhere.
  • A third ghost. Copy one of the ghost lines and give it a pos in a bottom corner, like pos(60, height() - 60). Don't put it too near the middle, or it catches Bean before you have pressed anything.
  • A faster ghost. Give one ghost speed=GHOST_SPEED * 2 and the other speed=GHOST_SPEED / 2, and they come at you at different times instead of bunching up into one.
  • Different pictures. Change "images/coin.png" to "images/apple.png", or the ghost to "images/bobo.png". Click Sprites in the playground to see what there is.