Consolă portabilă stil brick 9999 games

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

„Cărămidă” cu jocuri stil brick 9999 games, cu

  • un afișaj LCD - ar fi nevoie pentru reimplementarea acelor console de 10×20 celule de afișaj + 4×4 celule afișaj secundar - o celulă logică va avea mai mulți pixeli fizici.
  • butoane, joystick cu input analogic pentru inputurile direcționale
  • motor cu vibrații pentru feedback la acțiunile din joc

Propun implemenarea unui nucleu scris în C++, ce va apela fișierele de joc - implementate într-un limbaj dinamic ușor de înglobat în partea compilată (JavaScript), implementând un API abstractizat pentru logica jocurilor a.î. logica jocului să nu se ocupe direct de citirea de registre și alte astfel de detalii.

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ă.

Elemente folosite:

  • RP2040 (microcontrollerul pe care l-am ales)
  • LCD (conectat prin SPI, afișează jocul)
  • Butoane (conectate la GPIO simplu)
  • Joystick (conectat la ADC, 2 axe)
  • Motor de vibrații (conectat la PWM)
  • Nucleu cod C++ (folosește biblioteca Duktape ca interpretor JavaScript, administrează IO-ul)
  • Codul jocurilor în JavaScript (strict logica jocurilor)

Hardware Design

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

  • listă de piese
  • scheme electrice
  • diagrame de semnal
  • rezultatele simulării

Piese folosite:

  • Raspberry Pi Pico W (nu e nevoie de varianta W, dar pe asta o am și pe asta o folosesc)
  • Butoane (3)
  • Joystick (acest model)
  • Motor vibrații (model 1027)
  • Cabluri, breadboard
  • Rezistență (36 Ω - de o valoare pe care o aveam la îndemână, destul de mică, pentru a limita puțin curentului motorului de vibrații)

Schemă electrică:

Software Design

Descrierea codului aplicaţiei (firmware):

  • mediu de dezvoltare (if any) (e.g. AVR Studio, CodeVisionAVR)
  • librării şi surse 3rd-party (e.g. Procyon AVRlib)
  • algoritmi şi structuri pe care plănuiţi să le implementaţi
  • (etapa 3) surse şi funcţii implementate

Codul este disponibil la https://github.com/ALEX11BR/proiect-pm/tree/main/cod-rpipico.

Mediu de dezvoltare

Pentru dezvoltarea codului am folosit Visual Studio Code cu extensia PlatformIO.

Bibloiteci folosite

Ca biblioteci terțe folosite avem:

Las mai jos argumentele pentru folosirea bibliotecilor folosite:

  • Implementarea de la 0 a comunicării cu LCD-ul am considerat că depășește scopul proiectului, așa că am căutat o bibloiotecă care să implementeze randarea pe LCD, una care să poată suporta modelul meu de LCD ce pare a fi ST7735. Bodmer/TFT_eSPI este exact ce căutam.
  • Bodmer/TFT_eSPI folosește API-urile Arduino, așa că se impunea ca proiectul meu să le folosească, prin intermediul implementării pentru Pi Pico - Arduino-Pico
  • Simpla folosire a Arduino IDE și a convențiilor sale de compilare mi se părea un regres mare, fiind obișnuit cu mediile de dezvoltare software unde dependențele pot fi specificate clar într-un fișier aferent, fără să te bazezi pe un mecanism de forma alege biblioteca cutare din interfața IDE-ului și descarc-o într-un folder global tuturor proiectelor.
  • La un moment dat al dezvoltării proiectului s-a manifestat o eroare a platformei implicite PlatformIO pentru Raspberry Pi Pico ce m-a chinuit mult timp (mi se tot apelau interrupt-urile dacă dădeam analogWrite sau ceva de genul), până când am încercat platforma lui maxgerhardt și m-am convins că ea e de folosit cănd folosim PlatformIO pe Raspberry Pi Pico.
  • Pentru ideea de scriere a jocurilor într-un limbaj dinamic am încercat inițial cu Lua, dar inegrarea bibliotecii în proiect era dificilă. Am găsit Duktape ca bibliotecă ușor integrabilă (am pus fișierul (unul singur) .c și cele .h în directorul lib al codului sursă); într-adevăr, pentru JavaScript - o versiune mai veche a limbajului fără anumite caracteristici moderne cu care eram obișnuit din lucrul meu anterior cu JavaScript (let, arrow functions), dar pentru scopul proiectului este suficient.
  • Aveam dorința de a scrie codul JavaScript al jocurilor în fișiere .js, care să fie incluse ulterior în codul C++ ca șiruri de caractere și încărcate în interpretor. Am găsit ca soluție pentru acest lucru funcționalitatea PlatformIO de imagini ale sistemului de fișiere LittleFS cu fișierele aflate în directorul data, unde am pus fișierele .js cu logica jocurilor. Un dezavantaj al acestei abordări este că încărcarea codului pe plăcuță se face în 2 pași (în funcție de ce parte de cod s-a actualizat):
    • Upload pentru încărcarea codului C++ compilat
    • Upload filesystem pentru încărcarea logicii JavaScript a jocurilor
  • Anumite caracteristici ale Raspberry Pi Pico sunt accesibile doar prin API-urile specifice Raspberry Pi Pico SDK (timere, watchdog, restart forțat, alarme).

