We will make a program where you can draw lines with the arrow keys. You can also press the 'P' key to lift your pen (stop drawing) or put it down (start drawing again). We will use the pygame
library for this.
We will make a program where you can draw lines with the arrow keys. You can also press the 'P' key to lift your pen (stop drawing) or put it down (start drawing again). We will use the pygame
library for this.
Let's check if your program is working. We do this by running a special test. Open your terminal and type this command:
pytest module-1.2/blueprint-PY-1.2-BP7/quest-50
What you will see:
test_drawing_on_move
test_pen_toggle_off_prevents_drawing
test_pen_toggle_on_again_resumes_drawing
test_quit_event_terminates_loop
These tests will show a red X because your code is not finished yet.
Open the main.py
file. You need to make the drawing tool move with the arrow keys and toggle drawing on and off with the 'P' key.
Here's how you can check for different events:
import pygame
# Inside your game loop:
for event in pygame.event.get():
if event.type == pygame.QUIT:
# This means the user wants to close the window
pass
elif event.type == pygame.KEYDOWN:
# This happens when you press a key down
if event.key == pygame.K_a:
print("You pressed the 'a' key!")
To make a variable switch between True
and False
:
my_switch = True
my_switch = not my_switch # my_switch becomes False
my_switch = not my_switch # my_switch becomes True again
print(my_switch)
To draw a line, you need a starting point and an ending point, a color, and a thickness:
import pygame
# ... setup code ...
line_color = (0, 0, 0) # Black
start_point = (10, 10)
end_point = (50, 50)
line_thickness = 2
pygame.draw.line(my_screen, line_color, start_point, end_point, line_thickness)
Use these examples to help you make your drawing program.
Now that you've written your code, let's check it again. Type this command in your terminal:
pytest module-1.2/blueprint-PY-1.2-BP7/quest-50
test_drawing_on_move
test_pen_toggle_off_prevents_drawing
test_pen_toggle_on_again_resumes_drawing
test_quit_event_terminates_loop
This document provides a reference for creating graphical applications using the Pygame and Turtle libraries in Python.
Pygame applications typically follow a structure called the game loop. This loop runs continuously, handling events, updating the program's state, and drawing to the screen.
The core of a Pygame application is the while running:
loop.
running = True
while running:
# 1. Event Handling
# Process user input (keyboard, mouse, window close)
# 2. Update State
# Change positions, scores, etc. (often based on continuous input)
# 3. Drawing
# Clear the screen or draw shapes/images
# 4. Update Display
# Show the drawn content on the screen
# 5. Control Frame Rate
# Limit how fast the loop runs
Before the game loop, Pygame needs to be initialized, and the display window must be created.
import pygame
import sys # Often needed for sys.exit()
# Constants (like screen dimensions, colors) are usually defined here
def run_game():
pygame.init() # Initialize Pygame modules
# Create the display surface (the window)
screen_width = 800
screen_height = 600
screen = pygame.display.set_mode((screen_width, screen_height))
# Set the window title
pygame.display.set_caption("My Pygame Window")
# Game state variables (position, color, etc.) are initialized here
# Fill the background initially (can be done once or every frame)
background_color = (0, 0, 0) # Black
screen.fill(background_color)
# Clock for controlling frame rate
clock = pygame.time.Clock()
running = True
while running:
# ... game loop ...
clock.tick(60) # Limit to 60 frames per second
# Clean up Pygame resources
pygame.quit()
# sys.exit() # Use this in a real application to close the process
Drawing happens on the screen
surface. Shapes are drawn using pygame.draw
.
# Inside the game loop, after updating state
# To clear the screen each frame (for non-trail drawing)
screen.fill(BACKGROUND_COLOR)
# Draw a circle
# pygame.draw.circle(surface, color, center_position, radius)
pygame.draw.circle(screen, (255, 255, 255), (x, y), 10) # White circle at (x, y) with radius 10
# Draw a line
# pygame.draw.line(surface, color, start_pos, end_pos, width)
pygame.draw.line(screen, (0, 255, 0), (x1, y1), (x2, y2), 5) # Green line from (x1, y1) to (x2, y2) with width 5
After drawing, pygame.display.flip()
or pygame.display.update()
makes the changes visible on the screen.
# Inside the game loop, after all drawing commands
pygame.display.flip() # Updates the full screen
# pygame.display.update() # Can update specific areas, flip() is simpler
User input comes in two main forms: events (single occurrences like a key press or mouse click) and continuous state (whether a key is currently held down).
The for event in pygame.event.get():
loop processes events that have occurred since the last frame. This is suitable for actions that should happen once per press, like toggling a state or clearing the screen.
# Inside the 'for event in pygame.event.get():' loop
if event.type == pygame.QUIT:
running = False # Stop the game loop
elif event.type == pygame.KEYDOWN:
# A key was pressed down
if event.key == pygame.K_c:
# The 'c' key was pressed
screen.fill(BACKGROUND_COLOR) # Example: Clear screen
elif event.type == pygame.MOUSEBUTTONDOWN:
# A mouse button was pressed down
if event.button == 1: # 1 is the left mouse button
print("Left mouse button clicked at", event.pos) # event.pos is the mouse coordinates
elif event.type == pygame.MOUSEBUTTONUP:
# A mouse button was released
if event.button == 1:
print("Left mouse button released")
elif event.type == pygame.MOUSEMOTION:
# The mouse was moved
print("Mouse moved to", event.pos)
pygame.key.get_pressed()
)To check which keys are currently being held down on every frame, use pygame.key.get_pressed()
. This is suitable for smooth, continuous movement.
# Inside the main while loop, but OUTSIDE the 'for event in pygame.event.get():' loop
keys = pygame.key.get_pressed() # Get the state of all keys
move_speed = 5
x, y = 100, 100 # Example position variables
if keys[pygame.K_LEFT]:
x -= move_speed # Move left if left arrow is held
if keys[pygame.K_RIGHT]:
x += move_speed # Move right if right arrow is held
if keys[pygame.K_UP]:
y -= move_speed # Move up if up arrow is held
if keys[pygame.K_DOWN]:
y += move_speed # Move down if down arrow is held
# After checking keys, use the updated x, y for drawing
State variables track the current condition of your program (e.g., position, color, whether drawing is active).
Variables like x
, y
, dot_x
, pen_x
store the coordinates of an object. Update these variables based on input.
# Initial state
x, y = SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2
# Update based on input (example using get_pressed)
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
x -= MOVE_SPEED
# ... other movement checks ...
# Use the updated position for drawing
pygame.draw.circle(screen, COLOR, (x, y), RADIUS)
A variable can hold the current color to be used for drawing.
# Initial state
current_color = (255, 0, 0) # Start with Red
# Update based on input (example using KEYDOWN event)
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_g:
current_color = (0, 255, 0) # Change to Green
# Use the current color for drawing
pygame.draw.circle(screen, current_color, (x, y), RADIUS)
To cycle through a predefined list of values (like colors), use an index variable and the modulo operator (%
).
# Initial state
color_list = [(255, 0, 0), (0, 255, 0), (0, 0, 255)] # Red, Green, Blue
color_index = 0
current_color = color_list[color_index]
# Update based on input (example using KEYDOWN event for spacebar)
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
# Increment index and wrap around using modulo
color_index = (color_index + 1) % len(color_list)
# Update the current color variable
current_color = color_list[color_index]
# Use current_color for drawing
A boolean variable (True
or False
) can track an on/off state, like whether the pen is currently drawing.
# Initial state
is_drawing = True # Pen starts 'down'
# Toggle the state based on input (example using KEYDOWN event for 'p')
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_p:
is_drawing = not is_drawing # Flip the boolean value
# Perform an action conditionally based on the state
if is_drawing:
# Draw only if is_drawing is True
pygame.draw.circle(screen, COLOR, (x, y), RADIUS)
The turtle
library uses a different approach than Pygame's continuous loop. You define functions (called handlers) for specific actions and then tell the screen to run those functions when certain events (like key presses) occur.
Instead of a while
loop, Turtle waits for events and calls the functions you've assigned to them.
import turtle
# Global variables for the pen and screen are common
pen = turtle.Turtle()
screen = turtle.Screen()
# Handler functions are defined here
def move_forward():
# This function will be called when a specific key is pressed
pen.forward(20)
# The main function sets up the listeners
def main():
screen.listen() # Tell the screen to listen for events
screen.onkey(fun=move_forward, key="Up") # Bind the 'Up' arrow key to move_forward function
# Start the Turtle event loop
if __name__ == "__main__":
main()
screen.mainloop() # Keep the window open and responsive to events
Create the Turtle
object (the pen) and the Screen
object.
import turtle
pen = turtle.Turtle()
screen = turtle.Screen()
# Optional setup
screen.setup(width=600, height=500)
screen.bgcolor("white")
pen.speed("fastest") # Adjust drawing speed
The pen
object has methods for movement and changing direction.
# Inside a handler function
pen.forward(distance)
pen.backward(distance)
pen.left(angle) # Turn counter-clockwise
pen.right(angle) # Turn clockwise
Control whether the turtle draws as it moves.
# Inside a handler function
pen.penup() # Lift the pen (stop drawing)
pen.pendown() # Put the pen down (start drawing)
# Check the current state
if pen.isdown():
print("Pen is down")
Change the color of the line the turtle draws.
# Inside a handler function
pen.color("red") # Set color by name
pen.color((0, 255, 0)) # Set color by RGB tuple
home
)Move the turtle back to the center of the screen (0,0) without clearing the drawing.
# Inside a handler function
pen.home() # Go back to (0,0) and face the default direction (usually East)
onkey
)Connect a specific key press to a handler function.
# Inside the main setup function
screen.onkey(fun=my_function, key="a") # Call my_function when 'a' is pressed
screen.onkey(fun=another_function, key="space") # Call another_function when spacebar is pressed
screen.onkey(fun=move_forward, key="Up") # Call move_forward when Up arrow is pressed
mainloop
)This command starts the Turtle graphics window and begins listening for events. It must be the last line in your main execution block (if __name__ == "__main__":
).
# At the end of your script
screen.mainloop()
Handler functions need access to the pen
and screen
objects, which are typically created outside the functions. If a handler needs to modify a global variable (like a color index), it must use the global
keyword.
# Global state
color_index = 0
COLORS = ["red", "blue"]
pen = turtle.Turtle()
def cycle_color():
global color_index # Declare intent to modify the global variable
color_index = (color_index + 1) % len(COLORS)
pen.color(COLORS[color_index])
def main():
screen.listen()
screen.onkey(fun=cycle_color, key="c")
# ... other bindings ...
# ... rest of the script ...