Pull to refresh

Игра Pong на Arduino



Нам потребуется Arduino любой версии, резисторы 470ом и 1к, RCA коннектор (тюльпан), два потенциометра на 10k.

Для начала изготовим кабель для подключения к AV каналу телевизора. Возьмем кабель, желательно тонкий экранированный, с одной стороны установим RCA коннектор. С другой к центральному проводу припаиваем два резистора на 470ом и 1к – они подключаются к Arduino на D7 и D9 соответственно (по ним идут сигналы Video и Sync). Внешний провод (оплетка кабеля) подключается на GND.





Скачиваем и подключаем в среду Arduino библиотеку Arduino TV Out
code.google.com/p/arduino-tvout
Я использовал Arduino Uno R3, для некоторых версий Arduino возможно будут другие номера контактов для подключения кабеля, подробности в документации библиотеки. Можно загрузить в Arduino демонстрацию из этой библиотеки, подключить к TV и убедиться что наш кабель работает.

Берем потенциометр, подключаем крайние из трех контактов к Arduino на 5V и GND, центральный контакт на A0. Аналогично подключаем второй потенциометр, но средний контакт на A1. Для удобства я подключал потенциометры через отрезки Ethernet кабеля.



Загружаем в Arduino следующий код игры.

Код программы
/********
 * Arduino Pong
 * By Pete Lamonica
 *  modified by duboisvb
 *  updated by James Bruce (http://www.makeuseof.com/tag/author/jbruce
 * A simple implementation of Pong on the Arduino using a TV for output.
 ********/
 
#include <TVout.h>
#include <fontALL.h>
 
#define WHEEL_ONE_PIN 0 //analog
#define WHEEL_TWO_PIN 1 //analog
// #define BUTTON_ONE_PIN 2 //digital to start game
// #define BUTTON_TWO_PIN 3 //digital to reset and go back to main menu
 
#define PADDLE_HEIGHT 14
#define PADDLE_WIDTH 1
 
#define RIGHT_PADDLE_X (TV.hres()-4)
#define LEFT_PADDLE_X 2
 
#define IN_GAMEA 0 //in game state - draw constants of the game box
#define IN_GAMEB 0 //in game state - draw the dynamic part of the game
 
#define IN_MENU 1 //in menu state
#define GAME_OVER 2 //game over state
 
#define LEFT_SCORE_X (TV.hres()/2-15)
#define RIGHT_SCORE_X (TV.hres()/2+10)
#define SCORE_Y 4
 
#define MAX_Y_VELOCITY 6
#define PLAY_TO 7
 
#define LEFT 0
#define RIGHT 1
 
TVout TV;
unsigned char x,y;
 
boolean button1Status = false;
// boolean button2Status = false;
 
int wheelOnePosition = 0;
int wheelTwoPosition = 0;
int rightPaddleY = 0;
int leftPaddleY = 0;
unsigned char ballX = 0;
unsigned char ballY = 0;
char ballVolX = 2;
char ballVolY = 2;
 
int leftPlayerScore = 0;
int rightPlayerScore = 0;
 
int frame = 0;
int state = IN_MENU;
 
void processInputs() {
  wheelOnePosition = analogRead(WHEEL_ONE_PIN);
  // delay(50);
  wheelTwoPosition = analogRead(WHEEL_TWO_PIN);
 // delay(50);
//   button1Status = (digitalRead(BUTTON_ONE_PIN));
  button1Status = true;
 
 //  button2Status = (digitalRead(BUTTON_TWO_PIN) == LOW);
   if ((button1Status == 0)&& (state == GAME_OVER))
   {
     Serial.println("game over, drawing menu");
     drawMenu ();
   }
 
   delay(50);
  //Serial.println(button1Status);
  //Serial.println(state);
  //Serial.println(button2Status);
  //Serial.println(wheelOnePosition);
  //Serial.println(wheelTwoPosition);
}
 
void drawGameScreen() {
 //  TV.clear_screen();
  //draw right paddle
  rightPaddleY = ((wheelOnePosition /8) * (TV.vres()-PADDLE_HEIGHT))/ 128;
  x = RIGHT_PADDLE_X;
  for(int i=0; i<PADDLE_WIDTH; i++) {
    TV.draw_line(x+i,rightPaddleY,x+i,rightPaddleY+PADDLE_HEIGHT,1);
  }
 
  //draw left paddle
  leftPaddleY = ((wheelTwoPosition /8) * (TV.vres()-PADDLE_HEIGHT))/ 128;
  x = LEFT_PADDLE_X;
  for(int i=0; i<PADDLE_WIDTH; i++) {
    TV.draw_line(x+i,leftPaddleY,x+i,leftPaddleY+PADDLE_HEIGHT,1);
  }
 
  //draw score
  TV.print_char(LEFT_SCORE_X,SCORE_Y,'0'+leftPlayerScore);
  TV.print_char(RIGHT_SCORE_X,SCORE_Y,'0'+rightPlayerScore);
 
   //draw ball
  TV.set_pixel(ballX, ballY, 2);
}
 
