ARDUINO WERKPLAATS
◂ het slotstuk — gebruikt 01, 02 & 03 Project 04 · alles samen

Speel met je hand
in de lucht.

Het slotstuk. We bouwen een spel waarin je een blokje omhoog en omlaag beweegt door je hand dichter bij of verder van de afstandssensor te houden — en de blokjes ontwijkt die op je afkomen. Geen knoppen, geen joystick: puur je hand in de lucht.

Besturing: je hand Combineert: scherm + afstand ~40 min
Welk bord gebruik je?
Alle pinnen uit projecten 01–03 blijven zoals ze zijn.
Welk scherm gebruik je?
Alle sketches op deze pagina wisselen mee naar het scherm dat jij hebt.
0

Wat je nodig hebt

  • 1.44 inch TFT-scherm Je 1.44" TFT-scherm, aangesloten zoals in project 01.
  • 0.96 inch OLED-schermpje Je 0.96" OLED-schermpje, aangesloten zoals in de OLED-start — vier draadjes via I2C.
  • HC-SR04 afstandssensor De HC-SR04 afstandssensor (project 02, op D6/D7).
  • Verder niets nieuws. We hergebruiken alles wat al aangesloten is.
Pinnen bij elkaar Je TFT gebruikt D8/D9/D10 plus de klok/data-pinnen — op de R4 zijn dat D13/D11. De sensoren op D6, D7 en A2 komen daar los naast te zitten.
Pinnen bij elkaar Je OLED gebruikt alleen de I2C-pinnen SDA/SCL (of A4/A5) plus 5V en GND. D6, D7 en A2 blijven dus helemaal vrij voor de sensoren.
Dit is een samenvatting-project Je leert hier geen nieuw onderdeel, maar hoe je losse stukjes tot één ding samenvoegt — precies wat "iets bouwen" eigenlijk is. Herken de brokjes uit de vorige projecten terug.
1

Het idee

Een groen blokje zweeft aan de linkerkant van het scherm. De hoogte ervan bepaal jij met je hand boven de sensor: hand dichtbij = blokje omhoog, hand ver weg = blokje omlaag. Van rechts komen rode blokjes aangeschoven. Laat ze niet je blokje raken; elk blokje dat je ontwijkt is een punt.

Een gevuld staafje zweeft aan de linkerkant van het scherm. De hoogte ervan bepaal jij met je hand boven de sensor: hand dichtbij = staafje omhoog, hand ver weg = staafje omlaag. Van rechts komen kleine open vierkantjes aangeschoven. Laat ze niet je staafje raken; elk vierkantje dat je ontwijkt is een punt.

Geen kleur? Gebruik vorm. Op de OLED is alles wit. Het verschil tussen "jij" en "gevaar" maak je daarom met vorm en grootte: jij bent een hoog, gevuld staafje, de hindernissen zijn kleine omlijnde vierkantjes. Dat leest op zo'n klein schermpje zelfs sneller dan groen-tegen-rood.
sensor omhoog/ omlaag Score: 5
Je hand is de joystick — zonder de joystick.
sensor omhoog/ omlaag Score: 5 128 x 64 pixels — alles wit op zwart
Maar 64 pixels hoog: het speelveld begint onder de scorebalk, op y = 10.
2

Je hand als schuifknop

De kern is één regel die je al kent uit project 02: we meten de afstand en zetten die met map() om naar een hoogte op het scherm. Dat is de hele besturing.

de besturing in het kort
long cm = leesAfstand();               // hoe ver is je hand? (project 02)
cm = constrain(cm, 5, 40);             // houd het tussen 5 en 40 cm
spelerY = map(cm, 5, 40, 14, 110);     // dichtbij -> boven, ver -> onder
de besturing in het kort
long cm = leesAfstand();               // hoe ver is je hand? (project 02)
cm = constrain(cm, 5, 40);             // houd het tussen 5 en 40 cm
spelerY = map(cm, 5, 40, 10, 52);      // dichtbij -> boven, ver -> onder

