This is an old revision of the document!


Student: Andrei Petrea
Grupa: 331CC

PacMan

Introducere

PacMan este un joc arcade dezvoltat de compania Namco in anul 1980, fiind considerat unul dintre cele mai influente jocuri din toate timpurile, fiind responsabil pentru popularizarea jocurilor arcade si a jocurilor video in constientul maselor, generand venituri de 14 miliarde de dolari si vanzand peste 43 de milioane de unitati.

Scopul proiectului meu este sa portez acest joc, de pe arcade pe un chip Arduino, pentru a ma putea juca acest joc intr-un mod cat mai autentic cu masina originala cu care venea odinioara. Ma voi folosi de butoane, ecran lcd, difuzor si led-uri pentru a realiza acest lucru.

Descriere generală

Voi folosi un Arduino Uno pe post de unitate de procesare, la care voi atasa un ecran de 1.8” LCD pentru a afisa jocul, un speaker pentru a canta melodii si 5 butoane pentru a controla cele 4 directii (sus, jos, stanga, dreapta) + buton de start. Ecranul vine si cu un adaptor SD prin intermediul caruia care voi afisa imagine de start. La final ma voi folosi de un LED RGB pentru a afisa finalul (RED - pierdere, BLUE - castig).

Hardware Design

Lista de piese

  • Arduino Uno R3 ATMega328P
  • Ecran LCD 1.8” SPI
  • DFROBOT - FIT0449 - Add-On Board, Speaker Module, Gravity Series, Arduino, Digital Interface
  • Modul adaptor SD
  • 5x Butoane
  • Modul LED RGB
  • Breadboard
  • Fire Jumper
  • Rezistente

Schema electrica

Pinii folositi

  • Butoanele - cele 5 butoane vor fi conectate la accelasi pin analogic A0, folosindu-ma de ADC pentru am-mi da seama ce buton este apasat.
  • Ecran LCD 1.8” SPI - ecranul foloseste SPI, asa ca voi trebuie sa conectez pinii MOSI, MISO si CS, puse pe pinii 11, 12, si 10 respectiv. Pe langa acestia, voi connect pinul de clock SCK la 13, la fel si pinul SCL, iar pinul SDA la 11, la fel ca cel MOSI. Pinul de reset va fi la pinul 8 iar A0 la pinul 9.
  • Modul SD - acesta vine integrat cu ecranul, asa ca toti pinii lui SPI vor fi cei ai ecranului, cu exceptia CS-ului pe care l-am setat pe pinul 4.
  • Speaker - Acesta vine cu o interfata Gravity, care are 3 pinii: GND, VCC si Signal, acest din urma mergand conectat la orice pin digital, asa ca am ales pinul 7.
  • Modulul LED RGB - il voi connecta la 3 pini digital cu PWM, acestia fiind 5, 3 si 6.

Forma Initiala

pacman_initial_design.jpeg

Forma Finala

pacman_schema_finala.jpeg

Software Design

Mediu de dezvoltare

Arduino IDE, limbaj C/C++

Biblioteci folosite

  • SD.h → folosita pentru interfatarea cu cardul SD
  • TFT.h → folosita pentru afisarea pe display
  • SPI.h → folosita pentru SD
  • tone(), noTone() → pentru speaker
  • Arduino Songs → pentru melodia PacMan clasica

Descrierea implementarii

Structura unui obiect

Pentru a opera mai usor cu logica jocului, mi-am creat structura PacmanObject, care contine 4 campuri

  • x → abscisa obiectului
  • y → ordonata obiectului
  • draw → flag pentru afisarea la ecran
  • symbol → ce afisez la ecran
struct PacmanObject {
  int16_t x;
  int16_t y;
  bool draw;
  String symbol;
};
Start-up screen

La inceput, afisez o imagine sugestiva cu PacMan, acompaniata de muzica clasica si aprinderea led-ului in culoarea Verde. In cazul in care apar erori la incarcarea imaginii, voi afisa un mesaj pe ecran.

void intro() {
  if (!imageError) {
    TFTscreen.image(logo, 20, 25);
  } else {
    TFTscreen.text("Va saluta", 40, 64);
    TFTscreen.text("Andrei", 64, 90);
  }
  analogWrite(PIN_GREEN, 64);
  playPacmanIntro();
  TFTscreen.text("Press START", 18, 85);
}
Game Loop

