Autor: Badea Sebastian-Mihail
Grupa: 341C4
Îndrumător: Florin Stancu
Proiectul consta in realizarea jocului Pacman controlat din butoane cu afisajul pe un ecran LCD. Tu esti protagonistul, Pacman, care trebuie sa obtina un scor cat mai mare fara a se lasa atacat de inamici. Scopul jocului este de a te relaxa si cred ca este util pentru mine intrucat ma va ajuta sa inteleg cat mai bine ceea ce presupune un astfel de proiect.
Pentru deplasarea personajului se vor folosi 4 butoane. Personajul va avea 3 vieti la fiecare joc care vor fi reprezentate pe cele 3 led-uri (verde – reprezinta o viata ok, rosu inseamna ca s-a pierdut viata). La finalul jocului este afisat scorul si se mentioneaza daca acesta este un highscore. Jocul se termina cand protagonistul pierde toate cele 3 vieti.
Lista de componente:
Cum am legat pinii: OLED SSD1306:
LED-urile:
Butoanele:
Buzzer:
#include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #define SCREEN_WIDTH 128 #define SCREEN_HEIGHT 64 Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1); #define UP_BUTTON 9 #define DOWN_BUTTON 10 #define LEFT_BUTTON 11 #define RIGHT_BUTTON 12 #define PAUSE_BUTTON 8 #define BUZZER_PIN 7 #define LIFE_LED_1 3 #define LIFE_LED_2 5 #define LIFE_LED_3 6 int pacmanX = 10; int pacmanY = 10; const int pacmanRadius = 3; int lives = 3; int score = 0; struct Wall { int x, y, w, h; }; #define NUM_WALLS 12 Wall walls[NUM_WALLS] = { {0, 0, 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} }; #define DOT_SPACING 10 bool dots[SCREEN_WIDTH / DOT_SPACING][SCREEN_HEIGHT / DOT_SPACING]; struct Ghost { int x, y; int dx, dy; 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.x) g.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(newX, newY, 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 i = -radius; i < radius; i += 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 i = 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); }
Care au fost rezultatele obţinute în urma realizării proiectului vostru.
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.
Puteți avea și o secțiune de jurnal în care să poată urmări asistentul de proiect progresul proiectului.
Listă cu documente, datasheet-uri, resurse Internet folosite, eventual grupate pe Resurse Software şi Resurse Hardware.