Bouncing A Ball Off Keyboard Controlled Paddle

Hi, everyone -

Hopefully someone is able to direct me. I’m writing a program that has proven to be annoying several times over, and at this point am just sort of tearing my hair out. It’s similar to pong except with a ball affected by gravity, it’s a cooperative game designed around getting the ball into a certain spot.

I’ve managed to get the ball to respect collision on the mouse controlled paddle, but not one controlled by the keyboard–it just seems to pass through. I’ve tried a few code snippets I’ve found elsewhere and tried to edit around it, but no dice.

Anyone have a direction to point me? Included the ‘paddle’ (hands) code I have so far here. Maybe I’ve just been staring at it too long, I don’t know.

//Chef class
class Chef {  
  PVector pos, dir;

  Chef() {
    pos = new PVector(300, -300);
    dir = new PVector(5, 5);
  }

  //Hand variables
  color handColor = color(215, 176, 174);
  float handWidth = 50;
  float handHeight = 50;
  float handLocX = 500;
  float handLocY = 500;
  float handBounce = 20;


  //Draws the first hand. Attaches it to the mouse.
  void drawHand0() {
    fill(handColor);
    float mx = constrain(mouseX, 20, 500);
    rectMode(CENTER);
    rect(mx-25, mouseY, handWidth, handHeight);
  }

  //Draws the second hand. Attaches it to the keyboard. 
  void drawHand1() {
    fill(handColor);
    translate(pos.x, pos.y);
    rectMode(CENTER);      
    rect(handLocX, handLocY, handWidth, handHeight);
    move();
  }


  void move() {
    if (keys['a']) //move left 
      pos.x -= dir.x;
    if (keys['d']) //move right
      pos.x += dir.x;
    if (keys['w']) //move up
      pos.y -= dir.y;
    if (keys['s']) //move down
      pos.y += dir.y;
  }
}

void keyPressed() {
  keys[key] = true;
}

void keyReleased() {
  keys[key] = false;
}

void  handBounceDist0() {
  float overhead = mouseY - pmouseY;
  if ((meatX+(meatSize/2) > mouseX-(50/2)) && (meatX-(meatSize/2) < mouseX+(50/2))) {
    if (dist(meatX, meatY, meatX, mouseY)<=(meatSize/2)+abs(overhead)) {
      bottomBounce(mouseY);
      if (overhead<0) {
        meatY+=overhead;
        meatSpeed+=overhead;
      }
    }
  }
}
1 Like

I tried just swapping around the values in handBounceDist, creating a new segment to call named handBounceDist1, changing out any mouse reference to what I want to bounce it off of (ie, the meat ‘ball’ and the hand ‘paddle’). Though I got it to run, it didn’t actually seem to do anything. Wondering where the issue is, that doesn’t seem to be the way to go about it.

Tried messing around with constraints too, but quickly realized that wasn’t the route to go. Hrm.

I tried to help you but I would need the entire code or a runable version of it

This is the full code, if you think it’ll help. The ‘hand’ on the right is WASD controllable and I’m trying to get it so the ‘meat’ bounces off of it like it does for the mouse controlled one. Undoubtedly parts of it are sloppy, sorry about that - I’ve only been playing around with coding for a few weeks, a lot of it is way above my head still.

//Controls the game screen. 0 initial screen, 1 game, 2 game-over
int gameScreen = 0;

//Setup to call from Chef to handle keyboard movement fluidly
Chef myChef;


//Array to handle keys 
boolean [] keys = new boolean[128];


//Setup. Screen size. Chef creation.  
void setup() {
  size(1000, 1000);
  meatX=width/4;
  meatY=height/5;
  myChef = new Chef();
}

//Draw. Calls on the screen displays. 
void draw() {
  if (gameScreen == 0) {
    initScreen();
  } else if (gameScreen == 1) {
    gameScreen();
  } else if (gameScreen == 2) {
    gameOverScreen();
    myChef.drawHand1();
  }
}


