Paddle paddle = new Paddle(0, 0);
Paddle player;
Paddle enemy;
Circle circle;
int rand;
float fRand;

void setup() {
  size (640, 480);
  smooth();
  noStroke();
  noCursor();
  rectMode(CENTER);
  ellipseMode(CENTER);
  
  fill(255);
 
  // Create the paddle and circle objects.
  player = new Paddle(20, (height/2) - (paddle.getPHeight()/2));
  enemy = new Paddle(width-20, (height/2) - (paddle.getPHeight()/2));
  circle = new Circle(width/2, height/2);
  
  float fRand = random(0, 1.99);
  int rand = int(fRand);
} 
  
void draw() {
  background(60);
  
  circle.drawCircle();
  player.drawPaddle();
  enemy.drawPaddle();
 
  circle.move();
  if (outOfBounds()) {
     circle.reset();
     player.reset(20, (height/2) - (paddle.getPHeight()/2));
     enemy.reset(width-20, (height/2) - (paddle.getPHeight()/2));
  }
  
  if (enemyPaddleCol() || playerPaddleCol()) {
    circle.changeDirection();
  }
  
  // Enemy movement
  if (circle.y > enemy.y) {
    enemy.y += enemy.speed;
  } else {
    enemy.y -= enemy.speed;
  }
  
  // Keyboard controls
  if (keyPressed) {
    if (key == CODED) {
      if (keyCode == UP) {
        if (player.getPTop() >= 20) {
          player.y -= 3;
        }
      }
      if (keyCode == DOWN) {
        if (player.getPBottom() <= height-20) {
          player.y += 3;
        }  
      }
    } else if (key == 'r') {
       delay(1000);
       circle.reset();
       player.reset(20, (height/2) - (paddle.getPHeight()/2));
       enemy.reset(width-20, (height/2) - (paddle.getPHeight()/2));
    }
  }
}

// Boundary Testing
  boolean outOfBounds() {
    if (circle.x - circle.radius <= 0)
      return true;
    if (circle.y + circle.radius <= 0) {
      circle.changeDirection('y');
      return false;
    }
    if (circle.y + circle.radius >= height) {
      circle.changeDirection('y');
      return false;
    }
    if (circle.x + circle.radius >= width) 
      return true;
    return false;
  }
  
  boolean enemyPaddleCol() {
    if (circle.x + circle.radius >= enemy.getPLeft() &&
       (circle.y - circle.radius <= enemy.getPBottom()) &&
       (circle.y + circle.radius >= enemy.getPTop())) {
      circle.speedX += 0.065;
      circle.speedY += 0.05;
      enemy.speed += 0.08;
      return true;
    }
    return false;
  }
  
  boolean playerPaddleCol() {
   if (circle.x - circle.radius <= player.getPRight() &&
      (circle.y - circle.radius <= player.getPBottom()) &&
      (circle.y + circle.radius >= player.getPTop())) {
      circle.speedX += 0.065;
      circle.speedY += 0.05;
      enemy.speed += 0.08;
      return true;
    }
    return false;
  }
  
// Classes
  class Paddle {
    private float x, y;
    private int pWidth  = 20;
    private int pHeight = 60;
    
    public float speed = 1;
    
    // Instantiators
    public Paddle(float x, float y) {
      this.x = x;
      this.y = y; 
    }
    
    // Mutators
    public void setX(int x) {
      this.x = x;
    }
    
    public float getX() {
      return this.x;
    }
    
    public void setY(int y) {
      this.y = y;
    }
    
    public float getY() {
      return this.y;
    }
    
    public int getPWidth() {
      return this.pWidth;
    }
    
    public int getPHeight() {
      return this.pHeight;
    }
    
    public float getPTop() {
      return this.y - this.pHeight/2;    
    }
    
    public float getPBottom() {
      return this.y + this.pHeight/2;
    }
    
    public float getPLeft() {
      return this.x - this.pWidth/4;    
    }
    
    public float getPRight() {
      return this.x + this.pWidth/4;
    }
    
    public void drawPaddle() {
      rect(this.x, this.y, this.pWidth, this.pHeight);
    }
    
    public void reset(int x, int y) {
     this.x = x;
     this.y = y;
    }
  }
 
 class Circle {
    private float diameter = 10;
    private float radius   = this.diameter/2; 
    
    public int x, y;
    
    public float speedX = 3.5;
    public float speedY = 1.8;
    
    public int[] directions = { 1, -1 };
    public int directionX = this.directions[rand];
    public int directionY = this.directions[rand];

    // Instantiators
    public Circle(int x, int y) {
      this.x = x;
      this.y = y;
    }
    
     // Mutators
    
    public void move() {
      this.x += this.speedX * this.directionX;
      this.y += this.speedY * this.directionY;
    }
    
    public void changeDirection() {
       this.directionX *= -1;
       this.directionY *= -1;
    }
    
    public void changeDirection(char c) {
        if (c == 'x') {
          this.directionX *= -1;
        } else if (c == 'y') {
          this.directionY *= -1;
        }
    }
    
    public void reset() {
     this.x = width/2;
     this.y = height/2;
     
     fRand = random(0, 1.99);
     rand = int(fRand);
     this.directionX = this.directions[rand];
     
     fRand = random(0, 1.99);
     rand = int(fRand);
     this.directionY = this.directions[rand]; 
     
     this.speedX = 3.5;
     this.speedY = 1.8;
    }
    
    public void drawCircle() {
      ellipse(this.x, this.y, this.diameter, this.diameter);
    }
  }