JavaReference.com AllDevNet.com"
Welcome Guest     Login     Register    
 [ Home > Articles > Java Game Programming, Part VII ]  Submit Article   
Java Game Programming, Part VII
[ by Vijay Kukreja ]
Print   E-Mail 
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 
Advertisement

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.

Ball collision movement basics

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.

Ball and bat collision movement basics

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 :

Finished Game 1

Finished Game 2

Finished Game 3

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


Print   E-Mail 
  Java and all Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. and its subsidiaries in the U.S. and other countries.