//Chef class
class Chef {  
  PVector pos, dir;

  Chef() {
    pos = new PVector(300, -300);
    dir = new PVector(5, 5);
  }

  //Hand variables
  color handColor = color(215, 176, 174);
  float handWidth = 50;
  float handHeight = 50;
  float handLocX = 500;
  float handLocY = 500;
  float handBounce = 20;


  //Draws the first hand. Attaches it to the mouse.
  void drawHand0() {
    fill(handColor);
    float mx0 = constrain(mouseX, 20, 500);
    rectMode(CENTER);
    rect(mx0, mouseY, handWidth, handHeight);
  }

  //Draws the second hand. Attaches it to the keyboard. 
  void drawHand1() {
    fill(handColor);
    translate(pos.x, pos.y);
    rectMode(CENTER);      
    rect(handLocX, handLocY, handWidth, handHeight);
    move();
  }

  //Keyboard move commands
  void move() {
    if (keys['a']) //move left 
      pos.x -= dir.x;
    if (keys['d']) //move right
      pos.x += dir.x;
    if (keys['w']) //move up
      pos.y -= dir.y;
    if (keys['s']) //move down
      pos.y += dir.y;
  }
}

void keyPressed() {
  keys[key] = true;
}

void keyReleased() {
  keys[key] = false;
}

//
void  handBounceDist0() {
  float overhead = mouseY - pmouseY;
  if ((meatX+(meatSize/2) > mouseX-(50/2)) && (meatX-(meatSize/2) < mouseX+(50/2))) {
    if (dist(meatX, meatY, meatX, mouseY)<=(meatSize/2)+abs(overhead)) {
      bottomBounce(mouseY);
      if (overhead<0) {
        meatY+=overhead;
        meatSpeed+=overhead;
      }
    }
  }
}

//The kitchen variables. 
color kitchenColor = color(166, 164, 159);
float kitchenWidth = 65;
float kitchenHeight = 1500;
float kitchenLocX = 967;
float kitchenLocY = 700;
float wallWidth = 750;
float wallHeight = 80;

//Walls to be called/drawn
void drawKitchen() {
  fill(kitchenColor);
  rectMode(CENTER);
  rect(kitchenLocX, kitchenLocY, kitchenWidth, kitchenHeight);
}

void drawKitchen1() {
  fill(kitchenColor);
  rectMode(CENTER);
  rect(kitchenLocX-934, kitchenLocY, kitchenWidth, kitchenHeight);
}

void drawKitchen2() {

  fill(kitchenColor);
  rectMode(CENTER);
  rect(110, 970, wallWidth, wallHeight);
}

void drawKitchen3() {
  fill(kitchenColor);
  rectMode(CENTER);
  rect(890, 970, wallWidth, wallHeight);
}

//Meat Variables
float gravity = 1;
float meatSpeed = 0;
float meatSpeedX = 1;
float meatX, meatY;
float meatSize = 20;
int meatColor = color(255, 0, 0);
float slowDown = 0.0001;
float bigSlow = 0.1;
float x0 = 450;
float y0 = 900;
float x1 = 550;

//Show the meat
void drawMeat() {
  fill(meatColor);
  rect(meatX, meatY, meatSize, meatSize);
  if (meatX > x0 && meatX < x1 && meatY > y0) {
    score++;
  }
}


//Gravity for meat
void turnOnGravity() {
  meatSpeed += gravity;
  meatY += meatSpeed;
  meatSpeed -= (meatSpeed * slowDown);
}

//bottom and topBounce are to make the meant bounce
void bottomBounce(float surface) {
  meatY = surface-(meatSize/2);
  meatSpeed*=-1;
  meatSpeed -= (meatSpeed * bigSlow);
}

void topBounce(float surface) {
  meatY = surface+(meatSize/2);
  meatSpeed*=-1;
  meatSpeed -= (meatSpeed * bigSlow);
}

