Jump to content


Check out our Community Blogs

Register and join over 40,000 other developers!


Recent Status Updates

View All Updates

Photo
- - - - -

[Solved] Bouncing Ball Help

setpreferredsize bouncing ball

  • Please log in to reply
5 replies to this topic

#1 Cruel Hand

Cruel Hand

    CC Addict

  • Advanced Member
  • PipPipPipPipPip
  • 195 posts
  • Programming Language:Java, Objective-C, Visual Basic .NET
  • Learning:C, Java, C++, Objective-C, PHP, (Visual) Basic, Python, JavaScript, Perl, Ruby, PL/SQL, Pascal, Assembly, Haskell

Posted 17 June 2012 - 11:17 AM

I'm writing a program that animates a ball bouncing in a JFrame. The program gets the width and height of the frame from the user, it gets the diameter of the ball and the delay (in milliseconds) of the time between drawing the ball. I thought I wrote it correctly, but when I run the program I get an empty JFrame, so I'm obviously doing something wrong. I'm sure it has something to do with the while(true) loop I wrote, because it was drawing a single ball before that. If someone could help me out, that would be great, thanks :D
I've highlighted where I'm having trouble (BouncePanel class).


Solved thanks to gregwarner.

I'm sure I could have made the bounce() method much easier, though

Bounce class:
import java.util.Scanner;
import javax.swing.JFrame;

public class Bounce {

	static int width = 0, height = 0, diameter = 0, delay = 0;
	
	public static void main(String[] args){
		getInput();
		//declares a JFrame and adds the panel to it
		JFrame frame = new JFrame("Follow the Bouncing Ball");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		BouncePanel panel = new BouncePanel(width, height, diameter, delay);
		frame.getContentPane().add(panel);
		frame.pack();
		frame.setVisible(true);
		panel.bounce();
	}
	
	//gets user input. If the input is not an integer, re-prompt
	private static void getInput(){
		Scanner input = new Scanner(System.in);
		boolean widthPass = false, heightPass = false, diameterPass = false;
		while(true){
			try{
				if(diameterPass){
					System.out.print("Enter delay (in milliseconds): ");
					delay = Integer.parseInt(input.nextLine());
					break;
				}
				if(heightPass){
					System.out.print("Enter diameter of ball: ");
					diameter = Integer.parseInt(input.nextLine().trim());
					if(diameter > width/4){
						System.out.println("Diameter cannot be greater than "+width/4);
						continue;
					}
					diameterPass = true;
					continue;
				}
				if(widthPass){
					System.out.print("Enter height of frame: ");
					height = Integer.parseInt(input.nextLine().trim());
					if(height < 100){
						System.out.println("Height must be greater than 100; try again.");
						continue;
					}
					heightPass = true;
					continue;
				}
				System.out.print("Enter width of frame: ");
				width = Integer.parseInt(input.nextLine().trim());
				if(width < 100){
					System.out.println("Width must be greater than 100; try again.");
					continue;
				}
				widthPass = true;
			}catch(NumberFormatException e){
				System.out.println("Input was not an integer; try again.");
			}
		}
	}
	
}

BouncePanel class:
import javax.swing.JPanel;
import java.awt.*;
import java.util.Random;

public class BouncePanel extends JPanel {
	
	int width, height, diameter, delay;
	Random r = new Random();
	int x, y;
	Color c = new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255));
	boolean bouncingLeft = false, bouncingRight = false, bouncingUp = false,
			bouncingDown = false;
	
	public BouncePanel(int w, int h, int diam, int d){
		width = w;
		height = h;
		diameter = diam;
		delay = d;
		x = r.nextInt(width-diameter);
		y = r.nextInt(height-diameter);
		setPreferredSize(new Dimension(width, height));
	}
	
	public void paintComponent(Graphics g){
		super.paintComponent(g);
		//creates a random color, random x coordinate for the ball and a random y coordinate
		g.setColor(c);
			g.fillOval(x, y, diameter, diameter);
	}
	
	public void bounce(){
		while(true){
			//re-draws the ball every certain amt of milliseconds specified by the user (delay)
			//if the ball reaches the edge of the frame, reverse it
			if(bouncingLeft){
				x--; y--;
			}else if(bouncingUp){
				x++; y--;
			}else if(bouncingDown){
				x--; y++;
			}else if(bouncingRight){
				x++; y++;
			}else{
				x++; y++;
			}
			if(y == height-diameter){
				bouncingLeft = false;
				bouncingRight = false;
				bouncingUp = true;
				bouncingDown = false;
			}else if(y == 0){
				bouncingLeft = false;
				bouncingRight = false;
				bouncingUp = false;
				bouncingDown = true;
			}else if(x == width-diameter){
				bouncingLeft = true;
				bouncingRight = false;
				bouncingUp = false;
				bouncingDown = false;
			}else if(x == 0){
				bouncingLeft = false;
				bouncingRight = true;
				bouncingUp = false;
				bouncingDown = false;
			}
			try{
				Thread.sleep(delay);
			}catch(InterruptedException e){}
			repaint();
		}
	}

  • 0