Ca sa inceapa jocul, jucatorul trebuie sa apese butonul de START (butonul din centru), care va crea o noua arena, plasand PacMan-ul in centru ei, si plasand 4 inamici si 7 puncte aleatoriu pe harta.

void loop()
{
  int value = analogRead(A0);
  if (!gameStarted) {
    if (checkRange(value, 260, 330)) {
      gameStarted = true;
      gameOver = false;
      ateAll = false;
      score = 0;
      initBoard();
      analogWrite(PIN_RED, 0);
      analogWrite(PIN_BLUE, 0);
      analogWrite(PIN_GREEN, 64);
    }
  }
  // Rest of code...
}

Pentru realizarea randomizarii pozitiilor, am folosit functiile rand si srand din biblioteca standard C, seed-ul pe care l-am ales fiind obtinut prin citirea unui pin analogic neconectat (in cazul meu, A1).

void setup()
{
  // Rest of code...
  srand(analogRead(A1));
}

Odata intrat in joc, ne putem deplasa UP, DOWN, LEFT si RIGHT prin apasarea celor 4 butoane, dispuse conform celor 4 puncte cardinale. In functie de care buton a fost apasat, voi apela functia move, care are ca argument, deplasarea pe care i-o voi da PacMan-ului.

void loop()
{
   // Rest of code...
   if (!gameOver) {
      draw();
      if (checkRange(value, 120, 170)) {
        move(0, -1);
      } else if (checkRange(value, 190, 230)) {
        move(-1, 0);
      } else if (checkRange(value, 420, 500)) {
        move(1, 0);
      } else if (checkRange(value, 900, 1024)) {
        move(0, 1);
      }
    } 
      // Rest of code...
}

In functia move, voi muta PacMan-ul la pozitia noua, si voi calcula folosind functia checkCollision, daca ma intersectez cu obiectul de tip FOOD sau cu ENEMY. Ma voi folosi si de functia checkRange, pentru a oferi toleranta la detectia coliziunii.

bool checkCollision(PacmanObject obj1, PacmanObject obj2) {
  return (checkRange(obj1.x, obj2.x - 2, obj2.x + 2) && checkRange(obj1.y, obj2.y - 2, obj2.y + 2) && checkRange(obj2.x, obj1.x - 2, obj1.x + 2) && checkRange(obj2.y, obj1.y - 2, obj1.y + 2));
}
 
bool checkRange(int val, int low, int high) {
  return (val >= low && val <= high);
}
 
 

Inedit, pentru inamici, am folosit un algoritm de tip Hill-Climbing, care este apelat atunci cand jucatorul face o mutare, facand ca acestia sa se deplaseze catre PacMan. Fiecare inamic se va uita la starile sale vecine (UP, DOWN, LEFT, RIGHT in ordinea aceasta) si va alege prima stare mai apropiata decat pozitia sa curenta, folosind distanta Manhattan ca euristica.

void move(int16_t dx, int16_t dy)
{
   // Rest of code...
   for (i = 0; i < NR_ENEMIES; i++) {
    int8_t j, k;
    int16_t currDistance = manhattanDistance(pacMan, enemies[i]);
    PacmanObject aux;
    for (j = -1; j <= 1; j++) {
      bool ok = true;
      for (k = -1; k <= 1; k++) {
        if (abs(j) != abs(k)) {
          aux.x = enemies[i].x + j;
          aux.y = enemies[i].y + k;
          int16_t distance = manhattanDistance(pacMan, aux);
          if (distance < currDistance) {
            enemies[i].x = aux.x;
            enemies[i].y = aux.y;
            ok = false;
            break;
          }
        }
      }
      if (!ok) {
        break;
      }
    }
  }
}
}
 
int16_t manhattanDistance(PacmanObject obj1, PacmanObject obj2) {
  return (abs(obj2.x - obj1.x) + abs(obj2.y - obj1.y));
}

Rezultate Obţinute

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

Concluzii

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

  • 27.04 - Initializat pagina de proiect
  • 03.05‎‎ - Adaugat documentatia initiala
  • 05.05 - Adaugat imaginea de coperta
  • 16.05 - Adaugat schema electrica + detalii pini + jurnal
  • 19.05 - Adaugat legarea initiala
  • 21.05 - Adaugat design software initial + bibliografie + legarea finala

Bibliografie/Resurse

Resurse Hardware

Resurse Software

pm/prj2024/vstoica/andrei.petrea1210.1716667213.txt.gz · Last modified: 2024/05/25 23:00 by andrei.petrea1210
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