Let's begin.
The first step to developing a game is to figure out what pieces we will need to create. Pong is composed of two paddles and a ball. I'm thinking that it is going to be a 500 by 300 applet We are going to make three classes that will handle all of the characteristics of these three parts. There is going to be one human controlled paddle, one computer controlled paddle, and of course, the ball
Here we have the human-controlled paddle, or PaddleLeft class:
/*
* This is the class for the human-controlled paddle
*/
public class PaddleLeft{
//declaration for variables needed
private int yPos = 0;
final int XPOS = 30;
public PaddleLeft(){
//sets up the paddle to be at a y position of 120
setPos(120);
}
public void setPos(int pos){
this.yPos = pos;
//if the y position upper left hand corner is
//70 pixels of the bottom of the applet window
if(yPos > 230){
//set it back to 70 pixels away
setPos(230);
}
//if the y position upper left hand corner is
//less than zero(outside the applet window)
else if(yPos < 0){
//set the y position to 0
setPos(0);
}
}
public int getPos(){
return yPos;
}
}
makes sense so far, right? This is easy! Now for the other two. Here we have the Computer controlled paddle, or PaddleRight:
/*
* PaddleRight has essentially the same set up as the human-controlled
* paddle except that it uses the y position of the ball to determine
* the paddle location instead of using a mouseMovement listener
*/
public class PaddleRight{
private int yPos = 0, score;
final int XPOS = 460;
//the constructor takes in an integer( which is, in our case,
//the y position of the ball)
public PaddleRight(int ballPos){
//sets the position and sets the score to 0
setPos(ballPos);
setScore(0);
}
public void setPos(int pos){
//same set up as in Paddle left
this.yPos = pos;
if(yPos > 230){
setPos(230);
}
else if(yPos < 0){
setPos(0);
}
}
public int getPos(){
return yPos;
}
//setters and getters for int score
public void setScore(int score){
this.score = score;
}
public int getScore(){
return this.score;
}
}
Don't worry about the technicallities of using the ball's y position just yet. All that this means is that the paddle controlled by the computer will never miss the ball. The point of this particular game of Pong is to see how long you can last against this tough foe
Lastly, we have the ball:
/*
* This is the Ball class
*/
public class Ball{
//variables for the x and y position
private int xPos,yPos;
//the direction of the x and y position. Dy is set to -5 because,
//remeber that the applet "grid" has it's (0, 0) orgin at the
//top lefthand corner of the applet window. For the mathimatically
//minded among us, the applet is essentially quadrant IV
public int dx = 5, dy = -5;
public Ball(){
//sets the initial ball position to near the center of the
//screen
setPos(250, 140);
}
public void setPos(int x, int y){
this.xPos = x;
this.yPos = y;
}
public int getX(){
return xPos;
}
public int getY(){
return yPos;
}
//this is the method used to move the ball
public void move(){
//it takes the current x and y position, then adds their current
//direction of movement to them, giving us a shift in the ball's
//position in the applet
setPos(this.getX() + dx, this.getY() + dy);
}
//reset method for when the computer scores
public void reset(){
//the same initial setup as before
setPos(250,140);
dx = 5;
dy = -5;
}
}
Notice that the ball has kind of the same methods as the paddles (a get and set method for coordinate positions). The big difference here is the move() and reset() method. The reset method is important, but it is nothing special. It simply will reset the ball to it's original position.
Now, the move method simply used the x and y position of the ball and this dx and dy. Dx and Dy are just headings for the ball. a dx of 5 means that the ball is traveling to the right at a rate of 5. A dx of -5 means it's moving to the left at a rate of 5. It is exactly the same for dy. This business of
setPos(this.getX() + dx, this.getY() + dy);
simply takes the x and y position, then adds their heading to it, in effect moving the ball's location. Whew! So far so good
Still with me? Fantastic. Now we get to the meat of the program. We are going to call our main class pongMain Clever, isn't it? Like I mentioned earlier, there are two key concepts to Game Programming that I am going to cover, Timers and Double-Buffering.
Let's go over Timers first. A GUI is repainted, that's how progress is made in a program, right? Of course! I see many people using Thread.sleep() to delay their program's game loop, but the problem is that Thread.sleep() isn't thread safe. Ironic isn't it? Luckily, there is a super easy way to do do it that IS Thread safe. They are called Timers(a Swing timer).
Timer time = new Timer(15, this)
This line of code creates a timer for a class then says, this timer is a part of this class and it will call an actionPerformed method after 15 milliseconds. Related to Timers is the idea of frame rate. Frame rate is the number of frames per second. Since Timer counts by milliseconds(1000 seconds) we will divide it by 15 to get our frame rate.
1000 / 15 = almost 67 frames per secondThis means that we are going to excecute our actionPerformed method 67 times a second! Perfect!
Ok, our next topic is going to be double-buffering. The problem with drawing straight to an applet window is that it is going to flicker something terrible if there is anything more than a moving box (which is what our ball essentially will be), so we need a way to get the applet to repaint itself smoothly. The answer is double-buffering. Here is the process:
//The image I am creating is going to be double buffered
//so that there is no flicker when the applet is repainted
Graphics bufferGraphics;
// The image that will contain everything that has been drawn on
// bufferGraphics.
Image offscreen;
most of you use the Graphics g to paint things, right. Well, we are going to take this bufferGraphics and paint onto this image instead of straight to the screen
// Create an offscreen image to draw on
offscreen = createImage(WIDTH,HEIGHT);//<-- this is going to be (500, 300)
bufferGraphics = offscreen.getGraphics();
You, in the back row, wake up! This is great!
In our paint method, this is how we are going to start it:
//instead of using the typical graphics, we are going to
//use bufferGraphics (which we declared at the beginning
//of the class) to draw onto our off-screen image
//first, we clear off whatever was previously on the image
bufferGraphics.clearRect(0,0,WIDTH,HEIGHT);
You see, we have to clear the off screen image to be the same dimensions as our applet window and whenever we want to draw something we say
bufferGraphics.fillRect(0,0, 10, 70)//<-- or whatever drawing method you'd like
at the end of our paint method, after we are done drawing, we need to put:
g.drawImage(offscreen,0,0,this);
//this line makes sure that all the monitors are up to date before
//proceeding
Toolkit.getDefaultToolkit().sync();
The toolKit. command actually relates to our frame rates that we talked about earlier. It all goes hand in hand. We just need to make sure that everything is up to date so that the program is all on the same page, so to speak.
Finally, we need to add this method:
//all good double buffers need the update() method. If
// you leave this out, the image will still flicker
public void update(Graphics g)
{
paint(g);
}
The flickering problem is solved! Now lets apply this to our project. Alright, are you ready to tackle this now that we have our tools? Great,
here is how we are going to start this show. We need to import all of our methods and declare our necessary objects and variables:
import java.applet.*;
import java.awt.event.*;
import java.awt.*;
import javax.swing.Timer;
//we need the Applet methods and the MouseMotionListener interface
//(used for the human controlled panel
public class pongMain extends Applet implements MouseMotionListener, ActionListener
{
//we declare an instance of our ball and two paddles
Ball ball;
PaddleLeft pLeft;
PaddleRight pRight;
//a font used to display the score
Font newFont = new Font("sansserif", Font.BOLD, 20);
//The image I am creating is going to be double buffered
//so that there is no flicker when the applet is repainted
Graphics bufferGraphics;
// The image that will contain everything that has been drawn on
// bufferGraphics.
Image offscreen;
// variables used to set the width and height of the applet.
final int WIDTH = 500, HEIGHT = 300;
//variable used to record the time that the game has proceeded to
//because we want to tell the person how long the lasted
long currentTime;
Not very exciting, i know, but now we get into the heart of it. I'm going to post our three classes again so you can reference them as we go
PaddleLeft:
public PaddleLeft(){
//sets up the paddle to be at a y position of 120
setPos(120);
}
public void setPos(int pos){
this.yPos = pos;
//if the y position upper left hand corner is
//70 pixels of the bottom of the applet window
if(yPos > 230){
//set it back to 70 pixels away
setPos(230);
}
//if the y position upper left hand corner is
//less than zero(outside the applet window)
else if(yPos < 0){
//set the y position to 0
setPos(0);
}
}
public int getPos(){
return yPos;
}
}
PaddleRight:
/*
* PaddleRight has essentially the same set up as the human-controlled
* paddle except that it uses the y position of the ball to determine
* the paddle location instead of using a mouseMovement listener
*/
public class PaddleRight{
private int yPos = 0, score;
final int XPOS = 460;
//the constructor takes in an integer( which is, in our case,
//the y position of the ball)
public PaddleRight(int ballPos){
//sets the position and sets the score to 0
setPos(ballPos);
setScore(0);
}
public void setPos(int pos){
//same set up as in Paddle left
this.yPos = pos;
if(yPos > 230){
setPos(230);
}
else if(yPos < 0){
setPos(0);
}
}
public int getPos(){
return yPos;
}
//setters and getters for int score
public void setScore(int score){
this.score = score;
}
public int getScore(){
return this.score;
}
}
Ball:
/*
* This is the Ball class
*/
public class Ball{
//variables for the x and y position
private int xPos,yPos;
//the direction of the x and y position. Dy is set to -5 because,
//remeber that the applet "grid" has it's (0, 0) orgin at the
//top lefthand corner of the applet window. For the mathimatically
//minded among us, the applet is essentially quadrant IV
public int dx = 5, dy = -5;
public Ball(){
//sets the initial ball position to near the center of the
//screen
setPos(250, 140);
}
public void setPos(int x, int y){
this.xPos = x;
this.yPos = y;
}
public int getX(){
return xPos;
}
public int getY(){
return yPos;
}
//this is the method used to move the ball
public void move(){
//it takes the current x and y position, then adds their current
//direction of movement to them, giving us a shift in the ball's
//position in the applet
setPos(this.getX() + dx, this.getY() + dy);
}
//reset method for when the computer scores
public void reset(){
//the same initial setup as before
setPos(250,140);
dx = 5;
dy = -5;
}
}
Alright, First we have our int() method, which is ran to initialize the applet:
public void init()
{
//sets the applet to be 500 * 300
setSize(500, 300);
//we now instantiate our ball and two paddles
ball = new Ball();
pLeft = new PaddleLeft();
//this paddle is set to the current ball y position
//minus 35 so the ball will be lined up with the center
//of our 70 pixel long paddle
pRight = new PaddleRight(ball.getY() - 35);
//we add our mouseMotionListener so that the user can control their paddle (we will see this later)
addMouseMotionListener(this);
//I want the applet to look like a grass court =)
setBackground(Color.green);
// Create an offscreen image to draw on
offscreen = createImage(WIDTH,HEIGHT);
bufferGraphics = offscreen.getGraphics();
}
as you can see, we are setting up our pieces of the game as well as our double-buffering technique.
next, we have our start() method, which is where the game loop is:
public void start(){
//this sets the current time in milliseconds
currentTime = System.currentTimeMillis();
//I am going to use a timer to do a certain list of tasks
//every 15 milliseconds, which is about 67 frames a second
//(there are 1000 milliseconds in a second, so we divide that
//by 15 to set up our game's frame rate
Timer time = new Timer(15, this);
//this is the "game loop". It won't end until the
//computer has scored 10 points on the board.
//we begin our time so that the actionPerformed method will be called
//every 15 milliseconds
time.start();
while(pRight.getScore() < 10){
//nothing happens in here, but the timer is still running in the
//background, executing our actionPerformed method and making
//the wheels of this program turn
}
//after the game needs to end, we stop the timer and calculate
//how long the user has been playing by subtracting the current
//time from the intitial currentTime
time.stop();
currentTime = System.currentTimeMillis() - currentTime;
//we repaint one more time to display how long the player
//lasted in this helpless cause =)
repaint();
}
now remember, our timer is calling our actionPerformed method and this is what it looks like:
//every 15 milliseconds, the Timer time triggers the
//actionPerformed method
public void actionPerformed(ActionEvent arg0) {
//moves the ball
ball.move();
//lines the computer paddle up with the ball
pRight.setPos(ball.getY() - 35);
//checks the ball for a collision
checkCollision();
//repaints the applet
repaint();
}
so, as you can see, every 15 seconds, the ball moves a little, the computer paddle lines up with the ball's y position, then the program checks to see if the ball has run into a wall, paddle, or goal.
You have ball.move() in the ball class, so we will now post the checkCollision() method. Once again, remember that this is a 500 * 300 window:
public void checkCollision(){
//remember, our ball is 10*10 and the x and y positions are the
//top-left corners of the ball. If the top left corner y position
//is 0 or 290, we reverse the y- direction that the ball was
//travelling in by multiplying ball.dy by -1
if(ball.getY() == 0 || ball.getY() == 290){
ball.dy = (ball.dy * -1);
}
//if the ball is at the right-hand edge of the human paddle's
//domain and the boolean method hitPaddle() is true, then we
//reverse the dx position of ball by multiplying ball.dx by -1
if((ball.getX() == 40) && hitPaddle()){
ball.dx = (ball.dx * -1);
}
//we already know that the computer paddle can't miss, so if
//the ball reaches the left-hand edge of the paddle, we can make the
//dx switch directions without any additional checks
if(ball.getX() == 460){
ball.dx = (ball.dx * -1);
}
//if the ball is missed by the human paddle and reaches the
//left-hand edge of the applet window, then reset the ball
//and increment the score
if(ball.getX() == 0){
pRight.setScore(pRight.getScore() + 1);
ball.reset();
}
}
public boolean hitPaddle(){
boolean didHit = false;
//this just checks if the ball is lined up between the top and
//bottom right-hand corners of the human paddle
if((pLeft.getPos() - 10) <= ball.getY() && (pLeft.getPos() + 70) > ball.getY()){
//sets didHit to true
didHit = true;
}
return didHit;
}
The last thing called in our actionPerformed() method is repaint, which goes to the paint() method:
public void paint(Graphics g)
{
//instead of using the typical graphics, we are going to
//use bufferGraphics (which we declared at the beginning
//of the class) to draw onto our off-screen image
//first, we clear off whatever was previously on the image
bufferGraphics.clearRect(0,0,WIDTH,HEIGHT);
//we now draw our two paddles in blue
bufferGraphics.setColor(Color.blue);
//the XPOS is a final int, so it never changes, but the
//yPos does. We make the paddles 10 * 70.
//Left side
bufferGraphics.fillRect(pLeft.XPOS,pLeft.getPos(),10,70);
//Right side
bufferGraphics.fillRect(pRight.XPOS, pRight.getPos(), 10, 70);
//this draws our mid-court line and our scores in white
bufferGraphics.setColor(Color.white);
bufferGraphics.setFont(newFont);
//we show our player's hopeless circumstances
bufferGraphics.drawString("Futile", 150, 15);
//we get the score from our PaddleRight object
bufferGraphics.drawString(""+ pRight.getScore(),300,15);
//mid-court divider
bufferGraphics.fillRect(240,0,20,300);
//Remeber, we painted one last time after the computer's
//score reached ten
if(pRight.getScore() == 10){
//we divide the milliseconds by 1000 to display in seconds how
//long the game lasted
bufferGraphics.drawString("You Lasted: " + (currentTime/ 1000) + "sec.", 40, 150);
}
//we draw the ball
bufferGraphics.setColor(Color.red);
bufferGraphics.fillRect(ball.getX(),ball.getY(),10,10);
//finally, we draw the offscreen image to the applet
g.drawImage(offscreen,0,0,this);
//this line makes sure that all the monitors are up to date before
//proceeding
Toolkit.getDefaultToolkit().sync();
}
Don't let the confusing appearance of it fool you. all you are doing is painting our three pieces of the game, the score (as one sided as it may be
We are almost there my friends. The final part is the mouseMotionListener that we need for the human-controlled paddle
//this sets the mouse's y position to the center of our paddle
public void mouseMoved(MouseEvent evt)
{
pLeft.setPos(evt.getY()- 35);
}
// The necessary methods, though this one is unused, we still
//have to put it here.
public void mouseDragged(MouseEvent evt)
{
}
And that's a wrap, you have finished your first Game Java applet in a very professionally accepted and methodical way. Here is the entire main class:
/*
* This is the main method of my Pong applet. The game is played by a single
* player who uses the mouse to control the y position of their paddle.
* The computer controlled paddle(the one on the right) uses the y position
* of the ball in play to determine it's paddle position. Essetially, it has
* God-like capabilities that can't be beaten. The object is to see how long
* you can hold out before the computer scores 10 points
*/
import java.applet.*;
import java.awt.event.*;
import java.awt.*;
import javax.swing.Timer;
//we need the Applet methods and the MouseMotionListener interface
//(used for the human controlled panel
public class pongMain extends Applet implements MouseMotionListener, ActionListener
{
//we declare an instance of our ball and two paddles
Ball ball;
PaddleLeft pLeft;
PaddleRight pRight;
//a font used to display the score
Font newFont = new Font("sansserif", Font.BOLD, 20);
//The image I am creating is going to be double buffered
//so that there is no flicker when the applet is repainted
Graphics bufferGraphics;
// The image that will contain everything that has been drawn on
// bufferGraphics.
Image offscreen;
// variables used to set the width and height of the applet.
final int WIDTH = 500, HEIGHT = 300;
//variable used to record the time that the game has proceeded to
//because we want to tell the person how long the lasted
long currentTime;
public void init()
{
//sets the applet to be 500 * 300
setSize(500, 300);
//we now instantiate our ball and two paddles
ball = new Ball();
pLeft = new PaddleLeft();
//this paddle is set to the current ball y position
//minus 35 so the ball will be lined up with the center
//of our 70 pixel long paddle
pRight = new PaddleRight(ball.getY() - 35);
//we add our mouseMotionListener
addMouseMotionListener(this);
//I want the applet to look like a grass court =)
setBackground(Color.green);
// Create an offscreen image to draw on
offscreen = createImage(WIDTH,HEIGHT);
bufferGraphics = offscreen.getGraphics();
}
public void start(){
//this sets the current time in milliseconds
currentTime = System.currentTimeMillis();
//I am going to use a timer to do a certain list of tasks
//every 15 milliseconds, which is about 67 frames a second
//(there are 1000 milliseconds in a second, so we divide that
//by 15 to set up our game's frame rate
Timer time = new Timer(15, this);
//this is the "game loop". It won't end until the
//computer has scored 10 points on the board.
//we begin our time so that the actionPerformed method will be called
//every 15 milliseconds
time.start();
while(pRight.getScore() < 10){
//nothing happens in here, but the timer is still running in the
//background, executing our actionPerformed method and making
//the wheels of this program turn
}
//after the game needs to end, we stop the timer and calculate
//how long the user has been playing by subtracting the current
//time from the intitial currentTime
time.stop();
currentTime = System.currentTimeMillis() - currentTime;
//we repaint one more time to display how long the player
//lasted in this helpless cause =)
repaint();
}
public void stop(){
}
public void paint(Graphics g)
{
//instead of using the typical graphics, we are going to
//use bufferGraphics (which we declared at the beginning
//of the class) to draw onto our off-screen image
//first, we clear off whatever was previously on the image
bufferGraphics.clearRect(0,0,WIDTH,HEIGHT);
//we now draw our two paddles in blue
bufferGraphics.setColor(Color.blue);
//the XPOS is a final int, so it never changes, but the
//yPos does. We make the paddles 10 * 70.
//Left side
bufferGraphics.fillRect(pLeft.XPOS,pLeft.getPos(),10,70);
//Right side
bufferGraphics.fillRect(pRight.XPOS, pRight.getPos(), 10, 70);
//this draws our mid-court line and our scores in white
bufferGraphics.setColor(Color.white);
bufferGraphics.setFont(newFont);
//we show our player's hopeless circumstances
bufferGraphics.drawString("Futile", 150, 15);
//we get the score from our PaddleRight object
bufferGraphics.drawString(""+ pRight.getScore(),300,15);
//mid-court divider
bufferGraphics.fillRect(240,0,20,300);
//Remeber, we painted one last time after the computer's
//score reached ten
if(pRight.getScore() == 10){
//we divide the milliseconds by 1000 to display in seconds how
//long the game lasted
bufferGraphics.drawString("You Lasted: " + (currentTime/ 1000) + "sec.", 40, 150);
}
//we draw the ball
bufferGraphics.setColor(Color.red);
bufferGraphics.fillRect(ball.getX(),ball.getY(),10,10);
//finally, we draw the offscreen image to the applet
g.drawImage(offscreen,0,0,this);
//this line makes sure that all the monitors are up to date before
//proceeding
Toolkit.getDefaultToolkit().sync();
}
//all good double buffers need the update() method. If
// you leave this out, the image will still flicker
public void update(Graphics g)
{
paint(g);
}
//this sets the mouse's y position to the center of our paddle
public void mouseMoved(MouseEvent evt)
{
pLeft.setPos(evt.getY()- 35);
}
// The necessary methods, though this one is unused, we still
//have to put it here.
public void mouseDragged(MouseEvent evt)
{
}
//this is where the program figures out if the ball has hit
//a paddle, the top or bottom of the applet window, or if the
//computer scored
public void checkCollision(){
//remember, our ball is 10*10 and the x and y positions are the
//top-left corners of the ball. If the top left corner y position
//is 0 or 290, we reverse the y- direction that the ball was
//travelling in by multiplying ball.dy by -1
if(ball.getY() == 0 || ball.getY() == 290){
ball.dy = (ball.dy * -1);
}
//if the ball is at the right-hand edge of the human paddle's
//domain and the boolean method hitPaddle() is true, then we
//reverse the dx position of ball by multiplying ball.dx by -1
if((ball.getX() == 40) && hitPaddle()){
ball.dx = (ball.dx * -1);
}
//we already know that the computer paddle can't miss, so if
//the ball reaches the left-hand edge of the paddle, we can make the
//dx switch directions without any additional checks
if(ball.getX() == 460){
ball.dx = (ball.dx * -1);
}
//if the ball is missed by the human paddle and reaches the
//left-hand edge of the applet window, then reset the ball
//and increment the score
if(ball.getX() == 0){
pRight.setScore(pRight.getScore() + 1);
ball.reset();
}
}
public boolean hitPaddle(){
boolean didHit = false;
//this just checks if the ball is lined up between the top and
//bottom right-hand corners of the human paddle
if((pLeft.getPos() - 10) <= ball.getY() && (pLeft.getPos() + 70) > ball.getY()){
//sets didHit to true
didHit = true;
}
return didHit;
}
@Override
//every 15 milliseconds, the Timer time triggers the
//actionPerformed method
public void actionPerformed(ActionEvent arg0) {
//moves the ball
ball.move();
//lines the computer paddle up with the ball
pRight.setPos(ball.getY() - 35);
//checks the ball for a collision
checkCollision();
//repaints the applet
repaint();
}
}
Don't forget to create your html document and put it in the same folder as the other 4 class files, otherwise you will have many many errors. Put this in notepad and save it in the same folder as the class files:
<html>
<head>
<title>Pong</title>
<style type="text/css">
p {color: white; }
body {background-color: black; }
</style>
</head>
<body>
<h1><p>Pong</p></h1>
<hr>
<applet code=pongMain.class width = 500 height = 300>
alt="Your browser understands the <APPLET> tag but isn't running the applet, for some reason."
Your browser is completely ignoring the <APPLET> tag!
</applet>
<hr>
<p>See how many seconds you can last! Use the mouse to play!
Don't let the score get to 10!</p>
</body>
</html>
Congrats! I hope you learned a thing or two






MultiQuote











|