This is an old revision of the document!


Pong Multiplayer Game

Introducere

Ce face?

Proiectul implică dezvoltarea unui dispozitiv interactiv de divertisment, conceput pentru a oferi utilizatorilor o experiență de joc captivantă. Acest dispozitiv permite utilizatorilor să selecteze modul de joc (single player sau multiplayer) prin intermediul butoanelor disponibile, pentru un joc de Ping Pong. Apoi, ei interacționează cu joystick-urile dedicate pentru a participa la joc, care se desfășoară într-o serie de „best of 3”, afișându-se pe ecranul conectat. În funcție de rezultat, buzzer-ul va crea un sunet de învingător sau pierzător.

Scopul lui?

Scopul principal al dispozitivului este de a oferi o modalitate distractivă și interactivă de petrecere a timpului liber, aducând împreună elemente clasice de joc și tehnologie modernă.

Alte considerente

Consider că acest joc nu are o utilitate mare în zona educației sau medicinei, dar conferă o notă de nostalgie jucătorilor care au avut primul contact cu un astfel de joc. Prin acest proiect încerc să dezvolt un joc vechi într-un mod cât mai plăcut pentru toată lumea.

Ideea de la care am pornit pentru acest proiect a fost una simplă: îmi doream să fac ceva „catchy”, dar suficient de complicat și interactiv.

Descriere generală

Funcționarea sistemului de joc:

1. Inițializarea joculu:

  • Utilizatorul pornește sistemul și alege, prin interacțiunea cu butonul, modul de joc: singleplayer, multiplayer.

2. Începerea jocului

  • Odată inițializat jocul, acesta va începe, afișând pe ecran scorul actual (0 - 0) și creând jucătorii (cele 2 palete)

3. Procesarea mișcărilor

  • În funcție de modul de joc ales, acțiunea joystick-urilor va afecta poziția paletelor (sau a unei singure palete).
  • Monitorizarea acțiunilor asupra joystick-urilor se va face constant de către placa de acțiune (Arduino).
  • Prin atingerea bilei de joc cu o paletă, bila se va mișca către terenul advers.
  • Afișarea mișcărilor corecte va fi procesată de placa Arduino și transmisă către utilizator prin display-ul LED I2C.

4. Încheierea jocului

  • Jocul se va incheia odată cu atingerea scorului de 2/3 puncte de oricare dintre jucători.
  • Procesarea mișcărilor joystick-urilor va fi oprită.
  • Va fi acționat buzzer-ul pentru a transmite sunetul corespunzător finalului de joc.

5. Rematch

  • Odată cu finalizarea jocului anterior va fi pornită opțiunea de rematch care va reinițializa un joc după formatul anterior.

Hardware Design

Lista componente:

Nume componentă Cantitate
Arduino UNO (echivalent ATMega328P) 1
Buzzer 1
Joystick Analog 2
Display LCD (I2C) 1
Breadboard 1
LED (diverse culori) 1/2
Rezistor (diverse valori) 1/2
Cabluri nelimitat

Cum arată până acum:

Modelul sistemului (cu componente vizibile):


Schematicul sistemului:

  • Am utilizat potențiometre în locul joystick-urilor analogice din cadrul ambelor scheme, deoarece nu am putut găsi online un model care să se potrivească.
  • Urmează să construiesc din carton (sau orice material mai accesibil) o carcasă pentru a putea juca fără posibilitatea de a deconecta cablurile.

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

Descrierea codului aplicației

  • Mediu de dezvoltare:

Pentru dezvoltarea acestui proiect, a fost utilizat mediu de dezvoltare Arduino IDE. Acesta oferă un mediu prietenos și ușor de utilizat pentru programarea microcontrolerelor din familia Atmega.

  • Librării și surse 3rd-party:

Au fost utilizate următoarele librării:

  1. Wire.h: pentru comunicarea I2C între Arduino și display-ul LCD.
  2. LiquidCrystal_I2C.h: pentru gestionarea și controlul display-ului LCD I2C.
  • Algoritmi și structuri pe care plănuiesc să le implementez:

Algoritmii principali includ:

  1. Controlul mingii în jocul Pong, incluzând detectarea coliziunilor cu pereții și paletele.
  2. Actualizarea scorurilor și afișarea acestora pe display.
  3. Detectarea intrărilor analogice de la potențiometre pentru controlul paletelor.
  1. Surse și funcții implementate:
    1. Inițializarea și configurarea display-ului LCD I2C.
    2. Implementarea funcției de desenare a terenului de joc și a scorului.
    3. Controlul mișcării mingii și detectarea coliziunilor.
    4. Implementarea sunetelor pentru diferite evenimente în joc (coliziuni și puncte).

Stadiul actual al implementării software

TODO

Codul sursă:

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

const int SW_pin = 4; // digital pin connected to switch output
const int player1 = A1; // analog pin connected to Y output
const int player2 = A0; // analog pin connected to Y output

