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