Skip to main content
gamedev.net
🔒 Locked 🎮 Unity

[java] confusing bug

Started by orangefranzie Jan 27, 2006 at 11:07 PM 4 replies 850+ views
Original Post
orangefranzie
orangefranzie
Hey folks, nice to meet you! I'm trying to program a pong applet in Java, but not object oriented style. I've made a couple simple game clones before, but this is my first Java game and I'm having a bit of trouble. This is also my first time using threads in Java so if I'm doing something wrong let me know. Anyway, the problem is this: the game works fine at first, I can play for maybe 2 minutes without a glitch. Then suddenly it freezes. In the Java Console it stays there is a StackOverflowError, which usually means that there is some sort of recursion happening, but theres no recursion in this program. Here it is:

// PongApplet.java

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

public class PongApplet extends JApplet implements Runnable
{
	//Constants
	private static final int WIDTH = 500;
	private static final int HEIGHT = 350;
	private static final int TOP_PADDING = 30;
	
	private static final int WALL_THICKNESS = 10;

	private static final int PLAYAREA_TOP = TOP_PADDING + WALL_THICKNESS;
	private static final int PLAYAREA_BOTTOM = HEIGHT - WALL_THICKNESS;

	private static final int BAT_THICKNESS = 10;
	private static final int BAT_HEIGHT = 60;
	private static final double BAT_START_Y = PLAYAREA_TOP + (PLAYAREA_BOTTOM-PLAYAREA_TOP)/2 - BAT_HEIGHT/2;
	private static final double BAT_SPEED = .5;
	
	private static final int BALL_SIZE = 10;
	private static final int BALL_START_X = WIDTH / 2;
	private static final int BALL_START_Y = (PLAYAREA_BOTTOM - PLAYAREA_TOP) / 2;

	//ball location and velocity
	private double ballX = BALL_START_X;
	private double ballY = BALL_START_Y;
	private double xVelocity = -0.3;
	private double yVelocity = 0.3;

	//bat locations
	private double bat1Y = BAT_START_Y;
	private double bat2Y = BAT_START_Y;

	//used for getting input
	boolean upPressed = false;
	boolean downPressed = false;
	boolean resetPressed = false;

	private Image buffer;
	private Thread animatorThread;

	public void init() 
	{
	}

	public void start() 
	{			
		buffer = createImage(WIDTH,HEIGHT);
		animatorThread = new Thread(this);
		animatorThread.start();		
	}

	public void stop() 
	{
		buffer = null;
		animatorThread = null;
	}

	public void destroy() 
	{
	}
	
