tags:

views:

572

answers:

1

Hey peoples, I've been studying Java for a couple of weeks, and have decided to produce my own version of Breakout. The game is working fine, apart from the method which is supposed to modify the ball (GOval) speed based on the speed of the paddle (GRect). Anyway, this is the method:

private double paddleVelocity(){
      double paddleTracker=(paddleXTracker+paddleXTrackerTwo+paddleXTrackerThree)/3; //get the average x-coordinate for the paddle
      if(loopCounter>3){ //if the game has been through the loop more than three times (to ensure three x-coordinates have been stored)
       paddleVelocity=(paddle.getX()-paddleTracker)/50; //set paddleVelocity to the current paddle x-coordinate minus the average of the previous three paddle x-coordinates (which therefore finds the velocity and direction)
      }else{
       paddleVelocity=(paddle.getX()-paddleXTracker)/50; //takes the previous paddle x-coordinate and subtracts it from the current x-coordinate (which therefore finds the velocity and direction)
      }

      return (paddleVelocity);
     }

And this is the method that calls it:

         private void detectCollisionPaddle(){;
          double ballY = ball.getY()+(BALL_RADIUS*2);
          if(paddle.getY()<=ballY && ball.getX()+BALL_RADIUS>=paddle.getX() && ball.getX()+BALL_RADIUS/2<=(paddle.getX()+PADDLE_WIDTH)){ //a mess of code which ensures the ball is within the bounds of the paddle
           yVel=-yVel; //make the ball bounce off
           bounceClip.play(); //play the bounce clip
           xVel=xVel+paddleVelocity(); //increase the velocity of the ball in the direction and speed of the paddle
} }

The instance variables include:

private int loopCounter; //how many loops of the game code have been executed
private double paddleVelocity; //velocity of the paddle
private double paddleXTracker = 1; //value of the x-coordinate of the paddle one loop previous
private double paddleXTrackerTwo; //value of the x-coordinate of the paddle two loops previous
private double paddleXTrackerThree; //value of the x-coordinate of the paddle three loops previous
private double yVel = -1; //y velocity of the ball
private double xVel = 1; //x velocity of the ball

Basically I want paddleVelocity to grab three consecutive x-coordinates of the paddle, and compare them to the current position (paddle.getX()). This allows me to determine the speed and direction that the user has moved the paddle. I then return the result (paddleVelocity) which is supposed to add to the current velocity of the ball (xVel). However, this doesn't seem to function properly. When the call for paddleVelocity() is removed, the code works perfectly (albeit without acceleration). So I know there's an issue with the paddleVelocity method. It seems to be biased to the right side. Perhaps you guys can help, afterall, this is my first serious attempt at programming. Here's the game atm: http://cyb3rglitch.com/games/Glitchout_0.1/

Yes, the bricks don't break yet. :P Cheers!

EDIT: To make it easier, here's all the code in its messy glory:

/*
 * File: Breakout.java
 * -------------------
 * Name: Vito Cassisi
 */

import acm.graphics.*;
import acm.program.*;
import acm.util.*;

import java.applet.*;
import java.awt.*;
import java.awt.event.*;

public class Breakout extends GraphicsProgram {

/** Width and height of application window in pixels */
    public static final int APPLICATION_WIDTH = 400;
    public static final int APPLICATION_HEIGHT = 600;

/** Dimensions of game board (usually the same) */
    private static final int WIDTH = APPLICATION_WIDTH;
    private static final int HEIGHT = APPLICATION_HEIGHT;

/** Dimensions of the paddle */
    private static final int PADDLE_WIDTH = 60;
    private static final int PADDLE_HEIGHT = 10;

/** Offset of the paddle up from the bottom */
    private static final int PADDLE_Y_OFFSET = 30;

/** Number of bricks per row */
    private static final int NBRICKS_PER_ROW = 10;

/** Number of rows of bricks */
    private static final int NBRICK_ROWS = 10;

/** Separation between bricks */
    private static final int BRICK_SEP = 4;

/** Width of a brick */
    private static final int BRICK_WIDTH =
      (WIDTH - (NBRICKS_PER_ROW - 1) * BRICK_SEP) / NBRICKS_PER_ROW;

/** Height of a brick */
    private static final int BRICK_HEIGHT = 8;

/** Radius of the ball in pixels */
    private static final int BALL_RADIUS = 10;

/**Ball speed in milliseonds*/
    private static final int DELAY = 10;

/** Offset of the top brick row from the top */
    private static final int BRICK_Y_OFFSET = 70;

/** Number of turns */
    private static final int NTURNS = 3;