Jocuri Implementate

  • Snake
    • 4 vieți
    • Controlează șarpele cu joystick-ul în direcția pe care vrei să o ia
      • Se ignoră comenzile de înapoi
    • Cu butonul acțiune se merge mai departe în direcția capului
    • Șarpele se mișcă automat după ce jucătorul l-a mutat manual o dată
    • Șarpele crește când mănâncă mâncarea disponibilă în nivel, moment în care se generează un nou punct cu mâncarea
    • Șarpele moare când se lovește de margini sau de el însuși
  • Drive
    • 4 vieți
    • Controlezi o mașinuță ce trebuie să se ferească de zidurile de pe marginile drumului
      • Stânga-dreapta
    • Mașinuța merge înainte la un interval de timp sau la joystick înainte
    • Zidurile se schimbă periodic

Meniul principal este, de asemenea implementat ca script JavaScript.

Interfața JavaScript

Jocurile au acces la 2 ecrane virtuale, cu celule indexate de la 0:

  • Principal de 10×20 (pentru acțiunea jocului)
  • Secundar de 4×4 (pentru afișarea unor detalii suplimentare, ex. numărul de vieți)

Ecranele au 3 culori:

  • 0 = stins
  • 1 = aprins (negru)
  • 2 = parțial aprins (gri)

Există un sistem de tick-uri care se execută după fiecare TICK_TIME (500) milisecunde

Runtime-ul implementează următoarele funcții:

  • brickVibrate(intensity: number, duration: number) - Motorul cu vibrații va vibra la intensitatea intensity (număr între 0 și 255; 255 = maxim, 180 = valoare intermediară bună) timp de duration milisecunde.
  • brickMainDraw(x: number, y: number, color: number) - desenează pe ecranul principal la celula specificată (linia y, coloana x) culoarea specificată
  • brickSecondaryDraw(x: number, y: number, color: number) - desenează pe ecranul principal la celula specificată (linia y, coloana x) culoarea specificată
  • brickTickReset() - nu se va mai executa tick-ul următor, se va executa peste TICK_TIME milisecunde (dacă nu se mai apelează brickTickReset() încă o dată până atunci)
  • brickGameOver(x: number, y: number, noRestart: boolean) - inițializează ecranul de game over cu „X”-ul în punctul specificat (linia y, coloana x) și vibrație maximă. După un timp se ve reporni jocul în același context (variabilele globale sunt păstrate, dar se va rula handleInit()) dacă noRestart e false, altfel se va reseta consola la meniul principal.
  • brickLoad(gamePath: string) - încarcă jocul din calea specificată din sistemul de fișiere LittelFS încărcat pe plăcuță, resetând contextul JavaScript. Un API „intern”, nu e intenționată folosirea lui în jocuri, doar în meniul de start.

Jocurile trebuie să implementeze următoarele funcții, ce se apelează în cardul unor evenimente relevante în joc:

  • handleInit() - se apelează inițializarea jocului la pornire sau după o pierdere de viață prin brickGameOver(x, y, false). Aici se inițializează variabilele ce indică starea vieții curente. Inițializarea numărului de vieți sau alte chestii ce se păstrează de-a lungul vieților se face direct în corpul scriptului.
  • handleTick() - se apelează la fiecare tick - bun pentru aplicarea mișcărilor automate etc.
  • handleAction() - se apelează la apăsarea butonului acțiune (cel mai din dreapta).
  • handleUp() - se apelează la deplasarea în sus a joystick-ului.
  • handleLeft() - se apelează la deplasarea în stânga a joystick-ului.
  • handleRight() - se apelează la deplasarea în dreapta a joystick-ului.
  • handleDown() - se apelează la deplasarea în jos a joystick-ului.

Aceste funcții nu trebuie să dureze mult, doar cât trebuie pentru a administra evenimentul în cauză. Pentru a încuraja bunele practici, există un watchdog ce nu poate fi resetat de codul Javascript, doar de alte timere interne, care să reseteze consola dacă JavaScriptul durează prea mult.

Rezultate Obţinute

Care au fost rezultatele obţinute în urma realizării proiectului vostru.

Hardware

În cadrul laboratorului am prezentat o versiune cu componentele pe breadboard și cablate conform primei versiuni.

Deoarece după laborator mi-am dat seama că, pentru ca LCD-ul să funcționeze cu biblioteca folosită trebuia să pun pinii de SPI la modulul SPI0 al Raspberry Pi Pico, am rearanjat puțin breadboardul conform schemei finale ilustrate în schema electrică.

Software

Concluzii

A fost o perioadă chinuitoare pentru mine, plină de burn-out, și nu am putut implementa toate jocurile ce le-aș fi dorit, dar am eliminat cam toate obstacolele în implementarea unor jocuri noi. Am reușit să îmi evoluez visul meu de a avea o clonă a acelor console Brick 9999 games cu jocuri implementabile într-un limbaj dinamic, venind cu un API complet pentru scrierea în limbaj dinamic a jocurilor; într-adevăr, optimizat pentru un mediu cu randare lentă a ecranului.

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.

https://github.com/ALEX11BR/proiect-pm

Jurnal

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

Bibliografie/Resurse

Listă cu documente, datasheet-uri, resurse Internet folosite, eventual grupate pe Resurse Software şi Resurse Hardware.

Resurse Hardware

Resurse Software

pm/prj2025/rnedelcu/ioan_alexandru.popa.txt · Last modified: 2025/05/28 17:05 by ioan_alexandru.popa
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