• Welcome to Overclockers Forums! Join us to reply in threads, receive reduced ads, and to customize your site experience!

Working on a Java Pong Game

Overclockers is supported by our readers. When you click a link to make a purchase, we may earn a commission. Learn More.

updawg

StarCraft II Fanatic
Joined
May 19, 2006
Location
NOVA
Alright I am beginning to work with GUIs and I was trying to make a simple one person Pong game where your opponent is the wall. There really is no winning per say it is just staying alive.

My problem is trying to make the ball move. I have it so it bounces of the y bounds of the panel, and works great, but I can't seem to make it work using the x bounds as well. (I know there currently is no paddle in my code but that will be added in the future).

Code:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;

public class Pong extends FrameWithInheritance {
  private int x=0, y=0;
  private boolean startPong = false;
  private boolean test1 = true;
  private boolean test2 = false;


  private class MyPanel extends JPanel {
 
    public void paint(Graphics g) {
      if(startPong) {
        g.setColor(Color.BLUE);
        g.drawArc(x, y, 30, 30, 0, 360);
        

        if(y < 160 && test1) {
          test2 = false;
          x += 20; 
          y += 20;
        }else test2 = true;
        
        if(y > 0 && y <= 160 && test2)
        {
          test1 = false;
          x+=20;
          y-=20;
        }else test1 = true;
                
      }
   
    }

  }
 

  private MyPanel panel;
 
 
  public Pong(String title) {
    super(title);
    JMenuBar bar = new JMenuBar();
    this.add(bar, BorderLayout.NORTH);
    JMenu fileMenu = new JMenu("File");
    bar.add(fileMenu);
    JMenuItem pongItem = new JMenuItem("Pong");
    fileMenu.add(pongItem);
    pongItem.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e) {
        startPong();
      }
    });
    
    panel = new MyPanel();
    this.add(panel,BorderLayout.CENTER);
    
    while(true) {
      try {
        Thread.sleep(250);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      this.repaint();
    }
  }
 

  public void startPong(){
    startPong = ! startPong;
  }
 
 
  public static void main(String[] args) {
    new Pong("Pong");
  }

}

This is the JFrame it is extending:

Code:
import java.awt.Dimension;
import java.awt.Toolkit;
import javax.swing.JFrame;

public class FrameWithInheritance extends JFrame {

 public FrameWithInheritance(String title) {
  super(title);
  
  setBounds(200, 200, 505 , 255);
  
  setDefaultCloseOperation(EXIT_ON_CLOSE);
  setVisible(true);
 }

 public static void main(String[] args) {
  new FrameWithInheritance("Test");
 }

}

Thanks for any suggestions in advanced!
 
private boolean test1 = true;
private boolean test2 = false;

This is a NONO. Undocumented, non self-explanatory variables. :mad:

You should have values xIncrement and yIncrement, which will be positive or negative depending on which direction the ball is traveling. That will help cut back on complex special cases. When a ball hits the top or bottom, multiply yInc by -1. When the ball hits a side wall, multiply xInc by -1. Then after detecting wall hits, have the x and y of the ball be incremented by xInc and yInc respectively.

Also, I changed to
Code:
Thread.sleep(10);
and have the ball increment 1 pixel at a time for a much much smoother experience. :thup:
 
I can't seem to figure out how to implement that though? If (x>460) x*-1; Then what happens is once it get backs under 470 it starts coming towards the wall again. The y bounds is 160 and the x bounds is 470 respectively.

I change the ball movement to 1,1 and the thread sleep to 10 and you are right it is much more fluent.

Code:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;

public class Pong extends FrameWithInheritance {
  private int x=0, y=0;
  private boolean startPong = false;



  private class MyPanel extends JPanel {
 
    public void paint(Graphics g) {
      if(startPong) {
        g.setColor(Color.BLUE);
        g.drawArc(x, y, 30, 30, 0, 360);
              
        x+=1;
        y+=1;
                          
      }
   
    }

  }
 

  private MyPanel panel;
 
 
  public Pong(String title) {
    super(title);
    JMenuBar bar = new JMenuBar();
    this.add(bar, BorderLayout.NORTH);
    JMenu fileMenu = new JMenu("File");
    bar.add(fileMenu);
    JMenuItem pongItem = new JMenuItem("Pong");
    fileMenu.add(pongItem);
    pongItem.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e) {
        startPong();
      }
    });
    
    panel = new MyPanel();
    this.add(panel,BorderLayout.CENTER);
    
    while(true) {
      try {
        Thread.sleep(10);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      this.repaint();
    }
  }
 

  public void startPong(){
    startPong = ! startPong;
  }
 
 
  public static void main(String[] args) {
    new Pong("Pong");
  }

}
 
