Mamun Labs Learn
JourneyGlossary
esc
  • Try “map”, “flexbox” or “state”.
Log in
Start learning
Phase 7 · 2 / 5Touch input
Phase 7Games
5 topics · 3–4 wks
  1. 1The game loop
  2. 2Touch input
  3. 3Simple animation
  4. 4Collisions and score
  5. 5Sound and saving the best score
JourneyPhase 7Touch input
01 / 09Overview

Touch input

You'll learn to make the whole screen listen for a tap and change the game when it comes.

Why it mattersA tap is how the player talks to your game. Without it, the game only plays itself.
about 60 min·needs: The game loop, Pressable and TextInput
02 / 09

Watch & read

Start with the required ones. The others are there when you need them.

Docs
Pressablereactnative.dev · official docs · 10 min · English
MMamun's noteRead "How it works" slowly. It shows the order: onPressIn, then onPressOut, then onPress. That is why our game uses onPressIn. In "Props", only look at onPress, onPressIn and hitSlop.
Video
Complete React Native tutorial #8: Pressable componentYouTube · Net Ninja · 11 min · English
MMamun's noteHe builds a button with Pressable and onPress, and makes it fade while it is pressed. It is a login button, not a game, but it is the same Pressable. Skip the parts about his ThemedButton files if you get lost.
DocsOptional
Gesture responder systemreactnative.dev · official docs · 10 min · English
MMamun's noteRead only "Best Practices" at the top: a tap should give feedback, and the player should be able to cancel it. The rest is how React Native decides who gets a touch. Come back to it when you want swipes and drags.
03 / 09

Explanation

You want the square to jump when the player taps, anywhere on the screen. Small buttons are hard to hit in a fast game, so the whole screen becomes the button.

Think of a doorbell. Pressing it does not open the door by itself. It only tells someone inside, and they decide what to do. A tap is the same: it calls your function, and your function changes the game.

Pressable turns anything into something you can tap. Wrap the whole screen in one, with flex: 1:

<Pressable style={styles.screen} onPressIn={() => setGame((g) => handleTap(g))}>
{/* the world, the square, the obstacle */}
</Pressable>

Pressable has two events you will meet. onPress runs when the finger lifts. onPressIn runs the moment the finger touches. A game wants the jump right away, so we use onPressIn.

handleTap is a plain function, like step. It takes the game and returns the next one:

function handleTap(game) {
if (game.playerY > 0) return game;
return { ...game, playerY: JUMP_HEIGHT };
}

On the ground (playerY is 0) a tap puts the square up at 150. Then the game loop pulls it down, 10 points every tick, until it is back on the ground. That is our first, simple jump. It goes up all at once, which looks a bit rough. The next topic makes it smooth.

People often let the player jump in the air. Without the if, tapping fast sends the square up again and again, and it never comes down. The game becomes too easy, and the player can fly.

When you read touch code in a game, find the Pressable, see which event it uses, and read the function it calls. That function, not the Pressable, decides what the tap does.

Words to recognise
PressableonPressonPressIntouchevent handler
04 / 09

Code tour

Click a line number with a ring to read the note for that line.

App.jsx4 notes
1function handleTap(game) {
if (game.playerY > 0) return game;
Mentor note · line 2
In the air already? Then return the game unchanged. No double jumps.
return { ...game, playerY: JUMP_HEIGHT };
4}
5export default function App() {
6 const [game, setGame] = useState({ obstacleX: 400, playerY: 0, score: 0 });
7 // ...the game loop from the last topic...
8 return (
<Pressable style={styles.screen} onPressIn={() => setGame((g) => handleTap(g))}>
10 <View style={styles.world}>
<View style={[styles.player, { bottom: game.playerY }]} />
12 <View style={[styles.obstacle, { left: game.obstacleX }]} />
13 </View>
14 </Pressable>
15 );
16}
05 / 09

Practice

Short drills. Take your time and read the code before you answer.

