Python Turtle Graphics Game – Arachnophobia

Here’s a fun game written with Python Turtle Graphics. It’s called Arachnophobia, and is basically a spider version of Whack-a-Mole.

Please note spiders are mostly innocent and do not deserve to die just because you may be afraid of them. No spiders were harmed in the production of this game.

You can play the game online at this repl.it. The goal is to use the mouse to click on spiders as they appear. However, this is where we run into some of the limitations of browser-based Python programming, as the fastest time the online version can handle is 1000 ms between “frames” (You’ll see what I mean if you play it…)

Browser Based Version of Arachnophobia Python Turtle Graphics Game

Arachnophobia Python Turtle Graphics Game

You will find that running the game on a desktop or laptop will give you a much better experience. For one, you can change the speed by adjusting the SPEED constant (try 500, as in 500 ms between frames). Also, if you install playsound via pip install playsound, there is a fun sound effect every time you click on a spider.

Below is the code listing for the game. As usual, I strongly encourage you to type the code in for yourself, even if there are parts you don’t understand. But if that seems like a drag, just paste it into a new file for now and save and run.

I will explain some of the details after the listing, but please note that even though we are using a module which some people consider to be for beginners at programming, there are some fairly advanced techniques used, and many of the choices I have made are the result of a considerable amount of experience writing these kinds of games.

If you want to learn more about how to write games using Python, why not get in touch using the details on our contact page for further information or to book a free 1/2 hour no-obligation lesson? 

Here’s is the listing:

You will need to download the spider image and save it the same folder as the program, naming it spider.gif (right-click, save image as).

import turtle
import random

try:
    import playsound  # Not part of standard Library.

    SOUND = True
except ImportError:
    SOUND = False

WIDTH = 800
HEIGHT = 400
CURSOR_SIZE = 20
SQUARE_SIZE = 50
NUM_ROWS = 5
NUM_COLS = 5
BG_COLOR = "yellow"
TITLE = "Arachnophobia"
COLORS = ("red", "black")
SPEED = 500
NUM_TRIES = 20


def init_screen():
    screen = turtle.Screen()
    screen.title(TITLE)
    screen.setup(WIDTH, HEIGHT)
    canvas = screen.getcanvas()
    return screen, canvas


def create_board():
    board = []
    for i in range(NUM_ROWS):
        for j in range(NUM_COLS):
            tur = turtle.Turtle(shape="square")
            tur.setheading(90)
            board.append(tur)
            tur.penup()
            tur.shapesize(SQUARE_SIZE / CURSOR_SIZE)
            tur.color(COLORS[0] if i % 2 == j % 2 else COLORS[1])
            tur.onclick(lambda x, y, tur=tur: click(tur))
            x = -NUM_COLS / 2 * SQUARE_SIZE + j * SQUARE_SIZE + SQUARE_SIZE / 2
            y = NUM_ROWS / 2 * SQUARE_SIZE - i * SQUARE_SIZE - SQUARE_SIZE / 2
            tur.goto(x, y)
    return board


def click(tur):
    global score, high_score  # These values are modified within this function.
    if board.index(tur) == spider_pos:
        if SOUND:
            playsound.playsound("ouch2.mp3", False)
        score += 1
        if score > high_score:
            high_score = score
        update_score()


def toggle_turtle(tur):
    if tur.shape() == "square":
        tur.shape("spider.gif")
    else:
        tur.shape("square")
    # Turtles lose their onclick binding when image is used, so we have to rebind.
    tur.onclick(lambda x, y, tur=tur: click(tur))
    screen.update()


def update_score():
    pen.clear()
    pen.write(f"Score: {score}    High Score: {high_score}", font=("Arial", 16, "bold"))


def reset():
    global spider_pos, pen, score, high_score, board, counter

    # Reset screen
    screen.clear()
    screen.bgcolor(BG_COLOR)
    screen.register_shape("spider.gif")
    screen.tracer(0)  # Disable animation

    # Initialise board
    board = create_board()
    spider_pos = 0
    toggle_turtle(board[spider_pos])

    # Score
    score = 0
    pen = turtle.Turtle()
    pen.hideturtle()
    pen.penup()
    pen.goto(-119, -160)
    update_score()

    # Let's go
    counter = 0
    screen.update()
    game_loop()


def game_over():
    pen.goto(-80, -20)
    pen.color("white")
    pen.write("Game Over", font=("Arial", 24, "bold"))


def game_loop():
    global spider_pos, counter  # These values are modified within this function.
    toggle_turtle(board[spider_pos])
    spider_pos = random.randrange(NUM_ROWS * NUM_COLS)
    toggle_turtle(board[spider_pos])
    counter += 1
    if counter > NUM_TRIES:
        spider_pos = -999  # Avoid clicking in between rounds
        game_over()
        canvas.after(2000, reset)
        return  # Very important to ensure loop is not called again.
    screen.ontimer(game_loop, SPEED)


if __name__ == "__main__":
    screen, canvas = init_screen()
    high_score = 0
    reset()
    turtle.done()

Some observations about the above code:

  • Constants are used to avoid “magic numbers” scattered throughout the program
  • The board is based on the concept of a 2d grid of individual turtle objects.
  • The turtle objects have a click-handler attached, but all click events are handled by one function due to the use of the lambda expression (this is a fairly advanced technique).
  • The board is created using a nested FOR loop. See link for more info.
  • If you are concerned about the use of global variables, please read this article
  • It is a good idea to clear the screen on reset, otherwise there can be an unseen accumulation of stray turtle objects existing in memory which can cause the program to slow down as you play multiple rounds.

That’s it for now. As I said above, writing this kind of game is non-trivial, especially if you want to be able to do it entirely independently eventually. If you have any questions, go ahead and ask either in a comment or by email and I’ll get back to you with an answer.

Happy computing!

Sharing is caring!

Leave a Reply

Your email address will not be published. Required fields are marked *