Think of it this way. In the X-direction, the ball is going to move either +1 or -1. In the Y-direction, the ball is also only moving +1 or -1. If the ball's x coordinate hits 0 or 400, it needs to reverse its X direction. If the ball's y coordinate hits 0 or 160, it needs to reverse its Y direction. The increment values are what hold the direction the ball is going to travel.
 
Thanks for the help I got it working with the code below! Now I have to make a movable rectangle with .fillRec and a keylisteners. Does anyone have a good reference I can look over? Thank you for your help.

Code:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;

public class Pong extends FrameWithInheritance {
  
  private boolean startPong = false;



  private class MyPanel extends JPanel {
    private int x=1, y=1;
    private int a=1, b=1;
    public void paint(Graphics g) {
      if(startPong) {
        g.setColor(Color.BLUE);
        g.fillArc(x, y, 30, 30, 0, 360);
              
        x+=a;
        y+=b;
        
        if(x == 470) a=a*-1;
        if(y == 165 || y==0) b=b*-1;
        if(x == 0) startPong = false; //end game
        
        
                          
      }
   
    }

  }
 

  private MyPanel panel;
 
 
  public Pong(String title) {
    super(title);
    JMenuBar bar = new JMenuBar();
    this.add(bar, BorderLayout.NORTH);
    JMenu fileMenu = new JMenu("File");
    bar.add(fileMenu);
    JMenuItem pongItem = new JMenuItem("Pong");
    fileMenu.add(pongItem);
    pongItem.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e) {
        startPong();
      }
    });
    
    panel = new MyPanel();
    this.add(panel,BorderLayout.CENTER);
    
    while(true) {
      try {
        Thread.sleep(10);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      this.repaint();
    }
  }
 

  public void startPong(){
    startPong = ! startPong;
  }
 
 
  public static void main(String[] args) {
    new Pong("Pong");
  }

}
 
Also for some reason to make this work I have to resize within windows for the jmenubar to appear, it's like it is invisible until I try to resize the window size. Why is this?
 
Here is my working code, the only problem I am having is that I have to resize the window for the jmenu to appear. Why is that how can I fix it? Also if it catches the corner it rolls down the paddle, what causes that glitch?

Code:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;

public class Pong extends FrameWithInheritance  implements KeyListener{
  int padpos=50;
  int x=30, y=30;
  int a=2, b=2;
  
  private boolean startPong = false;
  private boolean pong = false;

  private class MyPanel extends JPanel {

    
    public void paint(Graphics g) {
      if(startPong) {
        
        g.setColor(Color.BLUE);
        
        g.fillArc(x, y, 30, 30, 0, 360);
        g.fillRect(1,padpos,25,75);
              
        x+=a;
        y+=b;
        
        if(x >= 470) a=a*-1; // bounce off far right wall
        if(y >= 165 || y==0) b=b*-1; // bounce off top/bottom wall
        if(x == 0) {
          startPong = false; // end game reset variables
          x=30;
          y=30;
          a=2;
          b=2;
          padpos=50;
        }
        if(y >= padpos && y <= padpos + 75 && x <= 28) a=a*-1; //bounce off paddle
                                  
      }
   
    }

  }
 

  private MyPanel panel;
 
 
  public Pong(String title) {
    super(title);
    JMenuBar bar = new JMenuBar();
    this.add(bar, BorderLayout.NORTH);
    JMenu fileMenu = new JMenu("File");
    bar.add(fileMenu);
    JMenuItem pongItem = new JMenuItem("Play Pong");
    fileMenu.add(pongItem);
    addKeyListener(this);
    pongItem.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e) {
        startPong();
      }
    });
    
    panel = new MyPanel();
    this.add(panel,BorderLayout.CENTER);
    
    while(true) {
      try {
        Thread.sleep(10);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      this.repaint();
    }
  }
  
  public void keyPressed(KeyEvent e) {
    if(e.getKeyCode() == 38) {
      if(padpos>10) padpos -= 10;
    }
    if(e.getKeyCode() == 40) {
      if(padpos<110) padpos += 10;
    }
  }
  
 
  public void keyTyped(KeyEvent e){}
  public void keyReleased(KeyEvent e){}
  
  public void startPong(){
    
    startPong = ! startPong;
  }
 
 
  public static void main(String[] args) {
    new Pong("Pong");
  }

}
 