Waarom 10 en 52? Het scherm is maar 64 pixels hoog. Boven laten we 10 pixels vrij voor de score, en het staafje is zelf 12 pixels hoog — dus de laagste stand is 64 − 12 = 52. Zo kan je speler nooit half buiten beeld zakken.

Waarom 5 tot 40 cm? Onder de 5 cm wordt de meting onbetrouwbaar, en boven ~40 cm is het onhandig ver reiken. Binnen dat bereik voelt de besturing lekker soepel. Voel je dat je te ver moet reiken? Maak van 40 gerust 30.
3

Het complete spel

Hier is alles bij elkaar. Plak het als geheel in de Arduino IDE en upload. Houd je hand boven de sensor en ontwijk de rode blokjes. Ben je af? Houd je hand vlak bij de sensor om opnieuw te starten.

hand_dodger.ino
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include <SPI.h>

#define TFT_CS 10
#define TFT_RST 9
#define TFT_DC 8
#define TRIG 6
#define ECHO 7

Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);

// --- speler (links) ---
const int SPELER_X = 6, SPELER_B = 10, SPELER_H = 18;
int spelerY = 60, vorigeY = 60;

// --- hindernis (van rechts) ---
int hindX, hindY, vorigeHindX = 120;
int snelheid = 3;
int score = 0;
bool gameOver = false;

long leesAfstand() {
  digitalWrite(TRIG, LOW);  delayMicroseconds(2);
  digitalWrite(TRIG, HIGH); delayMicroseconds(10);
  digitalWrite(TRIG, LOW);
  long duur = pulseIn(ECHO, HIGH, 30000);
  if (duur == 0) return 40;             // niets gezien -> "ver"
  return duur * 0.034 / 2;
}

void nieuweHindernis() {
  hindX = 122;
  hindY = random(14, 128 - 8);
}

void toonScore() {
  tft.fillRect(0, 0, 128, 12, ST77XX_BLACK);
  tft.setCursor(2, 2);
  tft.setTextSize(1);
  tft.setTextColor(ST77XX_WHITE);
  tft.print("Score: ");
  tft.print(score);
}

void resetSpel() {
  score = 0; snelheid = 3; gameOver = false;
  spelerY = vorigeY = 60;
  tft.fillScreen(ST77XX_BLACK);
  nieuweHindernis();
  vorigeHindX = hindX;
  toonScore();
}

void setup() {
  pinMode(TRIG, OUTPUT);
  pinMode(ECHO, INPUT);
  tft.initR(INITR_144GREENTAB);
  randomSeed(analogRead(A5));
  resetSpel();
}

void loop() {
  if (gameOver) {
    if (leesAfstand() < 10) { delay(300); resetSpel(); }   // hand dichtbij = opnieuw
    return;
  }

  // --- 1. hand bepaalt de hoogte ---
  long cm = constrain(leesAfstand(), 5, 40);
  spelerY = map(cm, 5, 40, 14, 128 - SPELER_H);

  // --- 2. hindernis verplaatsen ---
  tft.fillRect(vorigeHindX, hindY, 8, 8, ST77XX_BLACK);     // wis oude
  hindX -= snelheid;
  tft.fillRect(hindX, hindY, 8, 8, ST77XX_RED);             // teken nieuwe
  vorigeHindX = hindX;

  // --- 3. speler (laatst getekend = altijd bovenop) ---
  tft.fillRect(SPELER_X, vorigeY, SPELER_B, SPELER_H, ST77XX_BLACK);
  tft.fillRect(SPELER_X, spelerY, SPELER_B, SPELER_H, ST77XX_GREEN);
  vorigeY = spelerY;

  // --- 4. botsing of ontweken? ---
  bool xRaakt = (hindX < SPELER_X + SPELER_B) && (hindX + 8 > SPELER_X);
  bool yRaakt = (hindY < spelerY + SPELER_H) && (hindY + 8 > spelerY);

  if (xRaakt && yRaakt) {
    gameOver = true;
    tft.fillScreen(ST77XX_BLACK);
    tft.setTextSize(2); tft.setTextColor(ST77XX_RED);
    tft.setCursor(10, 40); tft.println("GAME");
    tft.setCursor(10, 60); tft.println("OVER");
    tft.setTextSize(1); tft.setTextColor(ST77XX_WHITE);
    tft.setCursor(10, 92);  tft.print("Score: "); tft.print(score);
    tft.setCursor(10, 106); tft.print("Hand dichtbij = opnieuw");
    return;
  }

  if (hindX + 8 < SPELER_X) {          // helemaal voorbij zonder raken
    score++;
    toonScore();
    if (snelheid < 7) snelheid++;      // wordt sneller
    nieuweHindernis();
    vorigeHindX = hindX;
  }

  delay(30);
}