#2 gregwarner

gregwarner

    Obi Wan of Programming

  • Expert Member
  • PipPipPipPipPipPipPip
  • 1586 posts
  • Location:Arkansas
  • Programming Language:C, Java, C++, C#, PHP, Transact-SQL

Posted 17 June 2012 - 12:02 PM

Your main game loop should not go inside paintComponent().

The system will call paintComponent() multiple times. This method should be responsible for painting one frame of animation, using instance variables to retrieve the current positions of the sprites.

Instead of telling you all the ways you need to restructure your program here, have a look at this tutorial I found and then rebuild your game using the proper structure.
http://www.gamedev.n...-a-simple-r1360

And another one:

http://www3.ntu.edu...._Framework.html

Edit: To put it briefly, your main loop should be executed in a different thread from the event dispatch thread, and look something like this:
boolean alive = true;
while (alive) {
    // Get the time that has passed since the last time the loop ran.
    // Move the game sprites and objects an appropriate distance for the time that has elapsed.
    // Get user input. Make changes to game sprites and objects as necessary.
    // If conditions dictate we should terminate the game, set alive = false.
    // ...
    repaint(); // Draw this frame of animation.
}
...
paintComponent(Graphics g) {
    // Get the locations of the sprites.
    // Draw all the sprites on the screen.
}

  • 0

ti-99-sig.png
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
– Douglas Hofstadter, Gödel, Escher, Bach: An Eternal Golden Braid


#3 Cruel Hand

Cruel Hand

    CC Addict

  • Advanced Member
  • PipPipPipPipPip
  • 195 posts
  • Programming Language:Java, Objective-C, Visual Basic .NET
  • Learning:C, Java, C++, Objective-C, PHP, (Visual) Basic, Python, JavaScript, Perl, Ruby, PL/SQL, Pascal, Assembly, Haskell

Posted 17 June 2012 - 12:26 PM

thanks, greg. However, that game programming stuff is way too advanced for me. I'm not trying to build a game, I'm just trying to re-draw a circle over and over again, until the user clicks exit. Can you try to dumb it down for me? According to the book I'm reading, this should be possible with just jpanel and jframe.
  • 0

#4 gregwarner

gregwarner

    Obi Wan of Programming

  • Expert Member
  • PipPipPipPipPipPipPip
  • 1586 posts
  • Location:Arkansas
  • Programming Language:C, Java, C++, C#, PHP, Transact-SQL

Posted 17 June 2012 - 12:37 PM

Whether you're learning game programming or simply trying to draw a bouncing ball on the screen is irrelevant. They both use the same technique.

Whenever you are animating anything on the screen, you need a main loop to control the state changes over time. Whenever anything is animated, it's position is usually a function of time. Therefore, you need to have your main loop run somewhere outside of the drawing function (paintComponent), and call repaint() on your interface once per loop iteration. This triggers the underlying system to call paintComponent, which draws one frame of your animation. Your main loop then repeats, changing the state of the objects slightly, and calling repaint() again.

Those tutorials I gave you, and the example I posted above, are both pretty basic and should be enough to get you going again. Move your main loop out of paintComponent and put it in its own method. Your program should start up and initialize all the objects in the animation: The frame size, the starting position of the ball, the initial movement vectors, etc. Then, after all this is initialized, you call your method with the main loop in it. The loop starts, and begins moving the animated objects around by changing their state through instance variables. You store the position in one variable, the velocity or movement vector in another, etc. Any information you need to draw one frame of movement at any given time needs to be stored in an instance variable. That way, whenever the loop finishes and calls repaint() as its last step before repeating, the component's paintComponent() method will be able to access these instance variables to get the necessary information to draw the frame.
  • 0

ti-99-sig.png
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
– Douglas Hofstadter, Gödel, Escher, Bach: An Eternal Golden Braid


#5 BlackRabbit

BlackRabbit

    CodeCall Legend

  • Expert Member
  • PipPipPipPipPipPipPipPip
  • 3871 posts
  • Location:Argentina
  • Programming Language:C, C++, C#, PHP, JavaScript, Transact-SQL, Bash, Others
  • Learning:Java, Others

Posted 17 June 2012 - 12:37 PM

i fully second greg's suggestion
  • 0

#6 Cruel Hand

Cruel Hand

    CC Addict

  • Advanced Member
  • PipPipPipPipPip
  • 195 posts
  • Programming Language:Java, Objective-C, Visual Basic .NET
  • Learning:C, Java, C++, Objective-C, PHP, (Visual) Basic, Python, JavaScript, Perl, Ruby, PL/SQL, Pascal, Assembly, Haskell

Posted 17 June 2012 - 03:11 PM

thanks a lot, greg! I got it working. The book I'm using uses a custom class (drawableFrame) so it doesn't teach anything about paintComponent (or JPanel and JFrame for that matter), so everything I've learned about graphics has pretty much been internet inquiries. I posted my code if anyone wants to run it and see what it looks like.

thanks again!
  • 0





Also tagged with one or more of these keywords: setpreferredsize, bouncing ball

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download