//player == LEFT or RIGHT
void playerScored(byte player) {
  if(player == LEFT) leftPlayerScore++;
  if(player == RIGHT) rightPlayerScore++;
 
  //check for win
  if(leftPlayerScore == PLAY_TO || rightPlayerScore == PLAY_TO) {
    state = GAME_OVER;
  }
 
  ballVolX = -ballVolX;
}
 
 void drawBox() {
  TV.clear_screen();
     
   //draw net
  for(int i=1; i<TV.vres() - 4; i+=6) {
    TV.draw_line(TV.hres()/2,i,TV.hres()/2,i+3,1);
  }
  // had to make box a bit smaller to fit tv
    TV.draw_line(0, 0, 0,95,1 );  // left
   TV.draw_line(0, 0, 126,0,1 ); // top
    TV.draw_line(126, 0, 126,95,1 ); // right
     TV.draw_line(0, 95, 126,95,1 ); // bottom
 
  state = IN_GAMEB;
}
 
 
void drawMenu() {
  x = 0;
  y = 0;
  char volX =3;
  char volY = 3;
  TV.clear_screen();
  TV.select_font(font8x8);
  TV.print(10, 5, "Arduino Pong");
  TV.select_font(font4x6);
  TV.print(22, 35, "Press Button");
  TV.print(30, 45, "To Start");
 
  delay(1000);
  while(!button1Status) {
    Serial.println("menu");
  Serial.println(button1Status);
 
    processInputs();
    TV.delay_frame(3);
    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);
  }
 
  TV.select_font(font4x6);
  state = IN_GAMEA;
}
 
void setup()  {
    //Serial.begin(9600);
  x=0;
  y=0;
  TV.begin(_NTSC);       //for devices with only 1k sram(m168) use TV.begin(_NTSC,128,56)
 
  ballX = TV.hres() / 2;
  ballY = TV.vres() / 2;
 
//  pinMode(BUTTON_ONE_PIN, INPUT);      // sets the digital pin as output
}
 
void loop() {
  processInputs();
 
  if(state == IN_MENU) {
    drawMenu();
  }
 if(state == IN_GAMEA) {
    //Serial.println("gamA");
  //Serial.println(button1Status);
 
    drawBox();
  }
 
  if(state == IN_GAMEB) {
    if(frame % 1 == 0) { //every third frame
      ballX += ballVolX;
      ballY += ballVolY;
 
 // change if hit top or bottom
      if(ballY <= 1 || ballY >= TV.vres()-1)
     { ballVolY = -ballVolY;
                 delay(50);
  TV.tone( 2000,30  );  
     }
     
  // test left side for wall hit    
      if(ballVolX < 0 && ballX == LEFT_PADDLE_X+PADDLE_WIDTH-1 && ballY >= leftPaddleY && ballY <= leftPaddleY + PADDLE_HEIGHT) {
        ballVolX = -ballVolX;
        ballVolY += 2 * ((ballY - leftPaddleY) - (PADDLE_HEIGHT / 2)) / (PADDLE_HEIGHT / 2);
            delay(50);
  TV.tone(2000,30 );  
      }
     
 // test right side for wall hit    
      if(ballVolX > 0 && ballX == RIGHT_PADDLE_X && ballY >= rightPaddleY && ballY <= rightPaddleY + PADDLE_HEIGHT) {
        ballVolX = -ballVolX;
        ballVolY += 2 * ((ballY - rightPaddleY) - (PADDLE_HEIGHT / 2)) / (PADDLE_HEIGHT / 2);
            delay(50);
  TV.tone( 2000,30  );  
      }
 
      //limit vertical speed
      if(ballVolY > MAX_Y_VELOCITY) ballVolY = MAX_Y_VELOCITY;
      if(ballVolY < -MAX_Y_VELOCITY) ballVolY = -MAX_Y_VELOCITY;
 
 // Scoring
      if(ballX <= 1) {
        playerScored(RIGHT);
     // sound
     delay(50);
  TV.tone( 500,300 );  
      }
      if(ballX >= TV.hres() - 1) {
        playerScored(LEFT);
        // sound
        delay(50);
 TV.tone(  500,300 );
      }
    }
   
   
//    if(button1Status) Serial.println((int)ballVolX);
 
    drawGameScreen();
  }
 
  if(state == GAME_OVER) {
    drawGameScreen();
    TV.select_font(font8x8);
    TV.print(29,25,"GAME");
    TV.print(68,25,"OVER");
    while(!button1Status) {
      processInputs();
      delay(50);
    }
    TV.select_font(font4x6); //reset the font
    //reset the scores
    leftPlayerScore = 0;
    rightPlayerScore = 0;
    state = IN_MENU;
  }
 
 
  TV.delay_frame(1);
  if(++frame == 60) frame = 0; //increment and/or reset frame counter
}




Подключаем к TV и играем.



Сделано на основе статьи
www.makeuseof.com/tag/how-to-recreate-the-classic-pong-game-using-arduino
Для упрощения схемы убрана кнопка старта игры (теперь запускается автоматически) и внесены соответствующие изменения в код игры.
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.