const unsigned long PADDLE_RATE = 45;
const unsigned long BALL_RATE = 0;
const uint8_t PADDLE_HEIGHT = 12;
int player1Score = 0;
int player2Score = 0;
int maxScore = 8;
int BEEPER = 12;
bool resetBall = false;
#define SCREEN_WIDTH 16 // LCD display width, in characters
#define SCREEN_HEIGHT 2 // LCD display height, in lines
#define RESET_BUTTON 3

LiquidCrystal_I2C lcd(0x27, SCREEN_WIDTH, SCREEN_HEIGHT); // Set the LCD I2C address

void drawCourt();
void drawScore();

uint8_t ball_x = 8, ball_y = 1;
uint8_t ball_dir_x = 1, ball_dir_y = 1;
unsigned long ball_update;

unsigned long paddle_update;
const uint8_t PLAYER2_X = 2;
uint8_t player2_y = 0;

const uint8_t PLAYER_X = 13;
uint8_t player1_y = 0;

void setup() {
  lcd.init();
  lcd.backlight();
  unsigned long start = millis();
  pinMode(BEEPER, OUTPUT);
  pinMode(SW_pin, INPUT);
  pinMode(RESET_BUTTON, INPUT_PULLUP);
  digitalWrite(SW_pin, HIGH);
  lcd.clear();
  drawCourt();
  drawScore();
  while (millis() - start < 2000);

  ball_update = millis();
  paddle_update = ball_update;
}

void loop() {
  bool update = false;
  unsigned long time = millis();

  static bool up_state = false;
  static bool down_state = false;

  if (resetBall)
  {
    if (player1Score == maxScore || player2Score == maxScore)
    {
      gameOver();
    }
    else {
      lcd.clear();
      drawScore();
      drawCourt();
      ball_x = random(7, 9);
      ball_y = random(0, 1);
      do
      {
        ball_dir_x = random(-1, 2);
      } while (ball_dir_x == 0);

      do
      {
        ball_dir_y = random(-1, 2);
      } while (ball_dir_y == 0);

      resetBall = false;
    }
  }

  if (time > ball_update) {
    uint8_t new_x = ball_x + ball_dir_x;
    uint8_t new_y = ball_y + ball_dir_y;

    // Check if we hit the vertical walls
    if (new_x == 0 || new_x == 15) {
      if (new_x == 0) {
        player1Score += 1;
        lcd.clear();
        soundPoint();
        resetBall = true;
      }
      else if (new_x == 15) {
        player2Score += 1;
        lcd.clear();
        soundPoint();
        resetBall = true;
      }
      ball_dir_x = -ball_dir_x;
      new_x += ball_dir_x + ball_dir_x;
    }

    // Check if we hit the horizontal walls.
    if (new_y == 0 || new_y == 1) {
      soundBounce();
      ball_dir_y = -ball_dir_y;
      new_y += ball_dir_y + ball_dir_y;
    }

    // Check if we hit the player 2 paddle
    if (new_x == PLAYER2_X && new_y == player2_y) {
      soundBounce();
      ball_dir_x = -ball_dir_x;
      new_x += ball_dir_x + ball_dir_x;
    }

    // Check if we hit the player 1 paddle
    if (new_x == PLAYER_X && new_y == player1_y) {
      soundBounce();
      ball_dir_x = -ball_dir_x;
      new_x += ball_dir_x + ball_dir_x;
    }

    lcd.setCursor(ball_x, ball_y);
    lcd.print(" ");
    lcd.setCursor(new_x, new_y);
    lcd.print("O");
    ball_x = new_x;
    ball_y = new_y;

    ball_update += BALL_RATE;

    update = true;
  }

  if (time > paddle_update) {
    paddle_update += PADDLE_RATE;

    // Player 2 paddle
    lcd.setCursor(PLAYER2_X, player2_y);
    lcd.print(" ");
    if (analogRead(player2) < 475) {
      player2_y = 0;
    }
    if (analogRead(player2) > 550) {
      player2_y = 1;
    }
    lcd.setCursor(PLAYER2_X, player2_y);
    lcd.print("|");

    // Player 1 paddle
    lcd.setCursor(PLAYER_X, player1_y);
    lcd.print(" ");
    if (analogRead(player1) < 475) {
      player1_y = 0;
    }
    if (analogRead(player1) > 550) {
      player1_y = 1;
    }
    up_state = down_state = false;
    lcd.setCursor(PLAYER_X, player1_y);
    lcd.print("|");
  }
  update = true;

  if (update) {
    drawScore();
    if (digitalRead(SW_pin) == 0) // Player pressed button to stop the game
    {
      gameOver(); 
    }
  }
}

// de implementat functiile
Elementul de noutate al proiectului este dat de posibilitatea de a interacționa direct cu sistemul prin intermediul joystickurilor.

Laboratoare utilizate

Video Demo

TODO

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

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.

Export to PDF

pm/prj2024/sseverin/andrei.napruiu.1716497303.txt.gz · Last modified: 2024/05/23 23:48 by andrei.napruiu
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