Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Phones, tablets and gamepads

A phone has no arrow keys, and a living-room console has no keyboard at all. In Keys, the mouse and a finger you saw that a finger works the mouse. Now for the rest: buttons on the screen, the ways a finger can steer, and a gamepad in your hands.

A gamepad on the screen

GAMEPAD ON puts a gamepad over the game: a D-pad on the left, A, B, X and Y on the right, and START in the middle. Each button presses a key, and GAMEPAD MAP says which one. So a game that reads keys with keydown works on a phone without changing a line of its loop.

SCREEN 320, 240
GAMEPAD ON
GAMEPAD MAP "UP", "Up"
GAMEPAD MAP "DOWN", "Down"
GAMEPAD MAP "LEFT", "Left"
GAMEPAD MAP "RIGHT", "Right"
GAMEPAD MAP "A", "Space"

x = 160
y = 80
DO
    IF COOLDOWN(1)
        IF keydown("Left") THEN x = x - 2
        IF keydown("Right") THEN x = x + 2
        IF keydown("Up") THEN y = y - 2
        IF keydown("Down") THEN y = y + 2
        shade = 14
        IF keydown("Space") THEN shade = 12
        MEMORYBUFFER "scene"
            CIRCLE (x, y), 10, shade, shade
        END MEMORYBUFFER
        FRAME
            CLS
            PUTIMAGE (0, 0), "scene"
        END FRAME
    END IF
LOOP

The buttons are called "UP", "DOWN", "LEFT", "RIGHT", "A", "B", "X", "Y" and "START". A button you haven’t mapped presses nothing.

Making it yours

Most games don’t need every button. A few more words tidy the gamepad up:

  • GAMEPAD BUTTON "B", FALSE hides a button, and TRUE brings it back.
  • GAMEPAD BUTTON "A" !! at((0.85, 0.8)) moves one. The place is a share of the screen, from 0 to 1 each way, so it lands in the same spot on any size of phone.
  • GAMEPAD ALPHA 0.5 makes the whole gamepad half see-through.
  • GAMEPAD SETIMAGE "A", "jump" draws a button with an image of yours.
  • GAMEPAD DPAD says how the D-pad works: "buttons", four of them, the way it starts; "joystick", a stick you push any way, diagonals and all; or "drag", where you put your thumb down anywhere and slide it.
  • GAMEPAD OFF hides it, for a cutscene or a menu you tap, and GAMEPAD RESET forgets every GAMEPAD MAP.

Here’s a gamepad for a runner, where all you do is jump: one big button, faint, in the corner where a right thumb rests.

SCREEN 320, 240
MEMORYBUFFER "jump", 32, 32
    CIRCLE (16, 16), 15, 12, 4
    POLYGON [(16, 6), (26, 20), (6, 20)], 15, 15
END MEMORYBUFFER

FOR button = ["UP", "DOWN", "LEFT", "RIGHT", "B", "X", "Y", "START"]
    GAMEPAD BUTTON button, FALSE
END FOR
GAMEPAD BUTTON "A" !! at((0.88, 0.82))
GAMEPAD SETIMAGE "A", "jump"
GAMEPAD ALPHA 0.6
GAMEPAD MAP "A", "Space"
GAMEPAD ON

y = 200
speed = 0
DO
    IF COOLDOWN(1)
        IF keydown("Space") AND y = 200 THEN speed = -6
        speed = speed + 0.3
        y = min(y + speed, 200)
        MEMORYBUFFER "scene"
            LINE (0, 211) -> (319, 239), 2 !! box fill
            CIRCLE (60, y), 10, 14, 14
        END MEMORYBUFFER
        FRAME
            CLS
            PUTIMAGE (0, 0), "scene"
        END FRAME
    END IF
LOOP

Steering with a finger

Some games are better with no buttons at all. Here’s what I know about a finger on the screen:

touchx, touchyWhere a finger is touching, or -1 when none is. Only a finger: the mouse doesn’t count.
mousex, mouseyWhere the mouse is, or a finger.
tap1 while a finger (or the mouse button) is held down and hasn’t moved.
dragx, dragyHow far a finger (or the mouse) has been dragged since it went down, from -1 to 1, and 0 when it isn’t dragging.

dragx and dragy make a joystick out of the whole screen: put a finger down anywhere and slide it. Halfway across the screen is all the way, 1 or -1. Try it with the mouse, too: hold the button and drag.

SCREEN 320, 240
x = 160
y = 120
DO
    IF COOLDOWN(1)
        x = clamp(x + dragx * 4, 0, 320)
        y = clamp(y + dragy * 4, 0, 240)
        shade = 11
        IF tap THEN shade = 15
        MEMORYBUFFER "scene"
            POLYGON [(x, y - 8), (x + 6, y + 6), (x - 6, y + 6)], shade, shade
        END MEMORYBUFFER
        FRAME
            CLS
            PUTIMAGE (0, 0), "scene"
        END FRAME
    END IF
LOOP

Press and hold without moving and the ship lights up: that’s tap. As soon as you drag, tap goes back to 0 and the ship starts to move.

Where am I running?

ismobile is 1 on a phone or a tablet, and isconsole is 1 on a console in the living room. Use them to pick the controls and the words on the screen:

SCREEN 320, 240
IF ismobile
    GAMEPAD ON
    PRINT "Tap A to start"
ELSE IF isconsole
    GAMEPAD PHYSICAL ON
    PRINT "Press A to start"
ELSE
    PRINT "Press Space to start"
END IF

Crash-tan’s Tip: On a console there’s no screen to touch, so I never show the on-screen gamepad there, even if you ask. Its players have a real gamepad, which is next.

A gamepad in your hands

GAMEPAD PHYSICAL ON, which you met in Keys, the mouse and a finger, switches on real gamepads. Once it’s on, GAMEPAD MAP works for them as it does for the one on the screen: the same mapping and the same keys, so one loop serves the keyboard, the screen and the gamepad.

For more than keys, ask the gamepad itself. joybutton(n) is 1 while a button’s held: 0 is A, 1 is B, 2 is X, 3 is Y, and 9 is START. joyaxis(0) and joyaxis(1) are the left stick, from -1 to 1, and joyaxis(2) and joyaxis(3) the right one. Each takes a second number to read the second gamepad, the third, or the fourth.

RUMBLE shakes it. !! strength is how hard, from 0 to 1, and !! duration is for how long, in milliseconds.

SCREEN 320, 240
GAMEPAD PHYSICAL ON
GAMEPAD MAP "A", "Space"

x = 160
was_down = FALSE
DO
    IF COOLDOWN(1)
        stick = joyaxis(0)
        IF abs(stick) > 0.2 THEN x = clamp(x + stick * 4, 10, 310)
        IF keydown("Left") THEN x = x - 3
        IF keydown("Right") THEN x = x + 3

        // A, or Space on the keyboard: a shake you can feel.
        down = keydown("Space")
        IF down AND NOT was_down THEN RUMBLE !! strength(0.8) duration(150)
        was_down = down

        MEMORYBUFFER "scene"
            CIRCLE (x, 120), 12, 14, 14
        END MEMORYBUFFER
        FRAME
            CLS
            PUTIMAGE (0, 0), "scene"
            LOCATE 1, 1
            PRINT "gamepads:", joyconnected
        END FRAME
    END IF
LOOP

Crash-tan’s Tip: A stick never rests at exactly 0. Ignoring anything under 0.2, as that loop does, keeps a sprite from creeping about on its own.