I have been working on and off for the past week or so on a simple game of PONG. I finally completed it yesterday and I would like to share some of the challenges I ran into during development.
My first real issue was trying to pause between volley’s. I knew about Thread.sleep but I couldn’t figure out the location in the code that would give me the functionality that I was looking for. I also struggled with calling the repaint method in the right spot in order to display the score and then pause the game between volley’s. The biggest issue I had was with the flickering of the application. Note the comments in the code where I addressed this issue. I just did a bit of Googling and I began to read about Double Buffering. I found the exact code that I use in this application and copied it verbatim into my application. You can use this code in any application that is having issues with flickering. Google Double Buffering, there is good info out there. So here it is:
//BTG 2.4.14 import java.awt.*; import java.awt.geom.*; import java.awt.event.KeyEvent; import javax.swing.JFrame; import java.util.Random; import java.util.Timer; //extends Canvas in order to create playPong component public class playPong extends Canvas { String currentMessage; Point referencePoint; Ellipse2D.Double ball; Rectangle paddle1, paddle2; int leftScore = 0, rightScore = 0; //used to remove flickering in application Image dbImage; Graphics dbg; //create JFrame public static void main( String[] args ) { JFrame win = new JFrame("Pong"); win.setSize(1000,750); win.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); win.add( new playPong() ); win.setVisible(true); }//main public playPong() { enableEvents(java.awt.AWTEvent.KEY_EVENT_MASK); //requests that this component become the focused Window requestFocus(); ball = new Ellipse2D.Double(500,350,20,20); referencePoint = new Point(-5,5); paddle1 = new Rectangle(50,250,20,200); paddle2 = new Rectangle(910,250,20,200); currentMessage = "Let's play until someone gets to 10, get ready....!"; //timer that loads individual frames on in the window, adjust to your liking Timer t = new Timer(true); t.schedule( new java.util.TimerTask() { public void run() { gameAction(); repaint(); } }, 10, 17); } //original paint settings public void paint( Graphics g ) { Graphics2D g2 = (Graphics2D)g; g2.setColor(Color.black); g2.fill(ball); g2.setColor(Color.blue); g2.fill(paddle1); g2.setColor(Color.blue); g2.fill(paddle2); g2.setColor(Color.BLACK); g2.setFont(Font.decode("sansserif-ITALIC-BOLD-18")); g2.drawString(currentMessage, 100, 100); } //Update - Method, implements double buffering. Double buffering cures application flickering. This is generic code and can be copied //along with the 2 initial variables into any application where flickering is happening. public void update (Graphics g) { dbImage = createImage (this.getSize().width, this.getSize().height); dbg = dbImage.getGraphics (); // initialize buffer if (dbImage == null) {} // clear screen in background dbg.setColor (getBackground ()); dbg.fillRect (0, 0, this.getSize().width, this.getSize().height); // draw elements in background dbg.setColor (getForeground()); paint (dbg); // draw image on the screen g.drawImage (dbImage, 0, 0, this); } //pick up VK(virtual key) events to move paddle public void processKeyEvent(KeyEvent e) { if ( e.getID() == KeyEvent.KEY_PRESSED ) { if ( e.getKeyCode() == KeyEvent.VK_DOWN ) { paddle1.y += 10; } if ( e.getKeyCode() == KeyEvent.VK_UP ) { paddle1.y -= 10; } } } public void gameAction() { //if statement to stop loop if a player has reached 10 points if(leftScore < 10 && rightScore < 10){ ball.x += referencePoint.x; ball.y += referencePoint.y; // and bounce if we hit a wall if ( ball.y < 0 || ball.y+20 > 700 ) referencePoint.y = -referencePoint.y; // check if the ball is hitting the paddle if ( ball.intersects(paddle1) ) referencePoint.x = -referencePoint.x; if ( ball.intersects(paddle2) ) referencePoint.x = -referencePoint.x; if ( ball.x > 1000 ) //a score for the right paddle { Random r = new Random(); int r1 = r.nextInt(650); //random starting position for the ball after a score int r2 = r.nextInt(10); //random starting position for the ball after a score rightScore++; //add a point to the R paddle score currentMessage = "The score is: " +leftScore+ " to " +rightScore+ "."; repaint(); //display score try { Thread.sleep(2000); //pause before next volley } catch (InterruptedException e) {} ball.x = 500; //ball starting point for next volley ball.y = r1; //ball starting point for next volley referencePoint = new Point(-5,r2); //ball starting direction for next volley } if ( ball.x < -30) //a score for the left paddle { Random r = new Random(); int r1 = r.nextInt(650); //random starting position for the ball after a score int r2 = r.nextInt(10); //random starting position for the ball after a score leftScore++; //add a point to the L paddle score currentMessage = "The score is: " +leftScore+ " to " +rightScore+ "."; repaint(); //display score try { Thread.sleep(2000); //pause before next volley } catch (InterruptedException e) {} ball.x = 500; //ball starting point for next volley ball.y = r1; //ball starting point for next volley referencePoint = new Point(-5,r2); //ball starting direction for next volley } } if(leftScore == 10 || rightScore == 10){ currentMessage = "GAME OVER!!"; repaint(); } } public boolean isFocusable() { return true; } }//class
Image may be NSFW.
Clik here to view.
Clik here to view.
