Analog Pong

Analog Pong is a simple demo I made at SparkFun to demonstrate how you might use different analog sensors to interface with Processing.  Basically, you hook up any two analog sensors you want, and use them to control the paddles on the left and right of the screen. The nice thing about this project is that it provides a nice platform for introducing a lot of nice concepts: different kinds of analog sensors, how to communicate between Arduino and Processing, and a bit of Object Oriented Programming in Processing as well.  Plus, every programmer should know how to program pong.  If you’re not so sure how to hook up analog inputs to your Arduino, here’s a link.  Note:  Depending on the range of the analog sensors you’re using, you may have to adjust the code so the paddle covers the height of the screen.  Hint: Take a close look at the Processing code for some fun easter eggs.

/* Analog Pong for Processing
 *  Reads in 2 sensor values connected to an Arduino for the paddle controls
 *  by Ben Leduc-Mills
 *  This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license)
 */
 
import processing.serial.*; //import serial library
 
Serial myPort;
PFont myFont; //init font for text
Paddle leftPaddle, rightPaddle; //paddle objects
Ball ball; //ball object
int padWidth = 15;
int padHeight = 60;
int leftPaddlePos = 0;
int rightPaddlePos = 0;
int distWall = 15; //paddle distance from wall
float lpp; //scaled left paddle position
float rpp; //scaled right paddle position
 
int playerOne = 0; //player 1 score (left paddle)
int playerTwo = 0; //player 2 score (right paddle)
boolean oneWins = false;
boolean twoWins = false;
 
boolean firstContact = false; // Whether we've heard from the microcontroller
 
void setup() {
  size(1000,600);
  frameRate(20);
  smooth();
  rectMode(CENTER);
  ellipseMode(CENTER);
  myFont = createFont("FFScala", 16);
  textFont(myFont);
  println(Serial.list()); //list serial ports
  myPort = new Serial(this, Serial.list()[0], 9600); //init serial object (picks 1st port available)
  myPort.bufferUntil('\n');
  leftPaddle = new Paddle(padWidth, padHeight, distWall, leftPaddlePos); //init right paddle (width, height, x, y)
  rightPaddle = new Paddle(padWidth, padHeight, width - distWall, rightPaddlePos); //init left paddle
  ball = new Ball(15, width/2, height/2, 8, 2, 1, 1); 
  //init ball (size, x, y, x speed, yspeed, x direction, y direction)
}
 
void draw() {
}
 
void serialEvent(Serial myPort) {
 
  background(0);
  showGUI(); //shows scores, etc. (see GUI tab)
  ball.display(); 
  ball.update();
 
  String myString = myPort.readStringUntil('\n');
  // if you got any bytes other than the linefeed:
  if (myString != null) {
 
    myString = trim(myString);
 
    // if you haven't heard from the microncontroller yet, listen:
    if (firstContact == false) {
      if (myString.equals("hello")) { 
        myPort.clear();          // clear the serial port buffer
        firstContact = true;     // you've had first contact from the microcontroller
        myPort.write('A');       // ask for more
        println("contact");
      }
    } 
    // if you have heard from the microcontroller, proceed:
    else {
      // split the string at the commas
      // and convert the sections into integers:
      int sensors[] = int(split(myString, ','));
 
      // print out the values you got:
      //      for (int sensorNum = 0; sensorNum < sensors.length; sensorNum++) {
      //        println("Sensor " + sensorNum + ": " + sensors[sensorNum]);
      //      }
 
      if(sensors.length > 1) {
 
        leftPaddlePos = sensors[0];
        rightPaddlePos = sensors[1];
 
        lpp = (float)leftPaddlePos;
        rpp = (float)rightPaddlePos;
        //println("right: " + rpp + " " + "left: " + lpp);
        //println(lpp);
 
        //adjust these mapping functions to fit the sensors values you're receiving 
        lpp = map(lpp, 0, 1023, 1, height);
        rpp =  map(rpp, 130, 270, 1, height); //flex sensor
 
          leftPaddle.display(lpp);
          rightPaddle.display(rpp);
 
      }
      // when you've parsed the data you have, ask for more:
      myPort.write("A");
    }
  }
}
 
void keyPressed() {
  ball.keyPressed();
}
 
//class for pong balls
 
class Ball {
 
  int bSize; //ball size (yeah, yeah, I know)
  float xpos, ypos; //starting position in X and Y
  float xspeed, yspeed; //speed
  float xdir, ydir; //direction
 
  //Constructor
  Ball(int ibSize, float ixpos, float iypos, float ixspeed, float iyspeed, float ixdir, float iydir) {
 
    bSize = ibSize;
    xpos = ixpos;
    ypos = iypos;
    xspeed = ixspeed;
    yspeed = iyspeed;
    xdir = ixdir;
    ydir = iydir;
  }
 