    private static final int COUNTDOWN = 200;

    private GOval ball;
    private GRect paddle;
    private GRect block;
    private GLabel life;
    private GLabel countDown;
    private GObject getObject;
    AudioClip bounceClip = MediaTools.loadAudioClip("bounce.au");

/* Method: run() */
/** Runs the Breakout program. */
    public void run() {
     drawBlocks();
     drawPaddle();
     drawBall();
     drawLife();
     addMouseListeners();

     while(!lose) {
      detectCollisionWall();
      detectCollisionBlock();
      detectCollisionPaddle();
      decelerate();
      assignPaddleTrackers();
      pause(DELAY);
      loopCounter++;
     }
     GLabel youLose = new GLabel("You lose!",APPLICATION_WIDTH/2,APPLICATION_HEIGHT/2);
     youLose.setLocation((getWidth()-youLose.getWidth())/2, (getHeight()-youLose.getAscent())/2);
     add(youLose);
    } 
     private void drawBlocks(){
     /**Draw as many rows as defined in the constant 'NBRICKS_PER_ROW'*/ 
      for(int i = 0;i<NBRICK_ROWS;i++){
       blockX=(APPLICATION_WIDTH-((BRICK_WIDTH+BRICK_SEP)*NBRICKS_PER_ROW))/2; //center the blocks horizontally
       drawRow(); //draw the row
       blockY+=BRICK_HEIGHT+BRICK_SEP; //move the row down
      }
     }

     private void drawRow(){
     /**Draw as many bricks as defined in the constant 'NBRICKS_PER_ROW'*/ 
      for(int i = 0;i<NBRICKS_PER_ROW;i++){
       block = new GRect(blockX,blockY,BRICK_WIDTH,BRICK_HEIGHT); //initialise the blocks
       add(block); //draw the blocks
       blockX+=BRICK_WIDTH+BRICK_SEP; //move x co-ordinate across
      }
     }

     private void drawPaddle(){
      paddle = new GRect((APPLICATION_WIDTH-PADDLE_WIDTH)/2,(APPLICATION_HEIGHT-PADDLE_Y_OFFSET-PADDLE_HEIGHT),PADDLE_WIDTH, PADDLE_HEIGHT);
      add(paddle);
     }

     private void drawBall(){
      double diameter = BALL_RADIUS*2;
      ball = new GOval((APPLICATION_WIDTH-diameter)/2,APPLICATION_HEIGHT-PADDLE_Y_OFFSET-PADDLE_HEIGHT*2-diameter,diameter,diameter);
      add(ball);
     }

     private void moveBall(){

      ball.move(xVel, yVel);
     }

     private void detectCollisionWall(){
      if(ball.getY()+(BALL_RADIUS*2)<getHeight() && ball.getY()>0 && ball.getX()+(BALL_RADIUS*2)<getWidth() && ball.getX()>0){
       moveBall();
      }
      if(ball.getY()+(BALL_RADIUS*2)>getHeight()){
       yVel=-yVel;
       turnsLeft--;
       testForLose();
       bounceClip.play();
      }
      if(ball.getY()<0){
       yVel=-yVel;
       bounceClip.play();
      }
      if(ball.getX()+(BALL_RADIUS*2)>=getWidth()){
       xVel=-xVel;
       bounceClip.play();
      }
      if(ball.getX()<=0){
       xVel=-xVel;
       bounceClip.play();
      }
      moveBall();
     }