	public void run()
	{
		while(true)
		{
			try {
			requestFocus();
			
			addKeyListener(new KeyAdapter() {
			
			//get input				
			public void keyPressed(KeyEvent e)
			{
				int keycode = e.getKeyCode();
				if(keycode == KeyEvent.VK_UP)
					upPressed = true;
				if(keycode == KeyEvent.VK_DOWN)
					downPressed = true;
				if(keycode == KeyEvent.VK_R)
					resetPressed = true;
			}

			public void keyReleased(KeyEvent e) 
			{			
				int keycode = e.getKeyCode();
				if(keycode == KeyEvent.VK_UP)
					upPressed = false;
				if(keycode == KeyEvent.VK_DOWN)
					downPressed = false;
				if(keycode == KeyEvent.VK_R)
					resetPressed = false;
			}
			});

			if(resetPressed)
			{
				ballX = BALL_START_X;
				ballY = BALL_START_Y;
				resetPressed = false;
			}
							
			//move the left bat	
			if(upPressed)
				bat1Y -= BAT_SPEED;
			if(downPressed)
				bat1Y += BAT_SPEED;

			//move the right bat (until i make the AI)
			if(upPressed)
				bat2Y -= BAT_SPEED;
			if(downPressed)
				bat2Y += BAT_SPEED;

			//correct the position if the bat left the play area
			if(bat1Y < PLAYAREA_TOP)
				bat1Y = PLAYAREA_TOP;
			if(bat1Y + BAT_HEIGHT > PLAYAREA_BOTTOM)
				bat1Y = PLAYAREA_BOTTOM-BAT_HEIGHT;

			//calculate ball's new position
			double newBallX = ballX + xVelocity;
			double newBallY = ballY + yVelocity;			

			//bounce ball off top or bottom of play area
			if(newBallY + BALL_SIZE/2 > PLAYAREA_BOTTOM ||
				newBallY < PLAYAREA_TOP)
				yVelocity = -yVelocity;

			//test for collisions between ball and right bat
			if(xVelocity > 0 && newBallX >= WIDTH-BAT_THICKNESS)
			{
				if(ballX <= WIDTH-BAT_THICKNESS) //bounce off front of bat
				{
					if(ballY > bat2Y && ballY < bat2Y+BAT_HEIGHT)
						xVelocity = -xVelocity;
				}
				else //bounce off top or bottom of bat
				{
					if(ballY < bat2Y && yVelocity > 0 && newBallY > bat2Y)		
						yVelocity = -yVelocity;	
					else if(ballY > bat2Y+BAT_HEIGHT && yVelocity < 0 && newBallY < bat2Y+BAT_HEIGHT)
						yVelocity = -yVelocity;
				}
			}
			//collisions between ball and left bat
			else if(xVelocity < 0 && newBallX <= BAT_THICKNESS)
			{
				if(ballX >= BAT_THICKNESS) //bounce off front of bat
				{
					if(ballY > bat1Y && ballY < bat1Y+BAT_HEIGHT)
						xVelocity = -xVelocity;
				}
				else //bounce off top or bottom of bat
				{
					if(ballY < bat1Y && yVelocity > 0 && newBallY > bat1Y)		
						yVelocity = -yVelocity;	
					else if(ballY > bat1Y+BAT_HEIGHT && yVelocity < 0 && newBallY < bat1Y+BAT_HEIGHT)
						yVelocity = -yVelocity;
				}
			}
			
			//move ball to new position
			ballX = newBallX;
			ballY = newBallY;
			
			//draw to buffer
			//draw background, ball
			Graphics bg = buffer.getGraphics();
			bg.setColor(Color.black);
			bg.fillRect(0,0,WIDTH,HEIGHT);
			bg.setColor(Color.white);
			bg.fillRect((int)(ballX - BALL_SIZE/2), (int)(ballY - BALL_SIZE/2), BALL_SIZE, BALL_SIZE);

			//draw walls
			bg.fillRect(0,PLAYAREA_TOP-WALL_THICKNESS,WIDTH,WALL_THICKNESS);
			bg.fillRect(0,PLAYAREA_BOTTOM,WIDTH,WALL_THICKNESS);

			//draw bats
			bg.fillRect(0,(int)bat1Y,BAT_THICKNESS,BAT_HEIGHT);
			bg.fillRect(WIDTH-BAT_THICKNESS,(int)bat2Y,BAT_THICKNESS,BAT_HEIGHT);
			
			//display buffer in the applet
			Graphics g = this.getGraphics();
			g.drawImage(buffer,0,0,null);	
				
			//let other threads do their thing
			animatorThread.yield();
			} catch (Exception e){}
		}
	}

	public void paint(Graphics g) 
	{
	}
}

If anyone can figure out what I've done wrong, I'd be really pleased. Theres still lots of functionality left to add to the game so try not to let that distract you. ;) Thanks a lot!
PorkBag
PorkBag
Maybe its because you're adding the key listener inside the main loop, running that code with everything by the addKeyListener part removed gives me an outofmemory error after a while.
orangefranzie
orangefranzie
That was exactly it. I guess adding a key listener in every iteration of the main loop would make quite a few key listeners, wouldn't it? Thanks for the help PorkBag, I owe you one.
Son of Cain
Son of Cain
Sure, a lot of them. Create them outside the scope of the main loop, whose only responsibility is to update the logic and draw the frames.

Son of Cain
a.k.a javabeats at yahoo.ca
orangefranzie
orangefranzie
So I finished making the pong game, and now I'm thinking about doing it again object oriented style. I've done a bit of research about different ways of designing the game, what classes to build and how they interact with each other.

The main thing that I'm not sure how to do is the collisions between the all and the paddles. Some designs put that in the Ball class, some put it in the Paddle class, and some put it in another higher level class like Playarea or PongGame. Is this a matter of programmer preference? Or is there a certain way that is considered correct in OOP?

To me it seems like the Playarea class would be the place for collision detection. If I put it in the Ball or Paddle class then those classes would have to have intimate knowledge of each other. Another thing I thought of was to make a class that specifically to deal with the collisions.

Anyway, I know theres hundreds of articles out there but I like to hear real peoples opinions on the subject too. If you have any advice to share, please do.
Son of Cain
Son of Cain
Your collision detection code goes into update(), dude. Your Ball class will surely have bounds (Rectangle2D or any other approach), and the logic for changing their directions based on the collision detected goes into the update() method called by the main loop.
a.k.a javabeats at yahoo.ca

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.