DrillPredict1 / 3
1const JUMP_HEIGHT = 150;
2const FALL_SPEED = 10;
3
4function handleTap(game) {
5 if (game.playerY > 0) return game;
6 return { ...game, playerY: JUMP_HEIGHT };
7}
8
9function fall(game) {
10 return { ...game, playerY: Math.max(0, game.playerY - FALL_SPEED) };
11}
12
13let game = { obstacleX: 300, playerY: 0, score: 0 };
14game = handleTap(game); // first tap
15game = fall(game); // tick
16game = fall(game); // tick
17game = handleTap(game); // second tap, in the air
18console.log(game.playerY);
What is playerY after the second tap?
DrillOnly jump from the ground2 / 3
Right now handleTap jumps on every tap, even in the air, so the player can fly. Change it: when playerY is above 0, give back the game unchanged. On the ground, jump to JUMP_HEIGHT like now.
1
2
3
4
5
Try 1 of 3 · solution unlocks after 3
DrillTap to jump3 / 3
Now the square listens. Tap anywhere on the screen and it jumps, then the loop pulls it down. Try to jump over the obstacle. It cannot hit you yet; that comes in a later topic.
1import { useEffect, useState } from "react";
2import { Pressable, StyleSheet, Text, View } from "react-native";
3
4const SPEED = 10;
5const SCREEN_WIDTH = 400;
6const OBSTACLE_WIDTH = 30;

Runs in the browser. Choose “My Device” in Snack to try it on your phone with Expo Go.

Working whenTap anywhere on the dark screen, not only on the square. It jumps.Tap again while it is in the air. Nothing happens.Change onPressIn to onPress, then hold your finger down. The jump only comes when you lift. Change it back.Make the jump higher by changing JUMP_HEIGHT to 200.
Check each goal yourself, then mark it.
06 / 09

Quick check

3 questions. Each one explains itself after you answer.

  1. 1 / 3Why does our game use onPressIn instead of onPress?
  2. 2 / 3How do we make a tap anywhere on the screen count?
  3. 3 / 3The square is in the air with playerY at 90. What does handleTap return?
07 / 09

Explain it back

Only you can see this. Log in to keep it.0 words
08 / 09

How confident are you with Touch input?

09 / 09

Done

You can now
Read a tap handler in a game and say what it changes, and when it does nothing.
Next: Simple animation Back to Phase 7
On this page
  1. 01Touch input
  2. 02Watch & read
  3. 03Explanation
  4. 04Code tour
  5. 05Practice
  6. 06Quick check
  7. 07Explain it back
  8. 08Confidence
  9. 09Done
Up next · 02 / 09Watch & read
Mamun Labs LearnFound a mistake on this page? Tell Mamun.
Mamun Labs Learn
JourneyGlossary
esc
  • Try “map”, “flexbox” or “state”.
Log in
Start learning
Log in to save your progress. Everything here works without an account.Log in to save progressLog in
Phase 7Games
5 topics · 3–4 wks
  1. 1The game loop
  2. 2Touch input
  3. 3Simple animation
  4. 4Collisions and score
  5. 5Sound and saving the best score
JourneyPhase 7Touch input
01 / 09Overview

Touch input

You'll learn to make the whole screen listen for a tap and change the game when it comes.

Why it mattersA tap is how the player talks to your game. Without it, the game only plays itself.
about 60 min·needs: The game loop, Pressable and TextInput
02 / 09

Watch & read

Start with the required ones. The others are there when you need them.

Docs
Pressablereactnative.dev · official docs · 10 min · English
MMamun's noteRead "How it works" slowly. It shows the order: onPressIn, then onPressOut, then onPress. That is why our game uses onPressIn. In "Props", only look at onPress, onPressIn and hitSlop.
Video
Complete React Native tutorial #8: Pressable componentYouTube · Net Ninja · 11 min · English
MMamun's noteHe builds a button with Pressable and onPress, and makes it fade while it is pressed. It is a login button, not a game, but it is the same Pressable. Skip the parts about his ThemedButton files if you get lost.
DocsOptional
Gesture responder systemreactnative.dev · official docs · 10 min · English
MMamun's noteRead only "Best Practices" at the top: a tap should give feedback, and the player should be able to cancel it. The rest is how React Native decides who gets a touch. Come back to it when you want swipes and drags.
03 / 09

