Tetris

Introducere

Prezentarea pe scurt a proiectului vostru:

  • ce face
  • care este scopul lui
  • care a fost ideea de la care aţi pornit
  • de ce credeţi că este util pentru alţii şi pentru voi

This project involves the implementation of the classic Tetris game on an Arduino Uno platform, using an OLED display for graphical output, physical buttons for controlling the game pieces, and a buzzer to provide audio feedback. The system is designed to be fully interactive and responsive, replicating the retro gameplay experience using minimal hardware resources.

The main goal was to create a complete and functional embedded game that integrates basic peripherals and reinforces practical skills acquired during PM labs. The idea stemmed from our desire to bring a nostalgic game to life using modern embedded techniques, showcasing how even simple microcontrollers can be used to recreate iconic games. It also serves as a valuable educational tool—for ourselves, as a learning opportunity in hardware-software integration, and for others, as a straightforward example of an embedded application that is both engaging and technically relevant.

Descriere generală

O schemă bloc cu toate modulele proiectului vostru, atât software cât şi hardware însoţită de o descriere a acestora precum şi a modului în care interacţionează.

Exemplu de schemă bloc: http://www.robs-projects.com/mp3proj/newplayer.html

Module Descriptions:

  • User Input (Buttons):
    Four physical push buttons allow the player to control the game: one to move the Tetris piece left, one to move it right, one to rotate it, and one to start or restart the game.

  • Input Handler (GPIO):
    Reads the state of each button using digital input pins. It debounces the signals if necessary and forwards user actions to the game logic (e.g., move, rotate, or start the game).

  • Game Logic Manager:
    The core of the application. It manages the game state including piece positions, rotation, collision detection, grid updates, score keeping, level tracking, and game over conditions. It responds to user input and controls overall game progression.

  • Display Controller (OLED - I2C):
    Handles visual output on a 128x64 OLED display using the I2C protocol. It renders the playing field, active and next pieces, player score, and other visual elements in real time according to the game state.

  • Sound Feedback (Buzzer - PWM):
    Provides audio feedback using PWM-generated tones for key game events such as piece rotation, line clearance, and game over notifications.

  • Hardware Design

    Aici puneţi tot ce ţine de hardware design:

    Component List

  • Arduino Uno
  • OLED Display 128x64 (I2C)
  • 4x Push Buttons
  • Breadboard
  • Buzzer
  • Pull-down Resistors (≈10kΩ)
  • Bill of Materials

    Interfețe utilizate:

    I2C – pentru comunicarea cu ecranul OLED (pinii A4 și A5)

    PWM (modulare a lățimii impulsului) – pentru redarea de sunete prin buzzer (pinul D6)

    GPIO – pentru citirea butoanelor (pinii D7, D8, D9, D10)

    Schema electrica

    Circuit electric

    Componente utilizate și rolul lor:

    - Arduino Uno – Microcontrolerul principal care citește semnalele de la senzori și butoane, procesează logica stărilor și controlează afișajul și buzzerul.

    - Display OLED 128×64 (I2C) – Afișează starea jocului de Tetris. Este conectat la interfața I2C a plăcii Arduino (SDA la A4, SCL la A5).

    - Buzzer pasiv – Conectat la pinul D6 (compatibil PWM), este utilizat pentru a reda muzica de fundal.

    - 4 butoane push – Conectate la pinii digitali D7, D8, D9 și D10, fiecare cu o rezistență de 10kΩ spre GND (configurație pull-down). Sunt folosite pentru: start/restart joc, miscare stanga, miscare dreapta, rotire.

    Toate componentele sunt alimentate de la 5V și GND.

    Interfețe utilizate:

    I2C – pentru comunicarea cu ecranul OLED (pinii A4 și A5)

    PWM (modulare a lățimii impulsului) – pentru redarea de sunete prin buzzer (pinul D6)

    GPIO – pentru citirea butoanelor (pinii D7, D8, D9, D10)

    Pini Folositi

    Componentă Pin Arduino Motivul alegerii
    OLED Display A4 (SDA), A5 (SCL) Pini dedicați pentru interfața I2C
    Buzzer D6 Pin digital compatibil PWM pentru `tone()`
    Button 1–4 D7, D8, D9, D10 Pini digitali disponibili, ușor de gestionat în cod

    Dovada functionare

    Software Design

    Mediu de Dezvoltare

    Proiectul este dezvoltat în Arduino IDE, utilizând limbajul C++. Arduino IDE oferă un mediu prietenos pentru programare, testare și încărcare rapidă a codului pe placă. Am folosit bibliotecile standard Arduino, precum și unele biblioteci externe pentru controlul componentelor I2C și OLED.

    Testarea și depanarea au fost realizate prin monitorul serial și feedback vizual/audio.

    Motivarea alegerii bibliotecilor

    Adafruit_SSD1306 și Adafruit_GFX

    Folosite pentru controlul ecranului OLED prin I2C. Oferă funcții pentru afișarea de text, pictograme și animații simple. Funcții utilizate:

    - display.begin(): inițializează ecranul

    - display.clearDisplay(): șterge conținutul ecranului

    - display.setCursor(), display.print(): pentru afișare de text

    - drawBitmap(): pentru afișarea pictogramelor

    Wire.h

    Folosită pentru comunicarea I2C cu ecranul OLED.

    Justificarea folosirii funcționalităților de laborator

    Funcționalități integrate:

    - I2C – comunicarea cu afișajul OLED.

    - GPIO – pentru citirea butonului.

    - PWM – buzzer: redarea de tonuri diferite prin tone().

    Modul de Validare a Funcționalităților

    - Fiecare buton a fost testat individual – acționând stări diferite în managerul de stare.

    - OLED-ul a fost validat cu mesaje și pictograme pentru fiecare stare.

    - Feedback-ul audio a fost testat prin acționări repetitive și schimbări de stare.

    - Comportamentul în timp real a fost verificat în sesiuni complete de testare.

    Scheletul Proiectului și Interacțiunea Funcționalităților: Joc Tetris pe Arduino

    Arhitectura Principală

    Proiectul implementează un joc clasic Tetris pe un microcontroller Arduino, utilizând un display OLED SSD1306 și butoane fizice. Logica principală este centralizată în loop(), gestionând stările jocului și interacțiunile.

    Inițializare și Intro

    setup(): Configurează pinii hardware (butoane, speaker) → Inițializează comunicarea serială și display-ul OLED (display.begin()) → Afișează ecrane introductive: “Loading…” → “TETRIS” → logo-ul mantex_logo (din `PROGMEM`) → Inițializează generatorul de numere aleatoare (randomSeed()) → Generează prima piesă (nextType = random(TYPES); generate()) → Setează timer-ul principal și variabilele de debounce → starea principală a jocului.

    Starea Principală (gestionată prin flag-ul boolean `isGameOver` și timer-ul `timer`):
    • isGameOver: monitorizează dacă jocul s-a încheiat.
      • Dacă `true`: afișează “GAME OVER” și scorul (display.println(F(“GAME OVER”)); … display.print(score);).
    • timer și interval: Controlează căderea automată a pieselor.
      • Dacă jocul nu este terminat (`!isGameOver`):
        • checkLines(): Verifică și elimină liniile complete.
        • refresh(): Redesenează starea curentă a jocului (grilă, piesa curentă, scor, piesa următoare).
        • nextCollision(): Verifică dacă piesa curentă a atins obstacol.
          • Dacă da: fixează piesa pe grilă (`grid[…]=1;`), generează o nouă piesă (generate()).
          • Verifică imediat dacă noua piesă cauzează Game Over (nextHorizontalCollision(piece, 0) && pieceY == 0).
          • Dacă nu: piesa coboară (`pieceY++`).
    Sistem de Evenimente:
    • digitalRead(left): Deplasează piesa la stânga (pieceX–) + verificare coliziune (!nextHorizontalCollision(piece, -1)) + feedback sonor (tone(SPEAKER_PIN, click…)).
    • digitalRead(right): Deplasează piesa la dreapta (pieceX++) + verificare coliziune (!nextHorizontalCollision(piece, 1)) + feedback sonor.
    • digitalRead(change): Rotește piesa (rotation++ sau `rotation = 0`) + verificare validitate rotație (canRotate()) + actualizează forma (copyPiece()) + feedback sonor.
    • digitalRead(restart): Resetează grila, scorul, generează o nouă piesă, resetează isGameOver.
    • Cădere Automată Piesă (bazată pe timer > interval): Declanșează logica de avansare a piesei (pieceY++ sau fixare și generare nouă piesă).

    Fluxul Principal de Execuție

    setup() → Afișare ecrane introductive (“Loading…”, “TETRIS”, mantex_logo) →

    • Buclă principală loop():
      • Dacă isGameOver este `true`:
        • Afișează ecranul “GAME OVER” cu scorul final.
      • Dacă isGameOver este `false` (Joc Activ):
        • Verificare Timer Cădere Piesă (millis() - timer > interval):
          • checkLines()refresh() → Verificare coliziune pentru piesa nou generată (potențial Game Over).
          • Dacă nextCollision() este `true`: Fixează piesa, generate().
          • Altfel: pieceY++.
          • Resetează timer.
        • Verificare Butoane:
          • digitalRead(left) → Acțiune mișcare stânga + refresh().
          • digitalRead(right) → Acțiune mișcare dreapta + refresh().
          • digitalRead(change) → Acțiune rotație + refresh().
          • digitalRead(restart) → Acțiune restart joc + refresh().

    Modul de Validare a Funcționalităților

    Testare unitară pe componente:
    • Fiecare funcție de desenare (drawGrid(), drawPiece(), drawLayout(), drawNextPiece()) testată vizual pe display-ul OLED.
    • Butoanele (left, right, change, restart) testate individual, observând răspunsul piesei și feedback-ul sonor. Serial Monitor utilizat pentru debug.
    • Logica de detecție a coliziunilor (nextCollision(), nextHorizontalCollision()) și rotație (canRotate(), getMaxRotation()) verificate prin interacțiune directă.
    Testare integrată:
    • Sesiuni complete de joc pentru verificarea evoluției scorului, eliminării liniilor (breakLine()) și tranziției la “Game Over”.
    • Test de rezistență cu apăsări rapide ale butoanelor pentru debounce.
    • Validarea funcției de restart și reluarea corectă a jocului.

    Calibrarea Elementelor de Senzoristică (Adaptat pentru Parametrii de Joc)

    Parametrii de joc, nu senzori fizici, definesc experiența.

    Proces de calibrare experimentală (pentru parametrii de joc):
    • Măsurători (teste de joc) cu diferite valori pentru interval (viteza de cădere).
    • Valoarea interval = 250 (ms) aleasă pentru un echilibru inițial.
    • Debounce-ul butoanelor și delay(100) pentru sunete ajustate empiric.
    Justificarea pragului (pentru parametrii aleși):
    • interval = 250: Oferă un ritm de joc antrenant, dar jucabil.
    • Dimensiunile SIZE, MARGIN_TOP, MARGIN_LEFT: Optimizate pentru lizibilitatea pe display-ul 128×64.
    • Debounce-ul (flag-uri `b1, b2, b3` și `delayer`): Reduce acțiunile multiple la o singură apăsare.

    Optimizări Realizate

    Optimizări de Performanță

    Cea mai importantă abordare este utilizarea millis() pentru timer-ul jocului (timer), permițând procesarea input-ului între căderile pieselor. Bitmap-ul mantex_logo este stocat în `PROGMEM`. Display-ul este reîmprospătat prin refresh() (incluzând display.clearDisplay()).

    Optimizări de Cod și Arhitectură

    Structura codului este modulară (ex: drawGrid(), checkLines(), generate(), copyPiece()). Utilizarea constantelor (`#define`, `const`) îmbunătățește lizibilitatea. Funcția copyPiece() centralizează logica formei pieselor.

    Optimizări de UX

    Feedback audio (tone()) pentru acțiuni și evenimente (breakLine()). Afișarea piesei următoare (drawNextPiece()) și a scorului. Sistem de debounce pentru butoane. Funcția de restart include protecție la apăsare lungă.

    Rezultate Obţinute

    Proiectul a fost finalizat cu succes, rezultând într-o versiune funcțională a jocului Tetris pe Arduino. Am implementat mecanismele de bază: generarea și controlul pieselor, detecția coliziunilor, eliminarea liniilor, scorul și “Game Over”. Sistemul rulează pe hardware, butoanele răspund, iar display-ul afișează corespunzător.

    Concluzii

    Realizarea acestui Tetris a fost o experiență valoroasă în programarea embedded și designul de jocuri simple. Am experimentat cu gestionarea stărilor, interacțiunea hardware și afișarea grafică. Procesul de debugging, în special pentru logica de coliziune și rotație, a fost o lecție importantă.

    Download

    O arhivă (sau mai multe dacă este cazul) cu fişierele obţinute în urma realizării proiectului: surse, scheme, etc. Un fişier README, un ChangeLog, un script de compilare şi copiere automată pe uC crează întotdeauna o impresie bună ;-).

    Fişierele se încarcă pe wiki folosind facilitatea Add Images or other files. Namespace-ul în care se încarcă fişierele este de tipul :pm:prj20??:c? sau :pm:prj20??:c?:nume_student (dacă este cazul). Exemplu: Dumitru Alin, 331CC → :pm:prj2009:cc:dumitru_alin.

    Jurnal

    Puteți avea și o secțiune de jurnal în care să poată urmări asistentul de proiect progresul proiectului.

    Bibliografie/Resurse

    pm/prj2025/avaduva/alex.dobritan.txt · Last modified: 2025/05/27 21:53 by alex.dobritan
    CC Attribution-Share Alike 3.0 Unported
    www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0