Handling Input
In this tutorial, you’ll make a blue box that moves across the screen using the arrow keys.
This is your first interactive app, and it’s surprisingly easy!
You’ll learn how to:
- Detect key presses in real time
- Use
pollevent()
andkeydown()
to check input - Move a shape by changing its position
Step 1: Setup
Section titled “Step 1: Setup”Start by importing gint
, clearing the screen, and defining your box’s starting position:
import gint
x = 100y = 100speed = 4
x
,y
: position of the boxspeed
: how many pixels to move per key press
Step 2: The Game Loop
Section titled “Step 2: The Game Loop”This loop will run forever — we’ll:
- Clear the screen
- Draw the box
- Check for input
- Move the box if needed
- Refresh the display
while True: gint.dclear(gint.C_WHITE) gint.drect(x, y, x+20, y+20, gint.C_RGB(0, 0, 31)) # Blue box gint.dupdate()
We draw the box every frame at its current position.
Step 3: Polling for Input
Section titled “Step 3: Polling for Input”We now check for keys using pollevent()
.
ev = gint.pollevent()
This returns an object with the type of event (KEYEV_DOWN
, KEYEV_UP
, etc.).
Then we check if the key is held down using keydown()
:
if gint.keydown(gint.KEY_LEFT): x -= speed if gint.keydown(gint.KEY_RIGHT): x += speed if gint.keydown(gint.KEY_UP): y -= speed if gint.keydown(gint.KEY_DOWN): y += speed
This makes the box move smoothly in response to arrow keys.
Step 4: Exit with EXIT key
Section titled “Step 4: Exit with EXIT key”Let’s allow the user to quit with the EXIT key:
if ev.type == gint.KEYEV_DOWN and ev.key == gint.KEY_EXIT: break
If you press [EXIT], the program ends.
What’s the Difference? keydown
vs. keypressed
Section titled “What’s the Difference? keydown vs. keypressed”For now you used keydown()
to move the box. This works perfectly for continuous actions like movement because keydown()
is true for every single frame your finger is holding the key down.
But what if you want an action to happen only once when you press a key?
- Jumping in a platformer
- Firing a single laser
- Opening a menu
If you used keydown()
for these, you’d jump 30 times a second or fire a constant beam of lasers! This is why there is keypressed()
, that is like a light switch:
gint.keydown()
is asking: “Is the light switch currently in the ‘on’ position?” You can ask this anytime, and it will be true as long as the switch is on.gint.keypressed()
is asking: “Did someone just flick the switch on?” This is only true for the one brief moment the action happens.
The Technical Difference and the Game Loop
Section titled “The Technical Difference and the Game Loop”To make keypressed()
work, gint
needs you to mark the beginning of your frame’s input check. This is done with a special function called cleareventflips()
.
The correct game loop structure for using both keydown
and keypressed
looks like this:
# Render game...
# --- INPUT HANDLING ---# 1. Mark the start of a new input check. This is our "reference point".cleareventflips()
# 2. Process all hardware events that happened since the last check.# This updates gint's internal state about what keys are up or down.clearevents() # or a loop with pollevent()
# 3. Now, ask your questions about the state.if keypressed(KEY_ACTION): # Do something ONCE passif keydown(KEY_LEFT): # Do something CONTINUOUSLY pass
# Simulate game...
Let’s modify use this to add some actions !
Step 5: Adding a One-Shot Action
Section titled “Step 5: Adding a One-Shot Action”We’ll keep the smooth movement using keydown()
, but we’ll add a new feature: pressing the [EXE] key will instantly change the box’s color. This should only happen once per press.
First, let’s create a variable for the color.
import gint
x = 100y = 100speed = 4box_color = gint.C_RGB(0, 0, 31) # Start as blue
Next, we’ll update the game loop to use the new input structure and check for keypressed()
.
while True: # --- RENDER --- gint.dclear(gint.C_WHITE) # Use the color variable here gint.drect(x, y, x+20, y+20, box_color) gint.dupdate()
# --- HANDLE INPUT --- gint.cleareventflips() gint.clearevents() # Replaces the single pollevent()
# Check for continuous movement with keydown() if gint.keydown(gint.KEY_LEFT): x -= speed if gint.keydown(gint.KEY_RIGHT): x += speed if gint.keydown(gint.KEY_UP): y -= speed if gint.keydown(gint.KEY_DOWN): y += speed
# Check for a single color change with keypressed() if gint.keypressed(gint.KEY_EXE): # Toggle between blue and red if box_color == gint.C_RGB(0, 0, 31): box_color = gint.C_RGB(31, 0, 0) # Red else: box_color = gint.C_RGB(0, 0, 31) # Blue
# Check for exit (you could use gint.keydown(gint.KEY_EXIT) too ) if ev.type == gint.KEYEV_DOWN and ev.key == gint.KEY_EXIT: break
Final Code
Section titled “Final Code”import gint
# --- Game State ---x = 100y = 100speed = 4box_color = gint.C_RGB(0, 0, 31) # Start as blue
# --- Game Loop ---while True: # 1. Render the current state of the game gint.dclear(gint.C_WHITE) gint.drect(x, y, x+20, y+20, box_color) gint.dupdate()
# 2. Handle all input for the next frame gint.cleareventflips() gint.clearevents()
# Continuous actions if gint.keydown(gint.KEY_LEFT): x -= speed if gint.keydown(gint.KEY_RIGHT): x += speed if gint.keydown(gint.KEY_UP): y -= speed if gint.keydown(gint.KEY_DOWN): y += speed
# Single, one-shot action if gint.keypressed(gint.KEY_EXE): if box_color == gint.C_RGB(0, 0, 31): box_color = gint.C_RGB(31, 0, 0) else: box_color = gint.C_RGB(0, 0, 31)
# Exit condition if gint.keydown(gint.KEY_EXIT): break
Now, when you run this, holding the arrow keys moves the box smoothly, but holding the [EXE] key will only change the color once. You have to release it and press it again for the color to change back.
You’ve successfully handled both continuous and discrete input !
What’s next?
Section titled “What’s next?”Now that you can move a rectangle. That’s cool !
As an exercise, you can try to prevent the box from going outside the screen.
Next up: Let’s make it move by itself.