// keeps the meat in the screen
void screenBounce() {
  if (meatY+(meatSize/2) > height) { 
    bottomBounce(height);
  }
  if (meatY-(meatSize/2) < 0) {
    topBounce(0);
  }
  if (meatX-(meatSize/2) < 0) {
    leftBounce(0);
  }
  if (meatX+(meatSize/2) > width) {
    rightBounce(width);
  }
}

//Deals with left/right to go with the bottom and topBounces of earlier
void turnOnMeatSpeedX() {
  meatX += meatSpeedX;
  meatSpeedX -= (meatSpeedX * slowDown);
}
void leftBounce(float surface) {
  meatX = surface+(meatSize/2);
  meatSpeedX*=-1;
  meatSpeedX -= (meatSpeedX * bigSlow);
}
void rightBounce(float surface) {
  meatX = surface-(meatSize/2);
  meatSpeedX*=-1;
  meatSpeedX -= (meatSpeedX * bigSlow);
}

//Score variable
int score = 0;

//The startup screen
void initScreen() {
  background(150, 0, 0);
  textAlign(CENTER);
  textSize(25);
  text("YES, CHEF!", height/2, width/2-10);
  text("Instructions:", height/2+5, width/2+35);
  text("Use Mouse & Keyboard", height/2+5, width/2+70);
  text("Deliver Food Through Door", height/2+5, width/2+100);
  text("Score Before Time Runs Out!", height/2+5, width/2+130);
  text("Click To Continue", height/2+5, width/2+190);
}

//The actual game itself
void gameScreen() {
  background(255);
  timer();
  drawMeat();
  turnOnGravity();
  turnOnMeatSpeedX();
  screenBounce();
  myChef.drawHand0();
  handBounceDist0();
  drawKitchen();
  drawKitchen1();
  drawKitchen2();
  drawKitchen3();
  fill(0, 0, 0);
  textSize(25);
  textAlign(CENTER, TOP);
  text("SCORE: " +score, height/2, 100);
  line(500, 0, 500, 1000);
  myChef.drawHand1();
}

//The game over screen
void gameOverScreen() {
  background(0);
  textAlign(CENTER);
  fill(255);
  textSize(25);
  text("Game Over", height/2, width/2 - 20);
  textSize(25);
}


//Starts the game if we're on the initial screen
void mousePressed() {
  if (gameScreen==0) {
    startGame();
  }
}


// Sets the screen variable to start the game.   
void startGame() {
  gameScreen=1;
}

//Timer. Sets the variables for the time to two minutes.

String time;
int t;
int interval = 120;

//The actual timer. Switches to Game Over screen when ended, forces noLoop. 
void timer()
{
  fill(0, 0, 0);   
  t = interval-int(millis()/1000);
  time = nf(t, 0);
  if (t == 0) {
    gameOverScreen();
    noLoop();
  }
  text(time, 900, 100);
}
1 Like

That’s a really nice game!

I made a new function handBounceDist1(). Not sure what to do with overhead in this new function for the right hand. Please correct.

also in the class, I had to change drawHand1(); you had handLocX, handLocY AND pos for the hand position. Bad. I now have only pos.

Warmest regards,

Chrisir

Full code.


//Controls the game screen. 0 initial screen, 1 game, 2 game-over
int gameScreen = 0;

//Setup to call from Chef to handle keyboard movement fluidly
Chef myChef;

//Array to handle keys 
boolean [] keys = new boolean[128];

// -------------------------------------------------------------------------------

//Setup. Screen size. Chef creation.  
void setup() {
  size(1000, 1000);
  meatX=width/4;
  meatY=height/5;
  myChef = new Chef();
}//

//Draw. Calls on the screen displays. Runs on and on. 
void draw() {
  if (gameScreen == 0) {
    initScreen();
  } else if (gameScreen == 1) {
    gameScreen();
  } else if (gameScreen == 2) {
    gameOverScreen();
    myChef.drawHand1();
  }
}//

