|
About the Author
|
| Vijay is an Information Systems Architect at CVS Pharmacy in Rhode Island. His primary focus is J2EE technology based solution Design and Development. Along with a combination of other enterprise technologies he believes that J2EE will become a primary driving force in the delivery of enterprise level systems. Vijay has participated in numerous consulting projects over the past six years. He has a Masters in Computer Science and a Sun Certified Java Programmer and Architect. His projects involve UML, Java, JSP/Servlets, EJB's, CORBA, XML, JMS, MQSeries & various tools. He has provided onsite J2EE and/or XML development at high-tech companies located in and around Massachusetts, CT and RI. He has also published articles on Java Programming, C++ and other technologies, in various online magazines and with other consultants and is a frequent writer on Java and related technologies. He can be reached at vijay (at) javareference (dot) com
|
More articles by Vijay Kukreja
|
|
|
|
Lets start playing our game
In this part I will add the remaining touches, i.e. collision
detection and making the brick disappear. Enhancements to this game
are only limited by ones imagination. First of all lets add different
directions to the motion of the ball.
We will use a simple direction logic. Let us assume that the upper
part of the screen is the north. The lower is south and the left is
east and right is west. Similarly we can have north east, north west,
south east and south west. For our purposes we will use one variable
for direction and two distance variables.