Hier is alles bij elkaar. Plak het als geheel in de Arduino IDE en upload. Houd je hand boven de sensor en ontwijk de vierkantjes. Ben je af? Houd je hand vlak bij de sensor om opnieuw te starten.

Eén groot verschil met het kleurenscherm Op de TFT wis je alleen de oude plek van een blokje zwart en teken je het opnieuw. Op de OLED doe je dat niet: je begint elke ronde met oled.clearDisplay(), tekent het hele beeld opnieuw en zet het met oled.display() in één klap op het scherm. Geen "vorige positie" onthouden dus — dat scheelt een hoop code, en flikkeren doet het niet.
hand_dodger_oled.ino
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define TRIG 6
#define ECHO 7

Adafruit_SSD1306 oled(128, 64, &Wire, -1);

// het scherm is 128 x 64: bovenaan 10 pixels voor de score,
// daaronder het speelveld van y = 10 tot y = 63
const int VELD_TOP = 10;

// --- speler (links): een hoog, GEVULD staafje ---
const int SPELER_X = 4, SPELER_B = 6, SPELER_H = 12;
int spelerY = 30;

// --- hindernis (van rechts): een klein, OMLIJND vierkantje ---
const int HIND = 7;
int hindX, hindY;
int snelheid = 3;
int score = 0;
bool gameOver = false;

long leesAfstand() {
  digitalWrite(TRIG, LOW);  delayMicroseconds(2);
  digitalWrite(TRIG, HIGH); delayMicroseconds(10);
  digitalWrite(TRIG, LOW);
  long duur = pulseIn(ECHO, HIGH, 30000);
  if (duur == 0) return 40;             // niets gezien -> "ver"
  return duur * 0.034 / 2;
}

void nieuweHindernis() {
  hindX = 121;                          // 121 + 7 = 128: net binnen de rechterrand
  hindY = random(VELD_TOP, 64 - HIND + 1);   // 10 t/m 57, dus altijd in beeld
}

void resetSpel() {
  score = 0; snelheid = 3; gameOver = false;
  spelerY = 30;
  nieuweHindernis();
}

void setup() {
  pinMode(TRIG, OUTPUT);
  pinMode(ECHO, INPUT);
  oled.begin(SSD1306_SWITCHCAPVCC, 0x3C);   // adres 0x3C (soms 0x3D)
  oled.setTextColor(SSD1306_WHITE);
  randomSeed(analogRead(A0));
  resetSpel();
}