     private void testForLose(){
      if(turnsLeft==0){
       lose=true;
       life.setLabel("You have "+turnsLeft+" lives!");
       return;
      }
      life.setLabel("You have "+turnsLeft+" lives!");
      remove(ball);
      drawBall();
      xVel=1;
      yVel=-1;
      drawCountDown();
     }

     private void drawCountDown(){
      GLabel countDown = new GLabel("",APPLICATION_WIDTH/2,APPLICATION_HEIGHT/2);
      for(int i=3;i>0;i--){
       countDown.setLabel("Respawn in: "+i);
       countDown.setLocation((getWidth()-countDown.getWidth())/2, (getHeight()-countDown.getAscent())/2);
       add(countDown);
       pause(COUNTDOWN);
      }
      countDown.setLabel("Go");
      countDown.setLocation((getWidth()-countDown.getWidth())/2, (getHeight()-countDown.getAscent())/2);
      pause(COUNTDOWN);
      remove(countDown);
     }

     private void drawLife(){
      life = new GLabel("You have "+turnsLeft+" lives!", APPLICATION_WIDTH/2,15);
      life.setLocation((getWidth()-life.getWidth())/2, 20);
      add(life);
     }

     private void detectCollisionBlock(){
      GObject collisionObject = detectObject(ball, BALL_RADIUS*2, BALL_RADIUS*2);
      if(collisionObject==block){
       remove(collisionObject);
       yVel=-yVel;
      }
     }

     private double paddleVelocity(){
      double paddleTracker=(paddleXTracker+paddleXTrackerTwo+paddleXTrackerThree)/3;
      if(loopCounter>3){
       paddleVelocity=(paddle.getX()-paddleTracker)/50;
       //paddleXTracker=paddle.getX();
      }else{
       paddleVelocity=(paddle.getX()-paddleXTracker)/50;
      }

      return (paddleVelocity);
     }

     private void detectCollisionPaddle(){;
      double ballY = ball.getY()+(BALL_RADIUS*2);
      //double ballX = ball.getX()+(BALL_RADIUS*2);
      /*if(ball.getY()+BALL_RADIUS*2>=paddle.getY() && ball.getX()+BALL_RADIUS*2>=paddle.getX() && ball.getX()<=paddle.getX()){
       ball.setLocation(ball.getX(),paddle.getY()-BALL_RADIUS*2-1);
      }*/
      if(paddle.getY()<=ballY && ball.getX()+BALL_RADIUS>=paddle.getX() && ball.getX()+BALL_RADIUS/2<=(paddle.getX()+PADDLE_WIDTH)){
       yVel=-yVel;
       bounceClip.play();
       xVel=xVel+paddleVelocity();
      /*
      int x = 4;
      int center = PADDLE_WIDTH/2;
      double parts=center/x;
      int location=0;
      if(ball.getX()+BALL_RADIUS*2>paddle.getX()&& ball.getX()<paddle.getX()+PADDLE_WIDTH){
      for(int i = 0;i<x;i++){
       if (ball.getX()<center+paddle.getX() && ball.getX()>(parts*i)+paddle.getX()){

       }else{
        location = i;
        break; 
       }

      }
      xVel=x/location;
      }
      }
      //

      if(ball.getX()+BALL_RADIUS<paddle.getX()+PADDLE_WIDTH/4){
       if(xVel!=1){
        if(xVel<0)
        {
         xVel=xVel-1;
        }else{
         xVel=-xVel-1;
        }
       }
      }
      if (ball.getX()>paddle.getX()+(PADDLE_WIDTH-PADDLE_WIDTH/4)){
       if(xVel>0){
        xVel=xVel+1;
       }else{
        xVel=-xVel+1;
       }
      }
      if (ball.getX()<paddle.getX()+(PADDLE_WIDTH-PADDLE_WIDTH/4) && ball.getX()+BALL_RADIUS>paddle.getX()+PADDLE_WIDTH/4){
       if(xVel>1){
        xVel=xVel-1;
       }
       if(xVel<-1){
        xVel=xVel+1;
       }
      }
      */
      }


     }