Explanation

You want the square to jump when the player taps, anywhere on the screen. Small buttons are hard to hit in a fast game, so the whole screen becomes the button.

Think of a doorbell. Pressing it does not open the door by itself. It only tells someone inside, and they decide what to do. A tap is the same: it calls your function, and your function changes the game.

Pressable turns anything into something you can tap. Wrap the whole screen in one, with flex: 1:

<Pressable style={styles.screen} onPressIn={() => setGame((g) => handleTap(g))}>
{/* the world, the square, the obstacle */}
</Pressable>

Pressable has two events you will meet. onPress runs when the finger lifts. onPressIn runs the moment the finger touches. A game wants the jump right away, so we use onPressIn.

handleTap is a plain function, like step. It takes the game and returns the next one:

function handleTap(game) {
if (game.playerY > 0) return game;
return { ...game, playerY: JUMP_HEIGHT };
}

On the ground (playerY is 0) a tap puts the square up at 150. Then the game loop pulls it down, 10 points every tick, until it is back on the ground. That is our first, simple jump. It goes up all at once, which looks a bit rough. The next topic makes it smooth.

People often let the player jump in the air. Without the if, tapping fast sends the square up again and again, and it never comes down. The game becomes too easy, and the player can fly.

When you read touch code in a game, find the Pressable, see which event it uses, and read the function it calls. That function, not the Pressable, decides what the tap does.

Words to recognise
PressableonPressonPressIntouchevent handler
04 / 09

Code tour

Click a line number with a ring to read the note for that line.

App.jsx4 notes
1function handleTap(game) {
if (game.playerY > 0) return game;
Mentor note · line 2
In the air already? Then return the game unchanged. No double jumps.
return { ...game, playerY: JUMP_HEIGHT };
4}
5export default function App() {
6 const [game, setGame] = useState({ obstacleX: 400, playerY: 0, score: 0 });
7 // ...the game loop from the last topic...
8 return (
<Pressable style={styles.screen} onPressIn={() => setGame((g) => handleTap(g))}>
10 <View style={styles.world}>
<View style={[styles.player, { bottom: game.playerY }]} />
12 <View style={[styles.obstacle, { left: game.obstacleX }]} />
13 </View>
14 </Pressable>
15 );
16}
05 / 09

Practice

Short drills. Take your time and read the code before you answer.

DrillPredict1 / 3
1const JUMP_HEIGHT = 150;
2const FALL_SPEED = 10;
3
4function handleTap(game) {
5 if (game.playerY > 0) return game;
6 return { ...game, playerY: JUMP_HEIGHT };
7}
8
9function fall(game) {
10 return { ...game, playerY: Math.max(0, game.playerY - FALL_SPEED) };
11}
12
13let game = { obstacleX: 300, playerY: 0, score: 0 };
14game = handleTap(game); // first tap
15game = fall(game); // tick
16game = fall(game); // tick
17game = handleTap(game); // second tap, in the air
18console.log(game.playerY);
What is playerY after the second tap?
DrillOnly jump from the ground2 / 3
Right now handleTap jumps on every tap, even in the air, so the player can fly. Change it: when playerY is above 0, give back the game unchanged. On the ground, jump to JUMP_HEIGHT like now.
1
2
3
4
5
Try 1 of 3 · solution unlocks after 3
DrillTap to jump3 / 3
Now the square listens. Tap anywhere on the screen and it jumps, then the loop pulls it down. Try to jump over the obstacle. It cannot hit you yet; that comes in a later topic.
1import { useEffect, useState } from "react";
2import { Pressable, StyleSheet, Text, View } from "react-native";
3
4const SPEED = 10;
5const SCREEN_WIDTH = 400;
6const OBSTACLE_WIDTH = 30;

Runs in the browser. Choose “My Device” in Snack to try it on your phone with Expo Go.