Lets look at the code first :
/* * A
simple brick game in Java. * Program
Name: Bricks a simple a Java Game. *
File Name : BricksGame * Author:
Vijay Kukreja * Date: 5-August-2001 *
Version : 1.0 */
package JavaGames;
//Lets
keep all our files under one package //lets
import the necessary classes to which will create the
GUI
import java.awt.*; import java.awt.event.*; import java.awt.Color; //new
import in this article for keyboard
handling import java.awt.event.KeyEvent;
//our
main class for the application now implements runnable interface
indicating //that there are threads
in the system then the run method would be
executed.
public class BricksGame extends Frame implements Runnable , KeyListener
//Some
variable declarations //Let
us declare those here and use them in our
wall. BricksEntity mBrick[]; BallEntity mBall; BatEntity mBat; int iFramex=0; int iFramey=0; int iFrameh=500; int iFramew=800; //declare
a thread variable which will be taking care of animation of
ball Thread bounceBall=null;
//the
constructor where we'll initialize our environment and create the
frame
public BricksGame() { this.setBounds(iFramex,iFramey,iFramew,iFrameh); this.setTitle("Welcome to Bricks Game"); //The
bricks need to be in an array as there are more than one bricks
and //its
easier logically to handle these
bricks. mBrick=new BricksEntity[10]; //initialise
the bricks before the paint is
called. initBrick(); //Let
us create live objects out of our entity
classes. mBall=new BallEntity(); mBat=new BatEntity(); //initialize
the sizes of the bricks and ball and
bat initBall(); initBat(); //call
paint so it refreshes the whole
scene. this.setVisible(true); //create
the instance of the thread which will be taking care //of
the balls
motion bounceBall = new Thread(this); //start
the execution of this thread
now bounceBall.start();
//adding
the Key Listening capability to our
program this.addKeyListener(this); {} //this
is the method we want for our arrow
keys public void keyPressed(KeyEvent e) //lets
take out the code of which key was
pressed. int keyCode = e.getKeyCode(); //now
lets switch for our arrow
keys int tempMove=mBat.getLeft(); switch(keyCode) { case java.awt.event.KeyEvent.VK_LEFT: //left
arrow
key tempMove-=15; break; case java.awt.event.KeyEvent.VK_RIGHT: //right
arrow
key tempMove+=15; break; {} //lets
move it mBat.setLeft(tempMove); //lets
refresh the screen this.repaint(); } //
we don't have to do anything
here public void keyTyped(KeyEvent e) {} //
we have nothing to do here
also. public void keyReleased(KeyEvent e) {} public void run() //variables
for storing direction of the ball and its amount of
distance //by
which we move it in the next movement int direction=5; //1
north //2
south //3
east //4
west //5
north east //6
north west //7
south east //8
south
west
int dist1=10; int dist2=5;
//continue
till the program
ends while(true) { //just
a temporary variable for storing intermediate ball
position int tempTop=0; int tempLeft=0; //check
and see which direction the ball is going //if
direction is set to go up i.e. 2 then subtract
distance //if
direction is set to go down then add
distance switch(direction) { case 1: //north tempTop=mBall.getTop()+dist1; break; case 2 : //south tempTop=mBall.getTop()-dist1; break; case 3: //east tempTop=mBall.getLeft()-dist2; break; case 4: //west tempTop=mBall.getLeft()+dist2; break; case 5: //north
east tempTop=mBall.getTop()-dist1; tempLeft=mBall.getLeft()-dist2; break; case 6: //north
west tempTop=mBall.getTop()-dist1; tempLeft=mBall.getLeft()+dist2; break; case 7: //south
east tempTop=mBall.getTop()+dist1; tempLeft=mBall.getLeft()-dist2; break; case 8: //south
west tempTop=mBall.getTop()+dist1; tempLeft=mBall.getLeft()+dist2; break; {} //update
the balls position in the
datastructure mBall.setTop(tempTop); mBall.setLeft(tempLeft); //if
you have reached bottom change
directions if(mBall.getTop()>=350 && direction==1) //coming
north now go south direction=2; //if
you have reached the top change
directions if(mBall.getTop()<=50 && direction==2) //coming
south now go
north direction=1; if(mBall.getLeft()<=50 && direction==3) //coming
east now go
west direction=4; if(mBall.getLeft()>=450 && direction==4) //coming
east now go
west direction=3; if( (mBall.getLeft()<=50 || mBall.getTop()<=50) && direction==5) //coming
north east now go south
west direction=8; if((mBall.getLeft()>=450 || mBall.getTop()<=50) && direction==6) //coming
north west now go south
east direction=7; if((mBall.getLeft()<=50 || mBall.getTop()>=350) && direction==7) //coming
south east now go north
west direction=6; if((mBall.getLeft()>=450 || mBall.getTop()>=350 ) && direction==8) //coming
north east now go south
west direction=5; //redraw
the ball at new
locations this.repaint(); //putting
the thread to sleep so we can create some delay //so
the ball's motion looks
natural. try Thread.sleep(300); //
as thread.sleep needs that it be inside try and catch
block. //
when a thread is put to sleep it can throw and
exception. //
read article for details on try catch
blocks. {} catch(Exception e) System.out.println("Error in running thread " + e); {} } }
public void paint(Graphics g) //setCOlor()
method is used to set the color by which you will be filling the
object g.setColor(Color.red); for(int i=0;i<10;i++) { g.fillRect(mBrick[i].getLeft(),mBrick[i].getTop(),mBrick[i].getWidth(),mBrick[i].getHeight()); {} g.setColor(Color.blue); g.fillRect(mBat.getLeft(),mBat.getTop(),mBat.getWidth(),mBat.getHeight()); g.setColor(Color.green); g.fillOval(mBall.getLeft(),mBall.getTop(),mBall.getHeight(),mBall.getWidth()); }
public void initBrick() int j=0; //initialize
all the bricks in the
list. for(int i=0;i<10;i++) { mBrick[i]=new BricksEntity(); mBrick[i].setTop(30); mBrick[i].setLeft(j); mBrick[i].setHeight(30); mBrick[i].setWidth(80); //next
brick left
position j=j+82; {} } public void initBall() mBall.setTop(150); mBall.setLeft(100); mBall.setHeight(40); mBall.setWidth(40); {} public void initBat() mBat.setTop(400); mBat.setLeft(100); mBat.setHeight(20); mBat.setWidth(100); {}
//the
main method the entry point into our game
program. public static void main(String[] args) System.out.println("Welcome to the Bricks Game!"); BricksGame m_bricksGame=new BricksGame(); {}
//In
case someone wants to close the program from the Frame we need
to //process
the window closing event and handle it
appropriately
protected void processWindowEvent(WindowEvent e) super.processWindowEvent(e); if (e.getID() == WindowEvent.WINDOW_CLOSING) { System.exit(0); //close
the window and exit out of the program. {} } }
I have added the various integer values to represent the various
directions. As you can see the checks involve in testing for two
conditions, the left and the top as well as the current direction the
ball is traveling in. Accordingly we change the direction of the ball
to the new direction. If the ball is coming from the bottom to the
top and there is a collision to the top wall we make it go towards
the bottom.
Similarly if its coming from the south west i.e. bottom right then
we make it go in the top left direction. You will notice two
conditions east and west i.e. left and right will never get invoked
as the ball does not travel horizontally. I left them there as the
flow is easier to understand that way.
Going further this is not the perfect collision detection logic.
We've used this just so that you get an idea. Please feel free to
modify the logic to suit your needs. Also the consideration of the
bat colliding with the ball is still remaining. I leave it to you to
add that part.
A rough explanation of the logic which can be used to achieve that
is explained to make thing simpler. As seen in the diagram above, if
the ball hits the bat on the 25% left area then we can make it go in
a different direction. If it hits the bat in the 50% middle area then
we can make it go in different direction and similary for the
remaining 25%. You can make it 10% and 10 different zones on the bat
to make the game more interesting.

