Differences

This shows you the differences between two versions of the page.

Link to this comparison view

pm:prj2025:fstancu:sebastian.badea0506 [2025/05/17 11:54]
sebastian.badea0506 created
pm:prj2025:fstancu:sebastian.badea0506 [2025/05/25 23:26] (current)
sebastian.badea0506
Line 1: Line 1:
-====== Pacman ======+====== Pacman ​- Badea Sebastian-Mihail ​======
 **Autor:** Badea Sebastian-Mihail\\ **Autor:** Badea Sebastian-Mihail\\
-**Grupa:​** ​332CD\\+**Grupa:​** ​341C4\\
 **Îndrumător:​** Florin Stancu **Îndrumător:​** Florin Stancu
  
Line 14: Line 14:
 ===== Hardware Design ===== ===== Hardware Design =====
 Lista de componente: Lista de componente:
-  * LCD Nokia 5110 +  * OLED SSD1306 
-  * x push button+  * x push button
   * Arduino UNO   * Arduino UNO
   * 3 x LED   * 3 x LED
   * rezistente   * rezistente
   * fire   * fire
 +  * buzzer
  
 Cum am legat pinii: Cum am legat pinii:
-LCD Nokia 5110:+OLED SSD1306:
  
-RST la pinul digital ​8+  * VCC la 3.3V 
 +  * GND la GND 
 +  * SDA la pinul digital A4 
 +  * SCL la pinul digital ​A5
  
-CE (CS) la pinul digital 7+LED-urile:
  
-DC la pinul digital 6+  * LED1 anod la digital 3, catod la GND 
 +  * LED2 anod la digital 5, catod la GND 
 +  * LED3 anod la digital 6, catod la GND
  
-DIN la pinul digital 5+Butoanele:
  
-CLK la pinul digital ​4+  * Buton1 un pin la digital ​9, celalalt pin la GND 
 +  * Buton2 un pin la digital 10, celalalt pin la GND 
 +  * Buton3 un pin la digital 11, celalalt pin la GND 
 +  * Buton4 un pin la digital 12, celalalt pin la GND 
 +  * Buton5 un pin la digital 8, celalalt pin la GND
  
-VCC la 3.3V+Buzzer:
  
-Backlight (BL) la GND+  * Buzzer plus la digital 7, minus la GND
  
-GND la GND+{{:​pm:​prj2025:​fstancu:​pm_arduino_pacman.png?​300|}} 
 +===== Software Design ===== 
 +<​code>​ 
 +#include <​Wire.h>​ 
 +#include <​Adafruit_GFX.h>​ 
 +#include <​Adafruit_SSD1306.h>​
  
-LED-urile:+#define SCREEN_WIDTH 128 
 +#define SCREEN_HEIGHT 64
  
-LED1 anod la digital 2catod la GND+Adafruit_SSD1306 display(SCREEN_WIDTHSCREEN_HEIGHT,​ &Wire, -1);
  
-LED2 anod la digital 3, catod la GND+#define UP_BUTTON 9 
 +#define DOWN_BUTTON 10 
 +#define LEFT_BUTTON 11 
 +#define RIGHT_BUTTON 12 
 +#define PAUSE_BUTTON 8
  
-LED3 anod la digital 12, catod la GND+#define BUZZER_PIN 7
  
-Butoanele:+#define LIFE_LED_1 3 
 +#define LIFE_LED_2 5 
 +#define LIFE_LED_3 6
  
-Buton1 un pin la analog A0, celalalt pin la GND+int pacmanX = 10; 
 +int pacmanY = 10; 
 +const int pacmanRadius = 3;
  
-Buton2 un pin la analog A1, celalalt pin la GND+int lives = 3; 
 +int score = 0;
  
-Buton3 un pin la analog A2celalalt pin la GND+struct Wall { 
 +  int xy, w, h; 
 +};
  
-Buton4 un pin la analog A3celalalt pin la GND+#define NUM_WALLS 12 
 +Wall walls[NUM_WALLS] = { 
 +  {00, 128, 5}, 
 +  {0, 59, 128, 5}, 
 +  {0, 0, 5, 64}, 
 +  {123, 0, 5, 64}, 
 +  {20, 15, 5, 35}, 
 +  {40, 5, 5, 15}, 
 +  {40, 45, 5, 20}, 
 +  {60, 15, 5, 35}, 
 +  {80, 5, 5, 15}, 
 +  {80, 45, 5, 20}, 
 +  {100, 15, 5, 35}, 
 +  {20, 30, 85, 5} 
 +};
  
