Arduino: costruire il videogame vintage Pong !

Con Arduino e pochissimi componenti è possibile ricreare il fantastico e storico gioco Pong!



Per la realizzazione sono necessari i seguenti componenti:

- 2 trimmer da 10 kohm
- 2 cavi rca (o 1 tagliato a metà)
- 1 resistenza da 1 kohm
- 1 resistenza da 470 ohm
- 1 resistenza da 10 kohm
- 1 pulsante
ed ovviamente il vostro arduino di qualsiasi versione, anche questo standalone.

ecco qui il semplice schema:




Qui di seguito lo sketch:


  1. /********
  2.  * Arduino Pong
  3.  * By Pete Lamonica
  4.  *  modified by duboisvb
  5.  *  updated by James Bruce (http://www.makeuseof.com/tag/author/jbruce
  6.  * A simple implementation of Pong on the Arduino using a TV for output.
  7.  *
  8.  */
  9. #include <TVout.h>
  10. #include <fontALL.h>
  11. #define WHEEL_ONE_PIN 0 //analog
  12. #define WHEEL_TWO_PIN 1 //analog
  13. #define BUTTON_ONE_PIN 2 //digital to start game
  14. // #define BUTTON_TWO_PIN 3 //digital to reset and go back to main menu
  15. #define PADDLE_HEIGHT 14
  16. #define PADDLE_WIDTH 1
  17. #define RIGHT_PADDLE_X (TV.hres()-4)
  18. #define LEFT_PADDLE_X 2
  19. #define IN_GAMEA 0 //in game state - draw constants of the game box
  20. #define IN_GAMEB 0 //in game state - draw the dynamic part of the game
  21. #define IN_MENU 1 //in menu state
  22. #define GAME_OVER 2 //game over state
  23. #define LEFT_SCORE_X (TV.hres()/2-15)
  24. #define RIGHT_SCORE_X (TV.hres()/2+10)
  25. #define SCORE_Y 4
  26. #define MAX_Y_VELOCITY 6
  27. #define PLAY_TO 7
  28. #define LEFT 0
  29. #define RIGHT 1
  30. TVout TV;
  31. unsigned char x,y;
  32. boolean button1Status = false;
  33. // boolean button2Status = false;
  34. int wheelOnePosition = 0;
  35. int wheelTwoPosition = 0;
  36. int rightPaddleY = 0;
  37. int leftPaddleY = 0;
  38. unsigned char ballX = 0;
  39. unsigned char ballY = 0;
  40. char ballVolX = 2;
  41. char ballVolY = 2;
  42. int leftPlayerScore = 0;
  43. int rightPlayerScore = 0;
  44. int frame = 0;
  45. int state = IN_MENU;
  46. void processInputs() {
  47.   wheelOnePosition = analogRead(WHEEL_ONE_PIN);
  48.   // delay(50);
  49.   wheelTwoPosition = analogRead(WHEEL_TWO_PIN);
  50.  // delay(50);
  51.    button1Status = (digitalRead(BUTTON_ONE_PIN));
  52.  //  button2Status = (digitalRead(BUTTON_TWO_PIN) == LOW);
  53.    if ((button1Status == 0)&& (state == GAME_OVER))
  54.    {
  55.      Serial.println("game over, drawing menu");
  56.      drawMenu ();
  57.    }
  58.    delay(50);
  59.   //Serial.println(button1Status);
  60.   //Serial.println(state);
  61.   //Serial.println(button2Status);
  62.   //Serial.println(wheelOnePosition);
  63.    //Serial.println(wheelTwoPosition);
  64. }
  65. void drawGameScreen() {
  66.  //  TV.clear_screen();
  67.   //draw right paddle
  68.   rightPaddleY = ((wheelOnePosition /8) * (TV.vres()-PADDLE_HEIGHT))/ 128;
  69.   x = RIGHT_PADDLE_X;
  70.   for(int i=0; i<PADDLE_WIDTH; i++) {
  71.     TV.draw_line(x+i,rightPaddleY,x+i,rightPaddleY+PADDLE_HEIGHT,1);
  72.   }
  73.   //draw left paddle
  74.   leftPaddleY = ((wheelTwoPosition /8) * (TV.vres()-PADDLE_HEIGHT))/ 128;
  75.   x = LEFT_PADDLE_X;
  76.   for(int i=0; i<PADDLE_WIDTH; i++) {
  77.     TV.draw_line(x+i,leftPaddleY,x+i,leftPaddleY+PADDLE_HEIGHT,1);
  78.   }
  79.   //draw score
  80.   TV.print_char(LEFT_SCORE_X,SCORE_Y,'0'+leftPlayerScore);
  81.   TV.print_char(RIGHT_SCORE_X,SCORE_Y,'0'+rightPlayerScore);
  82.   //draw ball
  83.   TV.set_pixel(ballX, ballY, 2);
  84. }
  85. //player == LEFT or RIGHT
  86. void playerScored(byte player) {
  87.   if(player == LEFT) leftPlayerScore++;
  88.   if(player == RIGHT) rightPlayerScore++;
  89.   //check for win
  90.   if(leftPlayerScore == PLAY_TO || rightPlayerScore == PLAY_TO) {
  91.     state = GAME_OVER;
  92.   }
  93.   ballVolX = -ballVolX;
  94. }
  95.  void drawBox() {
  96.       TV.clear_screen();
  97.      
  98.    //draw net
  99.   for(int i=1; i<TV.vres() - 4; i+=6) {
  100.     TV.draw_line(TV.hres()/2,i,TV.hres()/2,i+3,1);
  101.   }
  102.   // had to make box a bit smaller to fit tv
  103.     TV.draw_line(0, 0, 0,95,1 );  // left
  104.    TV.draw_line(0, 0, 126,0,1 ); // top
  105.     TV.draw_line(126, 0, 126,95,1 ); // right
  106.      TV.draw_line(0, 95, 126,95,1 ); // bottom
  107.   state = IN_GAMEB;
  108. }
  109. void drawMenu() {
  110.   x = 0;
  111.   y = 0;
  112.   char volX =3;
  113.   char volY = 3;
  114.   TV.clear_screen();
  115.   TV.select_font(font8x8);
  116.   TV.print(10, 5, "Arduino Pong");
  117.   TV.select_font(font4x6);
  118.   TV.print(22, 35, "Press Button");
  119.   TV.print(30, 45, "To Start");
  120.   delay(1000);
  121.   while(!button1Status) {
  122.     Serial.println("menu");
  123.   Serial.println(button1Status);
  124.     processInputs();
  125.     TV.delay_frame(3);
  126.     if(+ volX < 1 || x + volX > TV.hres() - 1) volX = -volX;
  127.     if(+ volY < 1 || y + volY > TV.vres() - 1) volY = -volY;
  128.     if(TV.get_pixel(+ volX, y + volY)) {
  129.       TV.set_pixel(+ volX, y + volY, 0);
  130.    
  131.       if(TV.get_pixel(+ volX, y - volY) == 0) {
  132.         volY = -volY;
  133.       }
  134.       else if(TV.get_pixel(- volX, y + volY) == 0) {
  135.         volX = -volX;
  136.       }
  137.       else {
  138.         volX = -volX;
  139.         volY = -volY;
  140.       }
  141.     }
  142.     TV.set_pixel(x, y, 0);
  143.     x += volX;
  144.     y += volY;
  145.     TV.set_pixel(x, y, 1);
  146.   }
  147.   TV.select_font(font4x6);
  148.   state = IN_GAMEA;
  149. }
  150. void setup()  {
  151.     //Serial.begin(9600);
  152.   x=0;
  153.   y=0;
  154.   TV.begin(_NTSC);       //for devices with only 1k sram(m168) use TV.begin(_NTSC,128,56)
  155.   ballX = TV.hres() / 2;
  156.   ballY = TV.vres() / 2;
  157. //  pinMode(BUTTON_ONE_PIN, INPUT);      // sets the digital pin as output
  158. }
  159. void loop() {
  160.   processInputs();
  161.   if(state == IN_MENU) {
  162.     drawMenu();
  163.   }
  164.  if(state == IN_GAMEA) {
  165.     //Serial.println("gamA");
  166.   //Serial.println(button1Status);
  167.     drawBox();
  168.   }
  169.   if(state == IN_GAMEB) {
  170.     if(frame % 3 == 0) { //every third frame
  171.       ballX += ballVolX;
  172.       ballY += ballVolY;
  173.  // change if hit top or bottom
  174.       if(ballY <= 1 || ballY >= TV.vres()-1)
  175.      { ballVolY = -ballVolY;
  176.                  delay(100);
  177.   TV.tone( 2000,30  );  
  178.      }
  179.      
  180.   // test left side for wall hit    
  181.       if(ballVolX < 0 && ballX == LEFT_PADDLE_X+PADDLE_WIDTH-1 && ballY >= leftPaddleY && ballY <= leftPaddleY +PADDLE_HEIGHT) {
  182.         ballVolX = -ballVolX;
  183.         ballVolY += 2 * ((ballY - leftPaddleY) - (PADDLE_HEIGHT / 2)) / (PADDLE_HEIGHT / 2);
  184.             delay(100);
  185.   TV.tone(2000,30 );  
  186.       }
  187.      
  188.  // test right side for wall hit    
  189.       if(ballVolX > 0 && ballX == RIGHT_PADDLE_X && ballY >= rightPaddleY && ballY <= rightPaddleY +PADDLE_HEIGHT) {
  190.         ballVolX = -ballVolX;
  191.         ballVolY += 2 * ((ballY - rightPaddleY) - (PADDLE_HEIGHT / 2)) / (PADDLE_HEIGHT / 2);
  192.             delay(100);
  193.   TV.tone( 2000,30  );  
  194.       }
  195.       //limit vertical speed
  196.       if(ballVolY > MAX_Y_VELOCITY) ballVolY = MAX_Y_VELOCITY;
  197.       if(ballVolY < -MAX_Y_VELOCITY) ballVolY = -MAX_Y_VELOCITY;
  198.  // Scoring
  199.       if(ballX <= 1) {
  200.         playerScored(RIGHT);
  201.      // sound
  202.      delay(100);
  203.   TV.tone( 500,300 );  
  204.       }
  205.       if(ballX >= TV.hres() - 1) {
  206.         playerScored(LEFT);
  207.         // sound
  208.         delay(100);
  209.  TV.tone(  500,300 );
  210.       }
  211.     }
  212.    
  213.    
  214. //    if(button1Status) Serial.println((int)ballVolX);
  215.     drawGameScreen();
  216.   }
  217.   if(state == GAME_OVER) {
  218.     drawGameScreen();
  219.     TV.select_font(font8x8);
  220.     TV.print(29,25,"GAME");
  221.     TV.print(68,25,"OVER");
  222.     while(!button1Status) {
  223.       processInputs();
  224.       delay(50);
  225.     }
  226.     TV.select_font(font4x6); //reset the font
  227.     //reset the scores
  228.     leftPlayerScore = 0;
  229.     rightPlayerScore = 0;
  230.     state = IN_MENU;
  231.   }
  232.   TV.delay_frame(1);
  233.   if(++frame == 60) frame = 0; //increment and/or reset frame counter
  234. }