Last edited:
Also for some reason to make this work I have to resize within windows for the jmenubar to appear, it's like it is invisible until I try to resize the window size. Why is this?

I don't have that problem. But I highly recommend this book if you really want to learn.
 
Is it a windows problem then? I've tried it on two different computers and it does the same thing, I just need to resize the window ever so slightly and the JMenuBar appears.
 
java version "1.6.0_13"
Java(TM) SE Runtime Environment (build 1.6.0_13-b03)
Java HotSpot(TM) Client VM (build 11.3-b02, mixed mode, sharing)

On windows XP. I swear it works perfectly over here. In a few hours or so I'll test it on Ubuntu..
 
Apparently it effects different machines differently depending upon where you set the setVisible statement. I fixed it by adding the setVisible after I added everything and now it comes up properly. Here is my finished code tell me what you think!

Code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;


public class Pong extends FrameWithInheritance  implements KeyListener{
  int padpos=50;
  int x=30, y=30;
  int a=2, b=2;
  int count = 0;
  boolean startPong = false;
  JMenu banner = new JMenu("You Lose!");
  
  
  private class MyPanel extends JPanel {
     
    public void paint(Graphics g) {
      if(startPong) {
        
        g.setColor(Color.BLUE);
        g.fillArc(x, y, 30, 30, 0, 360);
        g.setColor(Color.RED);
        g.fillRect(1,padpos,25,100);
        g.drawString("Score: " + count, 200, 100);
        
        x+=a;
        y+=b;
        
        if(x >= 470){
          a=a*-1; // bounce off far right wall
          count++; // increase score
        }
        if(y >= 165 || y==0) b=b*-1; // bounce off top/bottom wall
        if(y >= padpos && y <= padpos + 100 && x <= 24) a=a*-1; //bounce off paddle
        if(x == 0) {
          banner.setVisible(true);
          startPong = false; // end game reset variables
          x=30;
          y=30;
          a=2;
          b=2;
          padpos=50;
        }
        
      }
      else {
        g.setColor(Color.RED);
        g.drawString("Welcome to Pong", 190, 55);
        g.drawString("The Arrow Keys Move the Paddle Up and Down", 120, 80);
        g.drawString("Score Points by Hitting the Wall Adjacent to the Paddle", 100, 105);
        g.drawString("Click Play Pong to Begin", 170, 130);
        if(count !=0) g.drawString("Final Score: " + count, 200, 155);
      }
   
    }

  }
 

  private MyPanel panel;
 
 
  public Pong(String title) {
    super(title);
    
    JMenuBar bar = new JMenuBar();
    add(bar, BorderLayout.NORTH);
    JMenu fileMenu = new JMenu("File");
    bar.add(fileMenu);
    JMenuItem pongItem = new JMenuItem("Play Pong");
    fileMenu.add(pongItem);
    addKeyListener(this);
    pongItem.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e) {
        startPong();
      }
    });
    
    JMenu menu2 = new JMenu("About");
    bar.add(menu2);
    JMenuItem menuAbout = new JMenuItem("About");
    menuAbout.addActionListener(new AboutHandler());
    menu2.add(menuAbout);
    banner.setVisible(false);
    bar.add(banner);
    panel = new MyPanel();
    add(panel,BorderLayout.CENTER);
    setVisible(true);
    
    while(true) {
      try {
        Thread.sleep(5);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      this.repaint();
    }
    
  }
  
  
  public void keyPressed(KeyEvent e) {
    if(e.getKeyCode() == 38) {
      if(padpos>10) padpos -= 20;
    }
    if(e.getKeyCode() == 40) {
      if(padpos<90) padpos += 20;
    }
  }
 
  public void keyTyped(KeyEvent e){}
  public void keyReleased(KeyEvent e){}
  
  private static class AboutHandler implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      JOptionPane.showMessageDialog(null,
                                    "Thank you for playing \n" +
                                    "Created by: Michael Eber \n" + "Contact: [email protected] \n");
    }
  }
  
  public void startPong(){
    count=0; // resets the Final Score to 0
    startPong = ! startPong;
    banner.setVisible(false);
  } 
 
  public static void main(String[] args) {
    new Pong("Pong");
  }

}

