A game isn't much of a game if the player can't DO anything, right? We've been using INKEY$ in our examples, but there's SO much more to input in Crash BASIC!
Whether your players are mashing keys on a keyboard, clicking with a mouse, or tapping on their phone screen, Crash BASIC has you covered. Let's learn how to listen to your players!
Two Kinds of Input
Before we dive in, let's understand that there are two fundamentally different ways to get input:
1. Blocking Input — The program STOPS and waits for the player to type something. Great for menus, name entry, answering questions.
2. Real-time Input — The program keeps running and checks what keys/buttons are pressed RIGHT NOW. Essential for action games where you need smooth, responsive controls.
We'll cover both!
INPUT: Stop and Ask
When you need the player to type something—a name, a number, an answer—use INPUT:
INPUT "What is your name"; name$
PRINT "Hello, "; name$; "!"
PAUSEThe program stops at INPUT and waits. The player types their answer, presses Enter, and the value goes into the variable.
You can ask for numbers too:
INPUT "How many enemies"; enemyCount
INPUT "Difficulty (1-10)"; difficulty
PRINT "Creating "; enemyCount; " enemies at difficulty "; difficulty
PAUSEFancy Input with a Cursor
Want a more game-like input field with a blinking cursor? Use WITH CURSOR:
COLOR 14
INPUT WITH CURSOR("_") "Enter your name: "; name$
PRINT "Welcome, "; name$
PAUSEThe cursor character can be whatever you want:
"_"— Classic underscore cursorCHR$(219)— Solid block cursor
The input field uses your current COLOR for the text and border, so it matches your game's style!
Multiple Values
You can even ask for multiple values at once:
INPUT "Enter X, Y coordinates"; x, y
PRINT "You entered: "; x; ", "; y
PAUSEThe player types values separated by commas.
INKEY$: Quick Check, No Waiting
INKEY$ is the opposite of INPUT—it checks for a keypress WITHOUT stopping the program. If a key was pressed, it returns that key. If not, it returns an empty string.
SCREEN 13
PRINT "Press any key..."
DO
k$ = INKEY$
LOOP WHILE k$ = ""
PRINT "You pressed: "; k$
PAUSEThis is what we've been using in our game loops:
SCREEN 13
x = 160
DO
k$ = INKEY$
IF k$ = "a" THEN x = x - 5
IF k$ = "d" THEN x = x + 5
BEGIN FRAME
CLS
CIRCLE (x, 100), 10, 14
END FRAME
DELAY 16
LOOPThe Problem with INKEY$
INKEY$ works, but it has a limitation: it only catches ONE key at a time from a buffer. If you're holding down a key, you get repeated characters with a delay (like when you hold a key in a text editor).
This feels sluggish for games. Try holding "a" in that example above—see how it stutters?
For smooth, responsive controls, we need something better...
KEYDOWN: The Secret to Smooth Controls
KEYDOWN is a game-changer. Instead of checking what key WAS pressed, it checks what key IS pressed RIGHT NOW. Hold a key down? KEYDOWN returns 1 the entire time. Release it? Instantly returns 0.
SCREEN 13
x = 160
y = 100
DO
' Check keys in real-time
IF KEYDOWN("LEFT") THEN x = x - 3
IF KEYDOWN("RIGHT") THEN x = x + 3
IF KEYDOWN("UP") THEN y = y - 3
IF KEYDOWN("DOWN") THEN y = y + 3
BEGIN FRAME
CLS
CIRCLE (x, y), 10, 14
END FRAME
DELAY 16
LOOPTry THIS version! Hold down an arrow key—smooth as butter! The character moves continuously without any stutter.
Key Names for KEYDOWN
KEYDOWN uses string names for keys:
| Key | Name |
|---|---|
| Arrow keys | "LEFT", "RIGHT", "UP", "DOWN" |
| Space bar | "SPACE" |
| Escape | "ESC" |
| Enter | "ENTER" |
| Letters | "A", "B", "C", etc. (uppercase) |
| Numbers | "0", "1", "2", etc. |
Multiple Keys at Once!
Here's the REAL magic of KEYDOWN—you can check multiple keys simultaneously:
SCREEN 13
x = 160
y = 100
DO
' Diagonal movement works!
IF KEYDOWN("LEFT") THEN x = x - 3
IF KEYDOWN("RIGHT") THEN x = x + 3
IF KEYDOWN("UP") THEN y = y - 3
IF KEYDOWN("DOWN") THEN y = y + 3
' Fire while moving!
IF KEYDOWN("SPACE") THEN
CIRCLE (x, y - 20), 3, 12 ' Bullet!
END IF
BEGIN FRAME
CLS
CIRCLE (x, y), 10, 14
LOCATE 1, 1
PRINT "Arrows to move, SPACE to fire"
END FRAME
DELAY 16
LOOPWith INKEY$, you can only detect one key. With KEYDOWN, you can move diagonally AND fire at the same time! This is how real games feel responsive.
Mouse Input: Point and Click
For menu-driven games, strategy games, or any game where clicking matters, you need mouse input.
Where Is the Mouse?
SCREEN 13
DO
mx = MOUSEX()
my = MOUSEY()
BEGIN FRAME
CLS
CIRCLE (mx, my), 5, 15
LOCATE 1, 1
PRINT "Mouse: "; mx; ", "; my
END FRAME
DELAY 16
LOOPMOUSEX() and MOUSEY() return the current mouse position on your game canvas.
Is the Mouse Button Pressed?
SCREEN 13
DO
mx = MOUSEX()
my = MOUSEY()
BEGIN FRAME
CLS
IF MOUSEDOWN() THEN
CIRCLE (mx, my), 10, 14, 14 ' Filled yellow when clicking
ELSE
CIRCLE (mx, my), 10, 7 ' Gray outline otherwise
END IF
END FRAME
DELAY 16
LOOPMOUSEDOWN() returns 1 while the left mouse button is held down, 0 when released.
You can also check specific buttons:
MOUSEDOWN(0)— Left button (same as no parameter)MOUSEDOWN(1)— Middle buttonMOUSEDOWN(2)— Right button
Clicking on Things: COLLISION
To detect if the player clicked on a button or object, combine MOUSEDOWN with COLLISION:
SCREEN 13
buttonX = 110
buttonY = 80
buttonW = 100
buttonH = 40
DO
BEGIN FRAME
CLS
' Draw the button
LINE (buttonX, buttonY)-(buttonX + buttonW, buttonY + buttonH), 14, BF
LOCATE 12, 15
PRINT "CLICK ME"
' Check for click
IF MOUSEDOWN() THEN
IF COLLISION("POINT", MOUSEX(), MOUSEY(), buttonX, buttonY, buttonW, buttonH) THEN
LINE (buttonX, buttonY)-(buttonX + buttonW, buttonY + buttonH), 10, BF
LOCATE 12, 15
PRINT "CLICKED!"
END IF
END IF
END FRAME
DELAY 16
LOOPCOLLISION("POINT", ...) checks if a point (the mouse) is inside a rectangle (the button). The parameters are:
- Point X, Point Y (the mouse position)
- Rectangle X, Y, Width, Height (the button)
Mobile-Friendly Input: TAP and DRAG
Here's something cool: Crash BASIC runs in a web browser, which means your games can work on phones and tablets! But touchscreens don't have keyboards or mice. That's where TAP and DRAG come in.
TAP: Touch and Hold
TAP() returns 1 while the player is touching/clicking the screen (without dragging), 0 otherwise. It works on BOTH mobile (finger) and desktop (mouse)!
SCREEN 13
DO
BEGIN FRAME
CLS
IF TAP() THEN
' Player is tapping!
CIRCLE (MOUSEX(), MOUSEY()), 20, 14, 14
LOCATE 1, 1
PRINT "TAPPING!"
ELSE
LOCATE 1, 1
PRINT "Tap anywhere!"
END IF
END FRAME
DELAY 16
LOOPTAP is perfect for:
- Firing weapons (tap to shoot)
- Selecting things (tap on items)
- Charge-up mechanics (hold to charge, release to fire)
DRAG: Swipe and Slide
DRAGX() and DRAGY() return how far the player is dragging:
- Values range from -1 to 1
- -1 = dragging full left (or up for DRAGY)
- 0 = not dragging
- 1 = dragging full right (or down for DRAGY)
SCREEN 13
cameraX = 0
cameraY = 0
DO
' Drag to pan the camera
dx = DRAGX()
dy = DRAGY()
IF dx <> 0 OR dy <> 0 THEN
cameraX = cameraX - dx * 5
cameraY = cameraY - dy * 5
END IF
BEGIN FRAME
CLS
CIRCLE (160 + cameraX, 100 + cameraY), 30, 14
LOCATE 1, 1
PRINT "Drag to pan!"
LOCATE 2, 1
PRINT "Camera: "; INT(cameraX); ", "; INT(cameraY)
END FRAME
DELAY 16
LOOPDRAG is perfect for:
- Scrolling/panning the view
- Aiming (drag to set angle and power)
- Swipe gestures (swipe left/right to change pages)
- Virtual joysticks
Why TAP and DRAG Are Awesome
The best part about TAP and DRAG? They work on both mobile AND desktop!
- On mobile: TAP detects finger touches, DRAG detects swipes
- On desktop: TAP detects mouse clicks, DRAG detects click-and-drag
Write your game once, and it works everywhere. No separate code for touch vs. mouse!
Virtual Gamepad: Classic Controls on Mobile
What if you've already built a game using KEYDOWN() for arrow keys and buttons? Do you have to rewrite everything for touch screens? NOPE! Crash BASIC has a secret weapon: the Virtual Gamepad.
The virtual gamepad displays on-screen buttons—a D-pad for directions, A/B/X/Y action buttons, and a START button—that inject virtual key presses. Your existing KEYDOWN code works without changes!
Detecting Mobile Devices
First, use ISMOBILE() to check if the player is on a touch device:
SCREEN 13
IF ISMOBILE() THEN
PRINT "You're on a mobile device!"
ELSE
PRINT "You're on a desktop/laptop"
END IF
PAUSEISMOBILE() returns 1 on phones, tablets, and touchscreens, 0 on traditional desktops.
Setting Up the Gamepad
Map each gamepad button to a keyboard key, then turn it on:
IF ISMOBILE() THEN
' Map D-pad to WASD
GAMEPAD MAP "UP", "W"
GAMEPAD MAP "DOWN", "S"
GAMEPAD MAP "LEFT", "A"
GAMEPAD MAP "RIGHT", "D"
' Map action buttons
GAMEPAD MAP "A", "SPACE"
GAMEPAD MAP "B", "ENTER"
GAMEPAD MAP "X", "Q"
GAMEPAD MAP "Y", "E"
GAMEPAD MAP "START", "ESCAPE"
' Show the gamepad
GAMEPAD ON
END IFNow when a player presses the UP button on the virtual D-pad, KEYDOWN("W") returns 1! Your existing game code just works.
A Complete Mobile-Ready Game
SCREEN 13
' Enable virtual gamepad on mobile
IF ISMOBILE() THEN
GAMEPAD MAP "UP", "UP"
GAMEPAD MAP "DOWN", "DOWN"
GAMEPAD MAP "LEFT", "LEFT"
GAMEPAD MAP "RIGHT", "RIGHT"
GAMEPAD MAP "A", "SPACE"
GAMEPAD ON
END IF
playerX = 160
playerY = 100
DO
' These checks work with BOTH keyboard AND virtual gamepad!
IF KEYDOWN("LEFT") THEN playerX = playerX - 3
IF KEYDOWN("RIGHT") THEN playerX = playerX + 3
IF KEYDOWN("UP") THEN playerY = playerY - 3
IF KEYDOWN("DOWN") THEN playerY = playerY + 3
' Fire with A button or spacebar
IF KEYDOWN("SPACE") THEN
CIRCLE (playerX, playerY - 20), 3, 12
END IF
BEGIN FRAME
CLS
CIRCLE (playerX, playerY), 10, 14
LOCATE 1, 1
IF ISMOBILE() THEN
PRINT "Use the virtual gamepad!"
ELSE
PRINT "Arrows to move, SPACE to fire"
END IF
END FRAME
DELAY 16
LOOPGamepad Controls
| Command | What It Does |
|---|---|
GAMEPAD MAP "button", "key" |
Map a button to simulate a keyboard key |
GAMEPAD ON |
Show the virtual gamepad overlay |
GAMEPAD OFF |
Hide the virtual gamepad overlay |
GAMEPAD RESET |
Clear all button mappings |
GAMEPAD DPAD JOYSTICK |
Display D-pad as analog joystick (supports diagonals) |
GAMEPAD DPAD BUTTONS |
Display D-pad as 4 separate buttons (default) |
| Button Names | |
|---|---|
| D-pad | "UP", "DOWN", "LEFT", "RIGHT" |
| Action buttons | "A", "B", "X", "Y" |
| Center button | "START" |
Joystick Mode for Diagonal Movement
By default, the D-pad shows four separate directional buttons. But some games need diagonal movement! Use GAMEPAD DPAD JOYSTICK to switch to a draggable joystick that can press multiple directions at once:
' Set up a game with diagonal movement
GAMEPAD MAP "UP", "W"
GAMEPAD MAP "DOWN", "S"
GAMEPAD MAP "LEFT", "A"
GAMEPAD MAP "RIGHT", "D"
GAMEPAD MAP "A", "SPACE"
GAMEPAD ON
GAMEPAD DPAD JOYSTICK ' Now the D-pad is a joystick!
' Game loop - diagonal movement works automatically
DO
dx = 0
dy = 0
IF KEYDOWN("W") THEN dy = dy - 2
IF KEYDOWN("S") THEN dy = dy + 2
IF KEYDOWN("A") THEN dx = dx - 2
IF KEYDOWN("D") THEN dx = dx + 2
playerX = playerX + dx
playerY = playerY + dy
DELAY 16
LOOPWhen the player drags the joystick diagonally (like up-right), both "W" and "D" keys are pressed simultaneously. Switch back anytime with GAMEPAD DPAD BUTTONS.
Raw Touch Coordinates: TOUCHX and TOUCHY
Sometimes you want to know the exact position of a finger touch, separate from mouse input. TOUCHX() and TOUCHY() give you that:
SCREEN 13
DO
tx = TOUCHX()
ty = TOUCHY()
BEGIN FRAME
CLS
IF tx >= 0 AND ty >= 0 THEN
' Active touch - draw at touch position
CIRCLE (tx, ty), 15, 14, 14
LOCATE 1, 1
PRINT "Touch: "; tx; ", "; ty
ELSE
LOCATE 1, 1
PRINT "Touch the screen!"
END IF
END FRAME
DELAY 16
LOOPTOUCHX() and TOUCHY() return -1 when there's no active touch—unlike MOUSEX()/MOUSEY() which always return a position. This lets you distinguish between:
- No touch at all (-1)
- Touch at coordinate 0 (0)
Choosing the Right Input Method
Here's a quick guide:
| Situation | Use This |
|---|---|
| Player types text/numbers | INPUT |
| Menu selection (one key) | INKEY$ |
| Action game movement | KEYDOWN |
| Point-and-click game | MOUSEX, MOUSEY, MOUSEDOWN |
| Mobile-friendly game | TAP, DRAGX, DRAGY |
| Universal (works everywhere) | TAP + DRAG + KEYDOWN combo |
For the most compatible games, combine multiple input methods:
SCREEN 13
playerX = 160
playerY = 100
DO
' Keyboard controls
IF KEYDOWN("LEFT") THEN playerX = playerX - 3
IF KEYDOWN("RIGHT") THEN playerX = playerX + 3
IF KEYDOWN("UP") THEN playerY = playerY - 3
IF KEYDOWN("DOWN") THEN playerY = playerY + 3
' Touch/drag controls (mobile-friendly!)
dx = DRAGX()
dy = DRAGY()
IF dx <> 0 OR dy <> 0 THEN
playerX = playerX + dx * 5
playerY = playerY + dy * 5
END IF
' Keep player on screen
IF playerX < 10 THEN playerX = 10
IF playerX > 310 THEN playerX = 310
IF playerY < 10 THEN playerY = 10
IF playerY > 190 THEN playerY = 190
BEGIN FRAME
CLS
CIRCLE (playerX, playerY), 10, 14
LOCATE 1, 1
PRINT "Arrows or drag to move!"
END FRAME
DELAY 16
LOOPNow your game works with keyboard OR touch!
Putting It All Together: A Menu System
Let's build a complete menu with multiple input options:
SCREEN 13
' Menu state
selected = 1
menuItems = 3
DO
BEGIN FRAME
CLS
LOCATE 3, 12
PRINT "=== MAIN MENU ==="
' Draw menu items
FOR i = 1 TO menuItems
LOCATE 5 + i * 2, 10
IF i = selected THEN
PRINT "> ";
ELSE
PRINT " ";
END IF
IF i = 1 THEN PRINT "Start Game"
IF i = 2 THEN PRINT "Options"
IF i = 3 THEN PRINT "Quit"
NEXT i
LOCATE 15, 5
PRINT "UP/DOWN to select, ENTER to confirm"
LOCATE 16, 8
PRINT "Or tap/click an option!"
END FRAME
' Keyboard navigation
IF KEYDOWN("UP") THEN
selected = selected - 1
IF selected < 1 THEN selected = menuItems
DELAY 150 ' Debounce
END IF
IF KEYDOWN("DOWN") THEN
selected = selected + 1
IF selected > menuItems THEN selected = 1
DELAY 150
END IF
' Mouse/touch selection
IF TAP() THEN
my = MOUSEY()
FOR i = 1 TO menuItems
itemY = (5 + i * 2) * 8 ' Convert text row to pixel Y
IF my >= itemY AND my < itemY + 16 THEN
selected = i
END IF
NEXT i
END IF
' Confirm selection
IF KEYDOWN("ENTER") OR (TAP() AND MOUSEY() >= 56 AND MOUSEY() < 120) THEN
IF selected = 1 THEN
CLS
PRINT "Starting game..."
DELAY 1000
ELSEIF selected = 2 THEN
CLS
PRINT "Options screen..."
DELAY 1000
ELSEIF selected = 3 THEN
END
END IF
END IF
DELAY 16
LOOPThis menu:
- Works with UP/DOWN arrows
- Works with ENTER to confirm
- Works with mouse clicks
- Works with touch on mobile
- Highlights the current selection
Quick Reference
| Function | Returns | Use For |
|---|---|---|
INPUT "prompt"; var |
Typed value | Text entry, questions |
INKEY$ |
Key character or "" | Single key checks |
KEYDOWN("KEY") |
1 or 0 | Smooth real-time controls |
MOUSEX() |
X position | Mouse/touch location |
MOUSEY() |
Y position | Mouse/touch location |
MOUSEDOWN([btn]) |
1 or 0 | Click detection |
TAP() |
1 or 0 | Touch-friendly clicks |
DRAGX() |
-1 to 1 | Horizontal swipes |
DRAGY() |
-1 to 1 | Vertical swipes |
TOUCHX() |
X or -1 | Raw touch X coordinate |
TOUCHY() |
Y or -1 | Raw touch Y coordinate |
ISMOBILE() |
1 or 0 | Detect touch devices |
GAMEPAD ON/OFF |
— | Show/hide virtual gamepad |
GAMEPAD MAP "btn", "key" |
— | Map button to key |
GAMEPAD DPAD JOYSTICK |
— | D-pad as analog joystick |
GAMEPAD DPAD BUTTONS |
— | D-pad as separate buttons |
COLLISION("POINT",...) |
1 or 0 | Click on object detection |
Try It Yourself!
- Make a drawing program where you draw with the mouse (hint: PSET at MOUSEX(), MOUSEY() when MOUSEDOWN)
- Create a "Simon Says" game that shows a sequence of colors and the player must tap them in order
- Build a virtual joystick using DRAGX and DRAGY to control a character
- Make a typing game where random letters appear and the player must type them (use INKEY$)
Your players are ready to interact—give them something fun to do!
See you in Chapter 8!
Next Chapter: We'll organize our code with subroutines and functions—because good code is reusable code!