// -------------------------------------------------------------------------------
// Inputs 

void keyPressed() {
  keys[key] = true;
}

void keyReleased() {
  keys[key] = false;
}

//------------------------------------------------------------------------------------

//
void  handBounceDist0() {
  // meat bounces at hand 0
  float overhead = mouseY - pmouseY;
  if ((meatX+(meatSize/2) > mouseX-(50/2)) && (meatX-(meatSize/2) < mouseX+(50/2))) {
    if (dist(meatX, meatY, meatX, mouseY)<=(meatSize/2)+abs(overhead)) {
      bottomBounce(mouseY);
      if (overhead<0) {
        meatY+=overhead;
        meatSpeed+=overhead;
      }
    }
  }
}

void handBounceDist1() {  // ????    pos.x, pos.y
  // meat bounces at hand 1
  float overhead = 12; // mouseY - pmouseY;
  if ((meatX+(meatSize/2) > myChef.pos.x-(50/2)) && (meatX-(meatSize/2) < myChef.pos.x+(50/2))) {
    if (dist(meatX, meatY, meatX, myChef.pos.y)<=(meatSize/2)+abs(overhead)) {
      bottomBounce(myChef.pos.y); // ?????
      if (overhead<0) {
        meatY+=overhead;
        meatSpeed+=overhead;
      }
    }
  }
}

//------------------------------------------------------------------------------------

//The kitchen variables. 
color kitchenColor = color(166, 164, 159);
float kitchenWidth = 65;
float kitchenHeight = 1500;
float kitchenLocX = 967;
float kitchenLocY = 700;
float wallWidth = 750;
float wallHeight = 80;

//Walls to be called/drawn
void drawKitchen() {
  fill(kitchenColor);
  rectMode(CENTER);
  rect(kitchenLocX, kitchenLocY, kitchenWidth, kitchenHeight);
}

void drawKitchen1() {
  fill(kitchenColor);
  rectMode(CENTER);
  rect(kitchenLocX-934, kitchenLocY, kitchenWidth, kitchenHeight);
}

void drawKitchen2() {
  fill(kitchenColor);
  rectMode(CENTER);
  rect(110, 970, wallWidth, wallHeight);
}

void drawKitchen3() {
  fill(kitchenColor);
  rectMode(CENTER);
  rect(890, 970, wallWidth, wallHeight);
}

//Meat Variables
float gravity = 1;
float meatSpeed = 0;
float meatSpeedX = 1;
float meatX, meatY;
float meatSize = 20;
int meatColor = color(255, 0, 0);
float slowDown = 0.0001;
float bigSlow = 0.1;
float x0 = 450;
float y0 = 900;
float x1 = 550;

//Show the meat
void drawMeat() {
  fill(meatColor);
  rect(meatX, meatY, meatSize, meatSize);
  if (meatX > x0 && meatX < x1 && meatY > y0) {
    score++;
  }
}

//Gravity for meat
void turnOnGravity() {
  meatSpeed += gravity;
  meatY += meatSpeed;
  meatSpeed -= (meatSpeed * slowDown);
}

//bottom and topBounce are to make the meat bounce
void bottomBounce(float surface) {
  meatY = surface-(meatSize/2);
  meatSpeed*=-1;
  meatSpeed -= (meatSpeed * bigSlow);
}

void topBounce(float surface) {
  meatY = surface+(meatSize/2);
  meatSpeed*=-1;
  meatSpeed -= (meatSpeed * bigSlow);
}

// keeps the meat in the screen
void screenBounce() {
  if (meatY+(meatSize/2) > height) { 
    bottomBounce(height);
  }
  if (meatY-(meatSize/2) < 0) {
    topBounce(0);
  }
  if (meatX-(meatSize/2) < 0) {
    leftBounce(0);
  }
  if (meatX+(meatSize/2) > width) {
    rightBounce(width);
  }
}