Working whenTap anywhere on the dark screen, not only on the square. It jumps.Tap again while it is in the air. Nothing happens.Change onPressIn to onPress, then hold your finger down. The jump only comes when you lift. Change it back.Make the jump higher by changing JUMP_HEIGHT to 200.
Check each goal yourself, then mark it.
06 / 09

Quick check

3 questions. Each one explains itself after you answer.

  1. 1 / 3Why does our game use onPressIn instead of onPress?
  2. 2 / 3How do we make a tap anywhere on the screen count?
  3. 3 / 3The square is in the air with playerY at 90. What does handleTap return?
07 / 09

Explain it back

Only you can see this. Log in to keep it.0 words
08 / 09

How confident are you with Touch input?

09 / 09

Done

You can now
Read a tap handler in a game and say what it changes, and when it does nothing.
Next: Simple animation Back to Phase 7
On this page
  1. 01Touch input
  2. 02Watch & read
  3. 03Explanation
  4. 04Code tour
  5. 05Practice
  6. 06Quick check
  7. 07Explain it back
  8. 08Confidence
  9. 09Done
Up next · 02 / 09Watch & read

You want the square to jump when the player taps, anywhere on the screen. Small buttons are hard to hit in a fast game, so the whole screen becomes the button.

Think of a doorbell. Pressing it does not open the door by itself. It only tells someone inside, and they decide what to do. A tap is the same: it calls your function, and your function changes the game.

Pressable turns anything into something you can tap. Wrap the whole screen in one, with flex: 1:

<Pressable style={styles.screen} onPressIn={() => setGame((g) => handleTap(g))}>
{/* the world, the square, the obstacle */}
</Pressable>

Pressable has two events you will meet. onPress runs when the finger lifts. onPressIn runs the moment the finger touches. A game wants the jump right away, so we use onPressIn.

handleTap is a plain function, like step. It takes the game and returns the next one:

function handleTap(game) {
if (game.playerY > 0) return game;
return { ...game, playerY: JUMP_HEIGHT };
}

On the ground (playerY is 0) a tap puts the square up at 150. Then the game loop pulls it down, 10 points every tick, until it is back on the ground. That is our first, simple jump. It goes up all at once, which looks a bit rough. The next topic makes it smooth.

People often let the player jump in the air. Without the if, tapping fast sends the square up again and again, and it never comes down. The game becomes too easy, and the player can fly.

When you read touch code in a game, find the Pressable, see which event it uses, and read the function it calls. That function, not the Pressable, decides what the tap does.

Words to recognise
PressableonPressonPressIntouchevent handler

You want the square to jump when the player taps, anywhere on the screen. Small buttons are hard to hit in a fast game, so the whole screen becomes the button.

Think of a doorbell. Pressing it does not open the door by itself. It only tells someone inside, and they decide what to do. A tap is the same: it calls your function, and your function changes the game.

Pressable turns anything into something you can tap. Wrap the whole screen in one, with flex: 1:

<Pressable style={styles.screen} onPressIn={() => setGame((g) => handleTap(g))}>
{/* the world, the square, the obstacle */}
</Pressable>

Pressable has two events you will meet. onPress runs when the finger lifts. onPressIn runs the moment the finger touches. A game wants the jump right away, so we use onPressIn.

handleTap is a plain function, like step. It takes the game and returns the next one:

function handleTap(game) {
if (game.playerY > 0) return game;
return { ...game, playerY: JUMP_HEIGHT };
}

On the ground (playerY is 0) a tap puts the square up at 150. Then the game loop pulls it down, 10 points every tick, until it is back on the ground. That is our first, simple jump. It goes up all at once, which looks a bit rough. The next topic makes it smooth.

People often let the player jump in the air. Without the if, tapping fast sends the square up again and again, and it never comes down. The game becomes too easy, and the player can fly.

When you read touch code in a game, find the Pressable, see which event it uses, and read the function it calls. That function, not the Pressable, decides what the tap does.

Words to recognise
PressableonPressonPressIntouchevent handler