  void update() {
 
    //move
    xpos = xpos + (xspeed * xdir);
    ypos = ypos + (yspeed * ydir);
 
    //if hits paddle, change direction
    if ((xpos > rightPaddle.xPos - bSize && xpos < width - bSize && 
      ypos < rpp + rightPaddle.pHeight/2 - bSize && 
      ypos > rpp - rightPaddle.pHeight/2 - bSize) || 
      (xpos < leftPaddle.xPos + bSize && xpos < 0 + bSize &&
      ypos < lpp + leftPaddle.pHeight/2 - bSize &&
      ypos > lpp - leftPaddle.pHeight/2 - bSize) )
 
    {
      xdir *= -1;  //change ball direction
    }
 
    if (xpos > width-bSize) { //player one scored
      playerOne++;
      if (playerOne < 7) {
        //println(playerOne);
        reset();
      }
      else if (playerOne == 7) { //player one won
        oneWins = true;
        xpos = width/2;
        ypos = height/2;
        xdir = 0;
        ydir = 0;
      }
    }
 
    if(xpos < 0) { //player two scored
 
      playerTwo++; //player two gets a point
 
      if(playerTwo < 7) {
        //println(playerTwo);
        reset();
      }
      else if (playerTwo == 7) { //player 2 won
        twoWins = true;
        xpos = width/2;
        ypos = height/2;
        xdir = 0;
        ydir = 0;
      }
    }
 
    if(ypos > height-bSize || ypos < 0) { //ball hits top or bottom
      ydir *= -1;
    }
  }
 
  void display() {
    //draw ball to screen
    ellipse(xpos+bSize/2, ypos+bSize/2, bSize, bSize);
  }
 
  void reset() {
    //reset for a new game
    xpos = width/2;
    ypos = height/2;
    ydir = random(-1, 1);
    float dir = random(-1, 1);
    if (dir > 0) {
      xdir = 1;
    }
    else if (dir <= 0) {
      xdir = -1;
    }
  }
 
  void keyPressed() {
 
    //key presses
    if(keyCode=='R') {
      newGame();
    }
 
    if(keyCode=='1') {
      bSize++;
    }
    if(keyCode=='2') {
      bSize--;
    }
    if(keyCode=='3') {
      leftPaddle.pHeight++;
    }    
    if(keyCode=='4') {
      leftPaddle.pHeight--;
    }
    if(keyCode=='5') {
      rightPaddle.pHeight++;
    }    
     if(keyCode=='6') {
      rightPaddle.pHeight--;
    }
  }
 
  void newGame() {
 
    playerOne = 0;
    playerTwo = 0;
    oneWins = false;
    twoWins = false;
    reset();
  }
}
 
//class for paddles
 
class Paddle {
 
 float pWidth;
 float pHeight;
 float yPos;
 float xPos;
 
 Paddle(float ipWidth, float ipHeight, float ixPos, float iyPos) {
 
  pWidth = ipWidth;
  pHeight = ipHeight;
  xPos = ixPos;
  yPos = iyPos; 
 }
 
 void display(float yPos) {
 
  noStroke();
  fill(255); 
  rect(xPos, yPos, pWidth, pHeight);
 
 }
 
}
 
//game text
void showGUI() {
 
  stroke(255);
  line(width/2, 0, width/2, height);
 
  textSize(16);
  text("Player 1: " + playerOne, 100, 20); // player 1 score display
  text("Player 2: " + playerTwo, 600, 20);  // play 2 score display
 
  if (oneWins == true) { //if player one wins
    textSize(24);
    text("Player 1 WINS!!!", width/2 - 95, height/2 -50);
    text("Press 'R' for New Game", width/2 - 135, height/2 - 20);
  }
 
  if (twoWins == true) { //if player two wins
    textSize(24);
    text("Player 2 WINS!!!", width/2 - 95, height/2-50);
    text("Press 'R' for New Game", width/2 - 135, height/2 - 20);
  }
}

 

And here’s the Arduino Code:

/*
 * AnalogPong for Arduino
 * Reads in 2 sensor values as paddles to send to a processing sketch
 *  by Ben Leduc-Mills
 *  This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license)
 */
 
void setup() {
  Serial.begin(9600);
  establishContact();
}
 
void loop() {
 if (Serial.available() > 0) {
    // read the incoming byte:
    int inByte = Serial.read();
    int leftPaddle = analogRead(A0);
    Serial.print(leftPaddle, DEC);
    Serial.print(",");
    int rightPaddle = analogRead(A1);
    Serial.println(rightPaddle, DEC);
    // Serial.println(rightPaddle, DEC);
    //Serial.println(leftPaddle, DEC);
  }
}
 
void establishContact() {
  while (Serial.available() <= 0) {
    Serial.println("hello");   // send a starting message
    delay(300);
  }
}