Code:
import java.awt.Dimension;
import java.awt.Toolkit;
import javax.swing.JFrame;


public class FrameWithInheritance extends JFrame {

 public FrameWithInheritance(String title) {
  super(title);
  
  setBounds(200, 200, 505 , 255);
  setVisible(true);
  setDefaultCloseOperation(EXIT_ON_CLOSE);

  
 }

 public static void main(String[] args) {
  new FrameWithInheritance("Test");
 }

}
 
I'm trying to add sound but it seems too complicated, all I want to do is play a less than one second wav clip when the ball either hits the wall or paddle. I searched java sound and it seems very extensive can someone just dumb it down for me?
 
Also, if you want to fix that "rolling down the paddle" bug, take a look at this line
Code:
if(y >= padpos && y <= padpos + 100 && x <= 24) a=a*-1; //bounce off paddle
So, say the ball is moving left and hits the corner of the paddle. At the next time step, it moves right, but it's still in contact with the paddle. Hence, it moves left again, and so on until it doesn't touch the paddle anymore.

Instead, use absolute value. that is, do this:
Code:
if(y >= padpos && y <= padpos + 100 && x <= 24) a = Math.abs(a); //bounce off paddle
 
To address that audio feature,

Make sure the following import is present:
Code:
import java.applet.*;

Then, load the sound with
Code:
private AudioClip clip;

public Pong(String title)
{
    // ... snip ...
    clip = getAudioClip(getCodeBase(), "bounce.wav");
    // ... snip ...
}

Play the sound with
Code:
clip.play();

This assumes that you put the sound file in the same directory as the applet (which is where the getCodeBase() is going to point). If that's not the case, do this instead:
Code:
import java.io.*;

public Pong(String title)
{
    // ... snip ...
    File f = new File("<path to file>");
    clip = getAudioClip(f.toURI().toURL());
    // ... snip ...
}

Also, be warned that Java only supports a few types. Off the top of my head, I know that .AU, .WAV, and .MIDI are supported. And I'm pretty sure that .MP3 is not supported (yeah, that blows).
 
I tried both suggestions to no avail, the audio suggestions would only work if I extended it over a JApplet and not a JFrame. The absolute value just makes the ball go through the paddle every time.

Thanks for the help though, hopefully I can figure something out!
 
Oh I figured out why the absolute value didn't work was because I switched it to x-=a; and y-=a; so that the ball started off coming towards the paddle. Now it works perfectly.

Just have to figure out the sound aspect.
 
I tried this but I hear nothing:

Code:
    public void load(String file) {
 
      try{
      File af = new File("beep.wav");
      AudioInputStream ais = AudioSystem.getAudioInputStream(af);
 

      soundClip = AudioSystem.getClip();
      soundClip.open(ais);
      }catch(Exception e){};
    }
    

    public void play() {

      if (soundClip != null) {
        soundClip.setFramePosition(0);
        soundClip.start();
      }
    }

and I just put play(); where I wanted it to play.

I have beep.wav in the same folder as the class
 
Sorry about that. I guess I must have read the signs wrong. Anyways, for future reference, you could have made it work in the previous implementation by using a = -Math.abs(a) instead.

And for the sound, I forgot you weren't running in an Applet. Apologies again for that. Try this instead. Make sure you have these imports:
Code:
import sun.audio.*;
import java.io.*;

Then,
Code:
private AudioStream sound;

public Pong(String title)
{
    // ... snip ...
    sound = new AudioStream(new FileInputStream("<path to file>"));
    // ... snip ...
}

To play it:
Code:
AudioPlayer.player.play(sound);

Hopefully this all works this time around :)
 
I tried this but I hear nothing:

Code:
    public void load(String file) {
 
      try{
      File af = new File("beep.wav");
      AudioInputStream ais = AudioSystem.getAudioInputStream(af);
 

      soundClip = AudioSystem.getClip();
      soundClip.open(ais);
      }catch(Exception e){};
    }
    

    public void play() {

      if (soundClip != null) {
        soundClip.setFramePosition(0);
        soundClip.start();
      }
    }

and I just put play(); where I wanted it to play.

I have beep.wav in the same folder as the class

Do e.printStackTrace() in the catch. Maybe something went wrong.
 
Back