-{{:​pm:​prj2025:​fstancu:​pm_arduino_pacman.png?300|}} +#define DOT_SPACING 10 
-===== Software Design ​===== +bool dots[SCREEN_WIDTH / DOT_SPACING][SCREEN_HEIGHT / DOT_SPACING];​ 
-Descrierea codului aplicaţiei ​(firmware): + 
-  ​* mediu de dezvoltare ​(if any) (e.g. AVR StudioCodeVisionAVR+struct Ghost { 
-  ​* librării şi surse 3rd-party (e.g. Procyon AVRlib+  int x, y; 
-  * algoritmi şstructuri pe care plănuiţsă le implementaţ+  int dx, dy; 
-  * (etapa 3) surse şfuncţii implementate+  int stepCount;​ 
 +  int radius; 
 +}; 
 + 
 +#define NUM_GHOSTS 3 
 +Ghost ghosts[NUM_GHOSTS];​ 
 + 
 +bool isValidPosition(int x, int y, int radius) ​{ 
 +  for (int i = 0; i < NUM_WALLS; i++) { 
 +    if (x + radius > walls[i].x && x - radius < walls[i].x + walls[i].w &&​ 
 +        y + radius > walls[i].y && y - radius < walls[i].y + walls[i].h) { 
 +      return false; 
 +    } 
 +  } 
 +  return true; 
 +
 + 
 +bool checkDotCollision(int x, int y) { 
 +  int cx = x / DOT_SPACING;​ 
 +  int cy = y / DOT_SPACING;​ 
 +  if (cx >= 0 && cx < SCREEN_WIDTH / DOT_SPACING && cy >= 0 && cy < SCREEN_HEIGHT / DOT_SPACING) { 
 +    if (dots[cx][cy]) { 
 +      dots[cx][cy] = false; 
 +      score += 10; 
 +      tone(BUZZER_PIN,​ 1000, 100); 
 +    } 
 +  } 
 +
 + 
 +void updateLEDs() { 
 +  if (lives >= 1) analogWrite(LIFE_LED_1,​ 255); else analogWrite(LIFE_LED_1,​ 0); 
 +  if (lives >= 2) analogWrite(LIFE_LED_2,​ 180); else analogWrite(LIFE_LED_2,​ 0); 
 +  if (lives >= 3) analogWrite(LIFE_LED_3,​ 100); else analogWrite(LIFE_LED_3,​ 0); 
 +
 + 
 +void fadeOutLed(int pin) { 
 +  for (int brightness = 255; brightness >= 0; brightness -= 1) { 
 +    analogWrite(pin,​ brightness);​ 
 +    delay(2); 
 +  } 
 +  analogWrite(pin,​ 0); 
 +
 + 
 +void loseLife() { 
 +  if (lives > 0) { 
 +    if (lives == 3) fadeOutLed(LIFE_LED_3);​ 
 +    else if (lives == 2) fadeOutLed(LIFE_LED_2);​ 
 +    else if (lives == 1) fadeOutLed(LIFE_LED_1);​ 
 + 
 +    lives--; 
 +    updateLEDs();​ 
 +    tone(BUZZER_PIN,​ 500, 300); 
 +  ​} 
 +
 + 
 +void respawnGhost(Ghost &g) { 
 +  int x, y; 
 +  do { 
 +    x random(10, SCREEN_WIDTH - 10); 
 +    y random(10, SCREEN_HEIGHT - 10); 
 +  } while (!isValidPosition(x,​ y, g.radius));​ 
 +  g.x x; 
 +  g.y y; 
 +  g.stepCount ​0; 
 +  g.dx 0; 
 +  g.dy 0; 
 +
 + 
 +void moveGhost(Ghost &g) { 
 +  if (g.stepCount <0) { 
 +    int possibleDirs[3] ​{-1, 0, 1}; 
 +    g.dx possibleDirs[random(3)];​ 
 +    g.dy = possibleDirs[random(3)]; 
 +    g.stepCount = random(10, 30); 
 +  ​
 + 
 +  if (random(100) < 20) { 
 +    ​if (pacmanX > g.xg.dx = 1; 
 +    else if (pacmanX < g.x) g.dx = -1; 
 +    else g.dx = 0; 
 + 
 +    if (pacmanY > g.y) g.dy = 1; 
 +    else if (pacmanY < g.y) g.dy = -1; 
 +    else g.dy = 0; 
 +  } 
 + 
 +  int newX = g.x + g.dx; 
 +  int newY = g.y + g.dy; 
 + 
 +  if (isValidPosition(newXnewY, g.radius&&​ 
 +      newX - g.radius >= 0 && newX + g.radius <= SCREEN_WIDTH &&​ 
 +      newY - g.radius >= 0 && newY + g.radius <= SCREEN_HEIGHT) { 
 +    g.x = newX; 
 +    g.y = newY; 
 +  ​} else { 
 +    g.stepCount = 0; 
 +  } 
 + 
 +  g.stepCount--; 
 +
 + 
 +bool checkGhostCollision(Ghost &g) { 
 +  int dx = pacmanX - g.x; 
 +  int dy = pacmanY - g.y; 
 +  int distSq = dx * dx + dy * dy; 
 +  int radiiSum = pacmanRadius + g.radius; 
 +  return distSq <= radiiSum * radiiSum; 
 +
 + 
 +void drawGhost(int x, int y, int radius{ 
 +  ​display.fillCircle(x,​ y - radius / 2, radius / 1.5, SSD1306_WHITE);​ 
 +  display.fillRect(x - radius, y - radius / 2, radius ​2, radius, SSD1306_WHITE);​ 
 +  for (int = -radius; ​< radius; ​+= radius / 3) { 
 +    display.fillTriangle(x + i, y + radius, x + i + radius / 3 / 2, y + radius - 3, x + i + radius / 3, y + radius, SSD1306_WHITE);​ 
 +  ​
 +  display.fillRect(x - radius / 2, y - radius, radius / 3, radius / 3, SSD1306_BLACK);​ 
 +  display.fillRect(x + radius / 6, y - radius, radius / 3, radius / 3, SSD1306_BLACK);​ 
 +
 + 
 +void setup() { 
 +  Serial.begin(9600);​ 
 +  randomSeed(analogRead(A0));​ 
 + 
 +  if (!display.begin(SSD1306_SWITCHCAPVCC,​ 0x3C)) { 
 +    Serial.println(F("​SSD1306 allocation failed"​));​ 
 +    for (;;); 
 +  } 
 +  display.clearDisplay();​ 
 +  display.display();​ 
 + 
 +  pinMode(UP_BUTTON,​ INPUT_PULLUP);​ 
 +  pinMode(DOWN_BUTTON,​ INPUT_PULLUP);​ 
 +  pinMode(LEFT_BUTTON,​ INPUT_PULLUP);​ 
 +  pinMode(RIGHT_BUTTON,​ INPUT_PULLUP);​ 
 +  pinMode(PAUSE_BUTTON,​ INPUT_PULLUP);​ 
 +  pinMode(BUZZER_PIN,​ OUTPUT); 
 + 
 +  pinMode(LIFE_LED_1,​ OUTPUT); 
 +  pinMode(LIFE_LED_2,​ OUTPUT); 
 +  pinMode(LIFE_LED_3,​ OUTPUT); 
 + 
 +  updateLEDs();​ 
 + 
 +  for (int i = 0; i < NUM_GHOSTS; i++) { 
 +    ghosts[i].radius = 3; 
 +    respawnGhost(ghosts[i]);​ 
 +  } 
 + 
 +  for (int x = 0; x < SCREEN_WIDTH / DOT_SPACING;​ x++) { 
 +    for (int y = 0; y < SCREEN_HEIGHT / DOT_SPACING;​ y++) { 
 +      if (isValidPosition(x ​DOT_SPACING,​ y * DOT_SPACING,​ pacmanRadius)) { 
 +        dots[x][y] = true; 
 +      } 
 +    } 
 +  } 
 +
 + 
 +void loop() { 
 +  if (digitalRead(PAUSE_BUTTON) == LOW) { 
 +    display.clearDisplay();​ 
 +    display.setTextSize(1);​ 
 +    display.setTextColor(SSD1306_WHITE);​ 
 +    display.setCursor(20,​ 30); 
 +    display.print(F("​SCOR:​ ")); 
 +    display.print(score);​ 
 +    display.display();​ 
 +    delay(500);​ 
 +    return; 
 +  } 
 + 
 +  if (lives <= 0) { 
 +    display.clearDisplay();​ 
 +    display.setTextSize(2);​ 
 +    display.setTextColor(SSD1306_WHITE);​ 
 +    display.setCursor(20,​ 25); 
 +    display.println(F("​GAME OVER"​));​ 
 +    display.display();​ 
 +    delay(2000);​ 
 + 
 +    lives = 3
 +    pacmanX = 10; 
 +    pacmanY = 10; 
 +    updateLEDs()
 +    score = 0; 
 + 
 +    for (int = 0; i < NUM_GHOSTS; i++) { 
 +      respawnGhost(ghosts[i]);​ 
 +    } 
 + 
 +    for (int x = 0; x < SCREEN_WIDTH / DOT_SPACING;​ x++) { 
 +      for (int y = 0; y < SCREEN_HEIGHT / DOT_SPACING;​ y++) { 
 +        if (isValidPosition(x * DOT_SPACING,​ y * DOT_SPACING,​ pacmanRadius)) { 
 +          dots[x][y] = true; 
 +        } 
 +      } 
 +    } 
 +    return; 
 +  } 
 + 
 +  int newX = pacmanX; 
 +  int newY = pacmanY; 
 + 
 +  if (digitalRead(UP_BUTTON) == LOW) newY -= 2; 
 +  if (digitalRead(DOWN_BUTTON) == LOW) newY += 2; 
 +  if (digitalRead(LEFT_BUTTON) == LOW) newX -= 2; 
 +  if (digitalRead(RIGHT_BUTTON) == LOW) newX += 2; 
 + 
 +  if (newX - pacmanRadius < 0) newX = pacmanRadius;​ 
 +  if (newX + pacmanRadius > SCREEN_WIDTH) newX = SCREEN_WIDTH - pacmanRadius;​ 
 +  if (newY - pacmanRadius < 0) newY = pacmanRadius;​ 
 +  if (newY + pacmanRadius > SCREEN_HEIGHT) newY = SCREEN_HEIGHT - pacmanRadius;​ 
 + 
 +  if (isValidPosition(newX,​ newY, pacmanRadius)) { 
 +    pacmanX = newX; 
 +    pacmanY = newY; 
 +    checkDotCollision(pacmanX,​ pacmanY); 
 +  } 
 + 
 +  for (int i = 0; i < NUM_GHOSTS; i++) { 
 +    moveGhost(ghosts[i]);​ 
 +    if (checkGhostCollision(ghosts[i])) { 
 +      loseLife();​ 
 +      respawnGhost(ghosts[i]);​ 
 +    } 
 +  } 
 + 
 +  display.clearDisplay();​ 
 + 
 +  for (int i = 0; i < NUM_WALLS; i++) { 
 +    display.fillRect(walls[i].x,​ walls[i].y, walls[i].w, walls[i].h, SSD1306_WHITE);​ 
 +  } 
 + 
 +  for (int x = 0; x < SCREEN_WIDTH / DOT_SPACING;​ x++) { 
 +    for (int y = 0; y < SCREEN_HEIGHT / DOT_SPACING;​ y++) { 
 +      if (dots[x][y]) { 
 +        display.drawPixel(x * DOT_SPACING,​ y * DOT_SPACING,​ SSD1306_WHITE);​ 
 +      } 
 +    } 
 +  } 
 + 
 +  display.fillCircle(pacmanX,​ pacmanY, pacmanRadius,​ SSD1306_WHITE);​ 
 + 
 +  for (int i = 0; i < NUM_GHOSTS; i++) { 
 +    drawGhost(ghosts[i].x,​ ghosts[i].y,​ ghosts[i].radius);​ 
 +  } 
 + 
 +  display.setTextSize(1);​ 
 +  display.setCursor(100,​ 0); 
 +  display.print(score);​ 
 + 
 +  display.display();​ 
 +  delay(50);​ 
 +
 + 
 +</​code>​ 
 + 
 +==== Librarii si surse 3rd-party utilizate ==== 
 +  * **Adafruit_GFX** - pentru desenarea formelor grafice. 
 +  * **Adafruit_SSD1306** - pentru controlul afisajului OLED SSD1306. 
 + 
 +==== Concepte din laboratoare utilizate in proiect ==== 
 +  * **I2C** - utilizat pentru comunicarea cu display-ul OLED SSD1306 
 +  * **PWM** - folosit pentru controlul intensitatii LED-urilor care indica vietile jucatorului 
 +  * **GPIO** - utilizat pentru gestionarea butoanelor de control (sus, jos, stanga, dreapta, pauza)
  
 ===== Rezultate Obţinute ===== ===== Rezultate Obţinute =====
pm/prj2025/fstancu/sebastian.badea0506.1747472090.txt.gz · Last modified: 2025/05/17 11:54 by sebastian.badea0506
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