complimenti ai realizzatori di questo fantastico sketch!
Segui Daniele Alberti su Google+

15 commenti:

  1. Non riesco ad includere la libreria fontALL.h

    RispondiElimina
    Risposte
    1. Ciao!
      per prima cosa devi scaricare la libreria cliccando su questo link
      https://arduino-tvout.googlecode.com/files/TVoutBeta1.zip
      poi prendi le cartelle tvout e tvoutfonts e mettile nella cartella "libraries" della radice di Arduino.

      Elimina
  2. ciao Daniele... mi piacerebbe provare a fare questo... ho trovato un piccolo tv monitor... che però ha solo le entrate AV1...AV2...è possibile utilizzarlo?..
    grazie... e ..complimenti

    RispondiElimina
    Risposte
    1. Certo, com'è il connettore del monitor?

      Elimina
  3. è un'attacco per uno spinotto tipo jack...unico...non so dove lo abbia messo devo cercarlo ma posso anche ricomprarlo...basta sapere che si può fare... ti posterei una foto ma non so dove...

    RispondiElimina
  4. ho trovato gli spinotti che dovrebbero andare bene.. sono
    spinotto con finali rosso--bianco--giallo ..(penso che sia questo)
    spinotto rosso--bianco
    spinotto giallo --nero
    spinotto rosso-- nero
    spero sia sufficente...
    saluti

    RispondiElimina
    Risposte
    1. Si gli spinotti giusti sono gli RCA dei quali a noi servono solo il rosso e il giallo (il bianco non serve)

      Elimina
  5. Daniele devo presentare il progetto e ne devo spiegare il codice...riesco a capirlo tutto tranne questa parte:

    if(x + volX < 1 || x + volX > TV.hres() - 1) volX = -volX;
    if(y + volY < 1 || y + volY > TV.vres() - 1) volY = -volY;
    if(TV.get_pixel(x + volX, y + volY)) {
    TV.set_pixel(x + volX, y + volY, 0);

    if(TV.get_pixel(x + volX, y - volY) == 0) {
    volY = -volY;
    }
    else if(TV.get_pixel(x - volX, y + volY) == 0) {
    volX = -volX;
    }
    else {
    volX = -volX;
    volY = -volY;
    }
    }
    TV.set_pixel(x, y, 0);
    x += volX;
    y += volY;
    TV.set_pixel(x, y, 1);
    }
    a cosa serve? che cosa sono volX e volY?

    RispondiElimina
    Risposte
    1. Ciao, purtroppo questo è l'unico sketch che non ho scritto io, infatti all'inizio del codice puoi vedere chi è l'autore.
      Ammetto che il codice è complesso, e non avendolo neanche scritto diventa complicato entrare nella mente dello sviluppatore.
      L'unico aiuto che riesco a darti è che quella parte rientra nella funzione che serve a disegnare il menu, inoltre la funzione TV.set_pixel serve a decidere il colore del pixel di coordinate x e y, coordinate che cambiano agendo sul potenziometro.
      Quindi sembrerebbe che il tutto serva a permetterti di muoversi nel menu.
      Puoi provare a commentare qualche riga e caricare il codice, se riesci a capire cosa c'è di diverso sei a cavallo. Ciao!

      Elimina
  6. Ho un ultima domanda...ho cercato ma non riesco a capire...perchè il suono esce proprio dal pin 11? nel tuo codice non riesco a trovare dove dichiari all'Arduino che per l'output sonoro usi proprio il pin 11

    RispondiElimina
  7. Il pin 11 è imposto dalla libreria, per usare un altro pin bisogna modificare la libreria stessa.

    RispondiElimina
  8. Secondo te come si potrebbe fare per rendere più veloce

    RispondiElimina
  9. vorrei sapere perché il programma per programmare arduino mi dice dopo l'inserimento del programma qua supra:"TVout does not a name type" (riga 41). se mi potete dare una spiegazione o dirmi come correggerlo i ringrazio.
    grazie in anticipo!

    RispondiElimina
  10. Questo commento è stato eliminato dall'autore.

    RispondiElimina

Lascia un commento qui sotto, ti risponderò il prima possibile!

Related Posts Plugin for WordPress, Blogger...