Now coming to the removal of bricks on collision, A brick has to
be just disabled from the display once its been hit by the ball. The
code changes for this are given below :
/* * A
simple brick game in Java. * Program
Name: Bricks a simple a Java Game. *
File Name : BricksGame * Author:
Vijay Kukreja * Date: 5-August-2001 *
Version : 1.0 */
package JavaGames;
//Lets
keep all our files under one package //lets
import the necessary classes to which will create the
GUI
import java.awt.*; import java.awt.event.*; import java.awt.Color; //new
import in this article for keyboard
handling import java.awt.event.KeyEvent;
//our
main class for the application now implements runnable interface
indicating //that there are threads
in the system then the run method would be
executed.
public class BricksGame extends Frame implements Runnable , KeyListener
//Some
variable declarations //Let
us declare those here and use them in our
wall. BricksEntity mBrick[]; BallEntity mBall; BatEntity mBat; int iFramex=0; int iFramey=0; int iFrameh=500; int iFramew=800; //declare
a thread variable which will be taking care of animation of
ball Thread bounceBall=null;
//the
constructor where we'll initialize our environment and create the
frame
public BricksGame() { this.setBounds(iFramex,iFramey,iFramew,iFrameh); this.setTitle("Welcome to Bricks Game"); //The
bricks need to be in an array as there are more than one bricks
and //its
easier logically to handle these
bricks. mBrick=new BricksEntity[10]; //initialise
the bricks before the paint is
called. initBrick(); //Let
us create live objects out of our entity
classes. mBall=new BallEntity(); mBat=new BatEntity(); //initialize
the sizes of the bricks and ball and
bat initBall(); initBat(); //call
paint so it refreshes the whole
scene. this.setVisible(true); //create
the instance of the thread which will be taking care //of
the balls
motion bounceBall = new Thread(this); //start
the execution of this thread
now bounceBall.start();
//adding
the Key Listening capability to our
program this.addKeyListener(this); {} //this
is the method we want for our arrow
keys public void keyPressed(KeyEvent e) //lets
take out the code of which key was
pressed. int keyCode = e.getKeyCode(); //now
lets switch for our arrow
keys int tempMove=mBat.getLeft(); switch(keyCode) { case java.awt.event.KeyEvent.VK_LEFT: //left
arrow
key tempMove-=15; break; case java.awt.event.KeyEvent.VK_RIGHT: //right
arrow
key tempMove+=15; break; {} //lets
move it mBat.setLeft(tempMove); //lets
refresh the screen this.repaint(); } //
we don't have to do anything
here public void keyTyped(KeyEvent e) {} //
we have nothing to do here
also. public void keyReleased(KeyEvent e) {} public void run() //variables
for storing direction of the ball and its amount of
distance //by
which we move it in the next movement int direction=5; //1
north //2
south //3
east //4
west //5
north east //6
north west //7
south east //8
south
west
int dist1=10; int dist2=5;
//continue
till the program
ends while(true) { //just
a temporary variable for storing intermediate ball
position int tempTop=0; int tempLeft=0; //check
and see which direction the ball is going //if
direction is set to go up i.e. 2 then subtract
distance //if
direction is set to go down then add
distance switch(direction) { case 1: //north tempTop=mBall.getTop()+dist1; break; case 2 : //south tempTop=mBall.getTop()-dist1; break; case 3: //east tempTop=mBall.getLeft()-dist2; break; case 4: //west tempTop=mBall.getLeft()+dist2; break; case 5: //north
east tempTop=mBall.getTop()-dist1; tempLeft=mBall.getLeft()-dist2; break; case 6: //north
west tempTop=mBall.getTop()-dist1; tempLeft=mBall.getLeft()+dist2; break; case 7: //south
east tempTop=mBall.getTop()+dist1; tempLeft=mBall.getLeft()-dist2; break; case 8: //south
west tempTop=mBall.getTop()+dist1; tempLeft=mBall.getLeft()+dist2; break; {} //update
the balls position in the
datastructure mBall.setTop(tempTop); mBall.setLeft(tempLeft); //brick
collision logic here. if hit then hide
brick. for(int i=0;i<10;i++) if(mBrick[i].enabled==true) { if( (mBrick[i].getLeft() <= tempLeft) && ( tempTop <= (mBrick[i].getTop()+mBrick[i].getHeight()) ) && ( mBrick[i].getLeft()+ mBrick[i].getWidth()) >= tempLeft ) { mBrick[i].enabled=false; {} } } if(mBall.getTop()>=350 && direction==1) //coming
north now go south direction=2; //if
you have reached the top change
directions if(mBall.getTop()<=50 && direction==2) //coming
south now go
north direction=1; if(mBall.getLeft()<=50 && direction==3) //coming
east now go
west direction=4; if(mBall.getLeft()>=450 && direction==4) //coming
east now go
west direction=3; if( (mBall.getLeft()<=50 || mBall.getTop()<=50) && direction==5) //coming
north east now go south
west direction=8; if((mBall.getLeft()>=450 || mBall.getTop()<=50) && direction==6) //coming
north west now go south
east direction=7; if((mBall.getLeft()<=50 || mBall.getTop()>=350) && direction==7) //coming
south east now go north
west direction=6; if((mBall.getLeft()>=450 || mBall.getTop()>=350 ) && direction==8) //coming
north east now go south
west direction=5; //redraw
the ball at new
locations this.repaint(); //putting
the thread to sleep so we can create some delay //so
the ball's motion looks
natural. try Thread.sleep(300); //
as thread.sleep needs that it be inside try and catch
block. //
when a thread is put to sleep it can throw and
exception. //
read article for details on try catch
blocks. {} catch(Exception e) System.out.println("Error in running thread " + e); {} } }
public void paint(Graphics g) //setCOlor()
method is used to set the color by which you will be filling the
object g.setColor(Color.red); for(int i=0;i<10;i++) { if(mBrick[i].enabled==true) g.fillRect(mBrick[i].getLeft(),mBrick[i].getTop(),mBrick[i].getWidth(),mBrick[i].getHeight()); {} g.setColor(Color.blue); g.fillRect(mBat.getLeft(),mBat.getTop(),mBat.getWidth(),mBat.getHeight()); g.setColor(Color.green); g.fillOval(mBall.getLeft(),mBall.getTop(),mBall.getHeight(),mBall.getWidth()); }
public void initBrick() int j=0; //initialize
all the bricks in the
list. for(int i=0;i<10;i++) { mBrick[i]=new BricksEntity(); mBrick[i].setTop(30); mBrick[i].setLeft(j); mBrick[i].setHeight(30); mBrick[i].setWidth(80); //next
brick left
position j=j+82; {} } public void initBall() mBall.setTop(150); mBall.setLeft(200); mBall.setHeight(40); mBall.setWidth(40); {} public void initBat() mBat.setTop(400); mBat.setLeft(100); mBat.setHeight(20); mBat.setWidth(100); {}
//the
main method the entry point into our game
program. public static void main(String[] args) System.out.println("Welcome to the Bricks Game!"); BricksGame m_bricksGame=new BricksGame(); {}
//In
case someone wants to close the program from the Frame we need
to //process
the window closing event and handle it
appropriately
protected void processWindowEvent(WindowEvent e) super.processWindowEvent(e); if (e.getID() == WindowEvent.WINDOW_CLOSING) { System.exit(0); //close
the window and exit out of the program. {} } }
As seen in the code, the logic for enabling and disabling the
bricks is one for loop and one big if condition. It is basically
testing if the ball has touched the brick and also which brick as it
checks for the left and right side of the brick. If the ball is
hitting within the perimeter of the brick or not. If yes, setting the
enabled variable for the concerned brick to false.
Our final game looks like this :



Click here to download the code for the game.
I hope you have all enjoyed reading the series. I thank you for
the great response I have been getting and the questions being asked.
Please don't hesitate to send me any questions you would like
answered.
Please send your suggestions for articles you would like to see
here to webmaster@javareference.com
|