//Deals with left/right to go with the bottom and topBounces of earlier
void turnOnMeatSpeedX() {
  meatX += meatSpeedX;
  meatSpeedX -= (meatSpeedX * slowDown);
}
void leftBounce(float surface) {
  meatX = surface+(meatSize/2);
  meatSpeedX*=-1;
  meatSpeedX -= (meatSpeedX * bigSlow);
}
void rightBounce(float surface) {
  meatX = surface-(meatSize/2);
  meatSpeedX*=-1;
  meatSpeedX -= (meatSpeedX * bigSlow);
}

//Score variable
int score = 0;

//The startup screen
void initScreen() {
  background(150, 0, 0);

  textAlign(CENTER);
  textSize(25);
  text("YES, CHEF!", height/2, width/2-10);
  text("Instructions:", height/2+5, width/2+35);
  text("Use Mouse & Keyboard", height/2+5, width/2+70);
  text("Deliver Food Through Door", height/2+5, width/2+100);
  text("Score Before Time Runs Out!", height/2+5, width/2+130);
  text("Click To Continue", height/2+5, width/2+190);
}

//The actual game itself
void gameScreen() {
  background(255);

  timer();

  drawMeat();

  turnOnGravity();
  turnOnMeatSpeedX();
  screenBounce();

  myChef.drawHand0();
  myChef.drawHand1();

  handBounceDist0();
  handBounceDist1();

  drawKitchen();
  drawKitchen1();
  drawKitchen2();
  drawKitchen3();

  fill(0, 0, 0);
  textSize(25);
  textAlign(CENTER, TOP);
  text("SCORE: " +score, height/2, 100);

  line(500, 0, 500, 1000);
}

//The game over screen
void gameOverScreen() {
  background(0);
  textAlign(CENTER);
  fill(255);
  textSize(25);
  text("Game Over", height/2, width/2 - 20);
  textSize(25);
}

//Starts the game if we're on the initial screen
void mousePressed() {
  if (gameScreen==0) {
    startGame();
  }
}

// Sets the screen variable to start the game.   
void startGame() {
  gameScreen=1;
}

//Timer. Sets the variables for the time to two minutes.

String time;
int t;
int interval = 120;

//The actual timer. Switches to Game Over screen when ended, forces noLoop. 
void timer()
{
  fill(0, 0, 0);   
  t = interval-int(millis()/1000);
  time = nf(t, 0);
  if (t == 0) {
    gameOverScreen();
    noLoop();
  }
  text(time, 900, 100);
}

// ============================================================================

//Chef class
class Chef {  
  PVector pos, dir;

  Chef() {
    pos = new PVector(300+500, -300+500);
    dir = new PVector(5, 5);
  }

  //Hand variables
  color handColor = color(215, 176, 174);
  float handWidth = 50;
  float handHeight = 50;
  //float handLocX = 500;
  //float handLocY = 500;
  float handBounce = 20;


  //Draws the first hand. Attaches it to the mouse.
  void drawHand0() {
    fill(handColor);
    float mx0 = constrain(mouseX, 20, 500);
    rectMode(CENTER);
    rect(mx0, mouseY, 
      handWidth, handHeight);
  }

  //Draws the second hand. Attaches it to the keyboard. 
  void drawHand1() {
    fill(handColor);
    pushMatrix(); 
    translate(pos.x, pos.y);
    rectMode(CENTER);      
    rect(0, 0, 
      handWidth, handHeight);
    move();
    popMatrix();
  }

  //Keyboard move commands
  void move() {
    if (keys['a']) //move left 
      pos.x -= dir.x;
    if (keys['d']) //move right
      pos.x += dir.x;
    if (keys['w']) //move up
      pos.y -= dir.y;
    if (keys['s']) //move down
      pos.y += dir.y;
  }
}//class
//
1 Like