void loop() {
  if (gameOver) {
    if (leesAfstand() < 10) { delay(300); resetSpel(); }   // hand dichtbij = opnieuw
    delay(50);
    return;
  }

  // --- 1. hand bepaalt de hoogte ---
  long cm = constrain(leesAfstand(), 5, 40);
  spelerY = map(cm, 5, 40, VELD_TOP, 64 - SPELER_H);   // 10 ... 52

  // --- 2. hindernis opschuiven ---
  hindX -= snelheid;

  // --- 3. botsing? twee rechthoeken raken elkaar als ze
  //        en horizontaal en verticaal overlappen ---
  bool xRaakt = (hindX < SPELER_X + SPELER_B) && (hindX + HIND > SPELER_X);
  bool yRaakt = (hindY < spelerY + SPELER_H) && (hindY + HIND > spelerY);

  if (xRaakt && yRaakt) {
    gameOver = true;
    oled.clearDisplay();
    oled.setTextSize(2);
    oled.setCursor(8, 8);  oled.print("GAME OVER");
    oled.setTextSize(1);
    oled.setCursor(8, 34); oled.print("Score: "); oled.print(score);
    oled.setCursor(8, 46); oled.print("Hand dichtbij");
    oled.setCursor(8, 55); oled.print("= opnieuw");
    oled.display();
    return;
  }

  // --- 4. helemaal voorbij zonder raken? punt! ---
  if (hindX + HIND < SPELER_X) {
    score++;
    if (snelheid < 7) snelheid++;       // wordt sneller
    nieuweHindernis();
  }

  // --- 5. het hele beeld opnieuw tekenen ---
  oled.clearDisplay();
  oled.setTextSize(1);
  oled.setCursor(0, 0);
  oled.print("Score: ");
  oled.print(score);
  oled.drawRect(hindX, hindY, HIND, HIND, SSD1306_WHITE);          // omlijnd = gevaar
  oled.fillRect(SPELER_X, spelerY, SPELER_B, SPELER_H, SSD1306_WHITE);  // gevuld = jij
  oled.display();                       // <-- nu pas zichtbaar

  delay(30);
}
4

Uitleg per onderdeel

Elk stukje komt uit een eerder project — nu klikken ze in elkaar:

leesAfstand()
Exact de functie uit project 02. We hoefden hem niet opnieuw te bedenken.
map + constrain
Zet de gemeten centimeters om naar een schermhoogte — dezelfde truc als de balk in project 02.
tekenen
De animatie-aanpak van jouw scherm: op de TFT wis je de oude plek zwart en teken je de nieuwe (project 01); op de OLED maak je het kladblok leeg en teken je elke ronde het hele beeld opnieuw (de OLED-start).
botsing (xRaakt/yRaakt)
Twee rechthoeken overlappen als ze én horizontaal én verticaal overlappen. Dat check je met vier vergelijkingen.
Reageert het blokje omgekeerd? Wil je juist "hand omhoog = blokje omhoog"? Draai dan in de map(...)-regel de twee laatste getallen om: map(cm, 5, 40, 110, 14).
Reageert het staafje omgekeerd? Wil je juist "hand omhoog = staafje omhoog"? Draai dan in de map(...)-regel de twee laatste getallen om: map(cm, 5, 40, 52, VELD_TOP).
5

Waar nu heen?

Je hebt de hele reeks doorlopen: scherm, sensoren, een weerstation en een spel dat alles combineert. Ideeën om verder te gaan:

  • Voeg levens toe (bijv. 3 harten bovenin) in plaats van meteen game over.
  • Laat de snelheid en het aantal hindernissen oplopen voor een echte uitdaging.
  • Bouw een startmenu en onthoud je highscore.
  • Verzin een heel nieuw spel met dezelfde bouwstenen — een reactietest, een "houd de bal in de lucht", of iets waarbij je met de IR-sensor zwaait.
De belangrijkste les Elk groot project is gewoon een stapel kleine, begrepen stukjes. Je hebt nu een gereedschapskist: een sensor lezen, iets omrekenen met map, en tekenen & wissen. Daar bouw je alles mee.

Klaar met de reeks

Mooi gebouwd 🎉

Van een los rood printje naar een hands-free spel. Alle projecten blijven staan om terug te lezen — en er is altijd ruimte voor een volgende in de werkplaats.

← Project 03  ·  Alle projecten