     public void mouseMoved(MouseEvent e){
      paddle.move((e.getX()-paddle.getX()-PADDLE_WIDTH/2),0);
     }

     /*Passes in an object to be checked, i.e. the ball, and asks for it's height and width. It returns the object if one is present, otherwise it retuns null.**/
     private GObject detectObject(GObject object, int width, int height){
      double right = object.getX()+width;
      double bottom = object.getY()+height;
      getObject = getElementAt(object.getX(),object.getY());

      if(getObject==null){
       getObject = getElementAt(right,object.getY());
      }else{
       return getObject;
      }

      if(getObject==null){
       getObject = getElementAt(object.getX(),bottom);
      }else{
       return getObject;
      }

      if(getObject==null){
       getObject = getElementAt(right,bottom);
      }else{
       return getObject;
      }

      if(getObject==null){
      return null;
      }else{
       return getObject;
      }

     }

     private void decelerate(){
      if(xVel<-1){
       xVel=xVel+0.01;
      }
      if(xVel>1){
       xVel=xVel-0.01;
      }
     }

     private void assignPaddleTrackers(){
      paddleXTrackerThree=paddleXTrackerTwo;
      paddleXTrackerTwo=paddleXTrackerThree;
      paddleXTracker=paddle.getX();
     }

    private int loopCounter;
    private double paddleVelocity;
    private double paddleXTracker = 1;
    private double paddleXTrackerTwo;
    private double paddleXTrackerThree;
    private double yVel = -1;
    private double xVel = 1;
    private int turnsLeft = NTURNS;
    private int blockY = BRICK_Y_OFFSET;
    private int blockX = 0;
    private static boolean lose = false;
    private RandomGenerator rgen = RandomGenerator.getInstance();

}
+2  A: 

I can't see where you are setting paddleXTracker and friends when paddle velocity is updated. So here are some possible fixes:

  1. You are not updating the past values continuously, only once at the start.
  2. you never updated the paddleXTrackerTwo and paddleXTrackerThree values so the average is to the left (due to divide by 3), if origin is on the left (likely).

Both of these would account for the right bias you are seeing.

Further, you appear to be doing an adhoc version of moving average. There are other variations which maybe more suited to what you are trying to do.

edit

Now that your full code is available, I can't see what is wrong. I can only suggest you employ debugging techniques, such as printing out the paddle*Tracker* while the game is running to see what values are coming out, and whether or not they are as expected.

edit 2

Just to make this answer an answer, as per our OOB discussion, your assign tracker function is wrong, and is not updating paddleXTrackerTwo with paddleXTracker.

freespace
Oh hi Freespace, fancy an Atomican answering my Q. :PI update the values every loop. I updated the OP with the entire code to make things clear (yes, it's messy).BTW, this is Cyb3rGlitch. :P
Glitch
Yes I noticed that :P I didn't want to say anything just in case it was all a coincidence :P
freespace
Gotta love those Stanford Uni lectures, I never thought I could develop a game after two weeks of learning Java. :)Just gotta work this issue out.
Glitch
Hmm, it's odd.I'm not sure if I'm using the debugger correctly, but it seems to limit the negative values to -1 (i.e. the smallest value paddleVelocity is assigned is -1). What is the range of numbers that a 'double' can be assigned with? I'm sure it can be less than -1, can't it?
Glitch
Yes, the issue is not with double. How are you getting the value out? Also, what are the values of paddleXTracker{,Two,Three}? Also consider moving this discussion into email or something, I don't think this is how SO is suppose to be used.
freespace
What's your e-mail address?The trackers are defined by this method: private void assignPaddleTrackers(){ paddleXTrackerThree=paddleXTrackerTwo; paddleXTrackerTwo=paddleXTrackerThree; paddleXTracker=paddle.getX(); }
Glitch
I will send you message via your website :)
freespace