Menü


/*************************************************************************************
  EZUBI | E-HACKS
  ARDUINO-AUDIO-PONG
 ************************************************************************************
  Arduino Pong
  By Pete Lamonica

  modified by duboisvb
  updated by James Bruce (http://www.makeuseof.com/tag/author/jbruce
  modified for audio input by Roland Batroff (http://www.kollektorbase.net/)
  updated for audio input by David Ziegler (http://www.goleon.de/)
 ****************************************************************************************/

#include "TVout.h"
#include "TVoutfonts/fontALL.h"

#define WHEEL_ONE_PIN 0  // ANALOG AUDIO INPUT 1
#define WHEEL_TWO_PIN 1  // ANALOG AUDIO INPUT 2
#define BUTTON_ONE_PIN 2 // BUTTON PIN

#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;

/*************************************************************************************
* VARIABLES FOR AUDIO INPUT AND SAMPLING
*************************************************************************************/

const int sampleWindow = 50; // Sample window width in mS (50 mS = 20Hz)
unsigned long startMillis = millis(); // Start of sample window

unsigned int sample_1;
unsigned int sample_2;

unsigned int peakToPeak_1 = 0;   // peak-to-peak level
unsigned int peakToPeak_2 = 0;

unsigned int signalMax_1 = 0;
unsigned int signalMax_2 = 0;
unsigned int signalMin_1 = 1024;
unsigned int signalMin_2 = 1024;

/*********************************************/

boolean button1Status = 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;

int damperOne[5];
int damperTwo[5];

void processInputs() {

  /*************************************************************************************
  * AUDIO SAMPLING FOR BOTH MICROPHONES
  *************************************************************************************/

  // collect data for 50 mS
  unsigned long startMillis = millis(); // Start of sample window

  unsigned int signalMax_1 = 0;
  unsigned int signalMin_1 = 512;

  unsigned int signalMax_2 = 0;
  unsigned int signalMin_2 = 512;

  while (millis() - startMillis < sampleWindow) {

    sample_1 = analogRead(0);
    sample_2 = analogRead(1);

    if (sample_1 < 1024) {
      if (sample_1 > signalMax_1) {

        signalMax_1 = sample_1;  // save just the max levels
      }
      else if (sample_1 < signalMin_1) {

        signalMin_1 = sample_1;  // save just the min levels
      }
    }

    if (sample_2 < 1024) {
      if (sample_2 > signalMax_2) {

        signalMax_2 = sample_2;  // save just the max levels
      }
      else if (sample_2 < signalMin_2) {

        signalMin_2 = sample_2;  // save just the min levels
      }
    }
  }
  /*************************************************************************************/


  /*************************************************************************************
  * Signal Smoothing via Dampervals
  *************************************************************************************/

  for (int i = 0; i < 4; i++) {
    damperOne[i] = damperOne[i + 1];
    damperTwo[i] = damperTwo[i + 1];
  }

  damperOne[4] = (signalMax_1 - signalMin_1) * 2;
  damperTwo[4] = (signalMax_2 - signalMin_2) * 2;

  int val1 = 0;
  int val2 = 0;

  for (int i = 0; i < 5; i++) {
    val1 += damperOne[i];
    val2 += damperTwo[i];
  }

  wheelOnePosition = val1 / 5;
  wheelTwoPosition = val2 / 5;

  button1Status = (digitalRead(BUTTON_ONE_PIN));

  if ((button1Status == HIGH) && (state == GAME_OVER)) {
    Serial.println("game over, drawing menu");
    drawMenu ();
  }

  /*************************************************************************************/
}

void drawGameScreen() {

  //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);
}


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, "E-HACKS");
  TV.print(10, 20, "Arduino Pong");
  TV.select_font(font4x6);
  TV.print(22, 45, "Press Button");
  TV.print(30, 55, "To Start");

  delay(1000);

  while (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()  {
  x = 0;
  y = 0;
  TV.begin(_NTSC);

  ballX = TV.hres() / 2;
  ballY = TV.vres() / 2;

  pinMode(BUTTON_ONE_PIN, INPUT_PULLUP);
}

void loop() {
  processInputs();

  if (state == IN_MENU) {
    drawMenu();
  }
  if (state == IN_GAMEA) {
    drawBox();
  }
  if (state == IN_GAMEB) {
    //every third frame
    if (frame % 3 == 0) {
      ballX += ballVolX;
      ballY += ballVolY;

      //change if hit top or bottom
      if (ballY <= 1 || ballY >= TV.vres() - 1) {
        ballVolY = -ballVolY;
        delay(100);
        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(100);
        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(100);
        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);
        delay(100);
        TV.tone( 500, 300 );
      }
      if (ballX >= TV.hres() - 1) {
        playerScored(LEFT);
        // sound
        delay(100);
        TV.tone(  500, 300 );
      }
    }
    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
}