http://pastebin.com/PXLFJjNG
I'm trying to figure out threading and animations so I made this really basic program where you can press buttons to move a rectangle up and down. The problem is that if you keep pressing the UP button till the rectangle reaches the top of the screen there's suddenly an extra blue rectangle.
This problem is kinda hard to explain just run the program and keep pressing UP and when you get to the top there's suddenly 2 rectangles being drawn. Is it a problem with my paint component?
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class RectangleMovement implements Runnable {
JFrame frame;
MyPanel panel;
private int x = 100;
private int y = 100;
private int playerX = 400;
private int playerY = 350;
private int horizontalGoal = 0;
private int verticalGoal = 0;
public static void main(String[] args) {
new RectangleMovement().go();
}
private void go() {
frame = new JFrame("Worst Game Ever");
panel = new MyPanel();
MyPanel buttonPanel = new MyPanel();
JButton left = new JButton("Left");
JButton right = new JButton("Right");
JButton down = new JButton("Down");
JButton up = new JButton("Up");
left.addActionListener(new LeftButton());
right.addActionListener(new RightButton());
down.addActionListener(new DownButton());
up.addActionListener(new UpButton());
buttonPanel.setLayout(new FlowLayout());
buttonPanel.add(left);
buttonPanel.add(down);
buttonPanel.add(up);
buttonPanel.add(right);
frame.getContentPane().add(BorderLayout.CENTER, panel);
frame.getContentPane().add(BorderLayout.SOUTH, buttonPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setSize(500, 500);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
Thread player = new Thread(this);
player.start();
animate();
}
private class MyPanel extends JPanel {
/**
*
*/
private static final long serialVersionUID = 1L;
public void paintComponent(Graphics g) {
g.setColor(Color.RED);
g.fillRect(x, y, 10, 10);
g.setColor(Color.BLUE);
g.fillRect(playerX, playerY, 10, 10);
}
}
class LeftButton implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
horizontalGoal = -5;
}
}
class RightButton implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
horizontalGoal = 5;
}
}
class UpButton implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
verticalGoal = -5;
}
}
class DownButton implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
verticalGoal = 5;
}
}
/*
* Animates the player
*/
public void run() {
while (true) {
if (horizontalGoal < 0 && playerX > 0) {
playerX--;
horizontalGoal++;
} else if (horizontalGoal > 0 && playerX + 20 < frame.getWidth()) {
playerX++;
horizontalGoal--;
}
if (verticalGoal < 0 && playerY > 0) {
playerY--;
verticalGoal++;
} else if (verticalGoal > 0 && playerY + 10 < 400) {
playerY++;
verticalGoal--;
}
try {
Thread.sleep(15);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (intersects()){
playerX = 400;
playerY = 350;
}
frame.repaint();
}
}
private void animate() {
boolean direction = true;
while (true) {
if (y <= 100) {
direction = true;
} else if (y >= 400) {
direction = false;
}
if (direction) {
y++;
} else {
y--;
}
try {
Thread.sleep(15);
} catch (InterruptedException e) {
e.printStackTrace();
}
frame.repaint();
}
}
private boolean intersects() {
if (x <= playerX && playerX <= x + 10 && y <= playerY
&& playerY <= y + 10) {
return true;
}
return false;
}
}
Your buttonPanel is the Problem. It is also a MyPanel which uses your own paintComponent method. So if your player should be drawn playerY = 10. It is drawn on your game panel and your buttonPanel.
Change your ButtonPanel from
MyPanel buttonPanel = new MyPanel();
to
Panel buttonPanel = new Panel();
and your probelm is gone :-)
Related
Im trying to code a simple 2D game. I have a Square that you can move with a/w/d. I got jumping working with a sort of gravity but now I cant get myself to land on a platform. I know how to detect collision between two things but even still idk what to do. My gravity always pulls me down until I reach groundLevel which is part of the problem. Here is my code so far. There's a lot of experimenting happing so its pretty messy.
import javax.swing.Timer;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.geom.*;
/**
* Custom Graphics Example: Using key/button to move a line left or right.
*/
public class PlatformingGame extends JFrame implements ActionListener, KeyListener{
// Name-constants for the various dimensions
public static final int CANVAS_WIDTH = 800;
public static final int CANVAS_HEIGHT = 400;
public static final Color LINE_COLOR = Color.BLACK;
public static final Color CANVAS_BACKGROUND = Color.WHITE;
public int GRAVITY = 10;
public int TERMINAL_VELOCITY = 300;
public int vertical_speed = 0;
public int jumpSpeed;
public int groundLevel = CANVAS_HEIGHT;
int Shapes;
private DrawCanvas canvas; // the custom drawing canvas (extends JPanel)
public enum STATE {
PLAYING,
PAUSED,
ONGROUND,
INAIR
};
JButton btnStartRestat, btnExit;
Timer timer;
Rectangle2D.Double guy, platform, platform2;
Shape[] shapeArr = new Shape[10];
int dx, dy;
/** Constructor to set up the GUI */
ArrayList myKeys = new ArrayList<Character>();
public static STATE gameState = STATE.PAUSED;
//public static STATE playerState = STATE.ONGROUND;
public PlatformingGame() {
dx = 3;
dy = 3;
guy = new Rectangle2D.Double( CANVAS_WIDTH/2 - 20, CANVAS_HEIGHT, 30, 20);
platform2 = new Rectangle2D.Double( CANVAS_WIDTH/4, CANVAS_HEIGHT/2+130, 50, 10);
platform = new Rectangle2D.Double( CANVAS_WIDTH/3, CANVAS_HEIGHT/2+50, 50, 10);
timer = new Timer(10, this);
// Set up a panel for the buttons
JPanel btnPanel = new JPanel();
// btnPanel.setPreferredSize(new Dimension(CANVAS_WIDTH/2, CANVAS_HEIGHT));
btnPanel.setLayout(new FlowLayout());
btnStartRestat = new JButton("Start/Restart");
btnExit = new JButton("Exit");
btnPanel.add(btnStartRestat);
btnPanel.add(btnExit);
btnStartRestat.addActionListener(this);
btnExit.addActionListener(this);
// Set up a custom drawing JPanel
canvas = new DrawCanvas();
canvas.setPreferredSize(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT));
// Add both panels to this JFrame
Container cp = getContentPane();
cp.setLayout(new BorderLayout());
cp.add(canvas, BorderLayout.CENTER);
cp.add(btnPanel, BorderLayout.SOUTH);
// "this" JFrame fires KeyEvent
addKeyListener(this);
requestFocus(); // set the focus to JFrame to receive KeyEvent
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Handle the CLOSE button
pack(); // pack all the components in the JFrame
setVisible(true); // show it
}
public void generateSpikes(){
Rectangle2D.Double spikes = null;
for (int i = 0; i < 10; i++) {
spikes = new Rectangle2D.Double (CANVAS_WIDTH - 300 + i*20 , CANVAS_HEIGHT - 30 , 20, 30);
shapeArr[i] = spikes;
}
}
public void actionPerformed(ActionEvent e)
{
if (e.getSource()==btnStartRestat)
{
generateSpikes();
dx = 3;
dy = 3;
guy = new Rectangle2D.Double( 100, CANVAS_HEIGHT - guy.height, 15, 30);
platform = new Rectangle2D.Double( CANVAS_WIDTH/3, CANVAS_HEIGHT/2+50, 50, 10);
platform2 = new Rectangle2D.Double( CANVAS_WIDTH/4, CANVAS_HEIGHT/2+130, 50, 10);
gameState = STATE.PLAYING;
}
else if (e.getSource()==btnExit)
{
// requestFocus(); // change the focus to JFrame to receive KeyEvent
}
else if (e.getSource()== timer){
if (isHitDetected(platform2, guy)){
// playerState = STATE.ONGROUND;
guy.y = platform2.y;
}
if (myKeys.contains('a')
&& (guy.x > 0)){
guy.x = guy.x - 5; }
if (myKeys.contains('d')
&& (guy.x < CANVAS_WIDTH - guy.width)){
guy.x = guy.x + 5; }
{
updateGuyPosition();
}
requestFocus();
canvas.repaint();
}
}
public void updateGuyPosition(){
double guyHeight = guy.height;
if (guy.x >= CANVAS_WIDTH - guy.width){
}
if(gameState == STATE.PLAYING) {
guy.y += jumpSpeed;
if (guy.y < groundLevel - guyHeight) {
// if(playerState == STATE.INAIR) {
jumpSpeed += 1;
}
// }
else {
// if(playerState == STATE.INAIR) {
//playerState = STATE.ONGROUND;
jumpSpeed = 0;
guy.y = groundLevel - guyHeight;
}
// }
if (myKeys.contains('w') == true && guy.y == groundLevel - guyHeight) {
jumpSpeed = -15;
// playerState = STATE.INAIR;
}
}
}
public static boolean isHitDetected(Shape shapeA, Shape shapeB) {
Area areaA = new Area(shapeA);
areaA.intersect(new Area(shapeB));
return !areaA.isEmpty();
}
public void keyPressed(KeyEvent evt) {
if (!myKeys.contains(evt.getKeyChar())){
myKeys.add(evt.getKeyChar());
}
}
public void keyReleased(KeyEvent evt) {
myKeys.remove(myKeys.indexOf(evt.getKeyChar()));
}
public void keyTyped(KeyEvent evt) {
}
/** The entry main() method */
public static void main(String[] args) {
PlatformingGame myProg = new PlatformingGame(); // Let the constructor do the job
myProg.timer.start();
}
/**
* DrawCanvas (inner class) is a JPanel used for custom drawing
*/
class DrawCanvas extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
setBackground(CANVAS_BACKGROUND);
g.setColor(LINE_COLOR);
Graphics2D g2d = (Graphics2D)g;
if(gameState == STATE.PLAYING) {
g2d.fill(guy);
g.setColor(Color.lightGray);
g2d.fill(platform);
g2d.fill(platform2);
for (int i = 0; i < 10; i++) {
g2d.fill(shapeArr[i]);
}
}
if(gameState == STATE.PAUSED) {
g.drawString("Game Paused", CANVAS_WIDTH/2, CANVAS_HEIGHT/2);
}
}
}
}
So this is what I currently have. After I click the button, it should bounce from center to right and then left and then back to its original position. Then I should be able to click the button again so that it would start another cycle.
public class Bounce extends JFrame {
private static JButton btnMovement = new JButton("Click");
private Container container;
private Timer timer;
private int x = 290;
private int y = 350;
private int radius = 100;
private int moves = 2;
public Bounce() {
container = getContentPane();
container.setLayout(new FlowLayout());
final MoveListener ml = new MoveListener();
btnMovement.addActionListener(ml);
timer = new Timer(5, ml);
}
private void Move() {
x += moves;
if (x + (radius * 2) > getWidth()) {
x = getWidth() - (radius * 2);
moves *= -1;
} else if (x < 0) {
x = 0;
moves *= -1;
}
repaint();
}
class MoveListener implements ActionListener {
public void actionPerformed(final ActionEvent event) {
if (!timer.isRunning()){
timer.start();
} else if (timer.isRunning() && x == 290 && y == 350){ // I don't know what condition to put
timer.stop();
}
Move();
}
}
public void paint (Graphics g){
super.paint(g);
g.setColor(Color.black);
g.fillOval(x - 5, y - radius - 5, radius + 110, radius + 110);
g.setColor(Color.red);
g.fillOval(x, y - radius, radius * 2, radius * 2);
}
public static void main(String args[]){
final JFrame window = new Bounce();
window.add(btnMovement);
window.setSize(800, 800);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setVisible(true);
}
}
The ActionListener for the Timer should be seperate - it acts as pseudo loop. Basically, once the ball bounces of the left side, you change a flag to indicate that it should stop once it reaches or passes the mid point, for example...
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private Timer timer;
private int xPos;
private int yPos;
public TestPane() {
JButton btn = new JButton("Start");
xPos = 95;
yPos = 95;
timer = new Timer(5, new ActionListener() {
private int xDelta = 1;
private boolean hasBounced = false;
#Override
public void actionPerformed(ActionEvent e) {
xPos += xDelta;
int middleX = (getWidth() / 2) - 5;
if (xPos + 10 > getWidth()) {
xPos = getWidth() - 10;
xDelta *= -1;
} else if (xPos < 0) {
xPos = 0;
xDelta *= -1;
hasBounced = true;
} else if (hasBounced && xPos >= middleX) {
timer.stop();
btn.setEnabled(true);
hasBounced = false;
}
repaint();
}
});
setLayout(new BorderLayout());
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
btn.setEnabled(false);
timer.start();
}
});
add(btn, BorderLayout.SOUTH);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawOval(xPos, yPos, 10, 10);
g2d.dispose();
}
}
}
A more complicated solution would be to record the current position as the timer starts and use that as the "end point", but I'll leave that up to you
I want to run the snake class after the start button its pressed the programg works until i press the start button and try to move the rectangle around the window, there is the problem the rectangle wont move at all. Please help. Thanks.
public class Main {
public static void main(String [] args) {
MenuScreen MenuScreen = new MenuScreen();
MenuScreen.menuscreen();
}
}
The Screen Menu class
import java.awt.Color;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class MenuScreen {
Snake Snake = new Snake();
public void menuscreen () {
//Window
final JFrame window = new JFrame();
window.setVisible(true);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setSize(800, 600);
window.setLocationRelativeTo(null);
//Panel
JPanel panel = new JPanel();
window.getContentPane().add(panel);
panel.setBackground(Color.BLACK);
panel.setVisible(true);
panel.setLayout(null);
//Title
JLabel label = new JLabel("SNAKE");
panel.add(label);
label.setBounds(290, 5, 204, 73);
label.setFont(new Font("Tahoma", Font.BOLD, 60));
label.setHorizontalAlignment(SwingConstants.CENTER);
label.setForeground(Color.RED);
label.setBackground(Color.red);
//Buttons
//start button
JButton bstart = new JButton ("Start");
panel.add(bstart);
bstart.setBounds(424, 200, 70, 60);
bstart.setVisible(true);
//start button - run snake on click
bstart.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
window.getContentPane().removeAll();
Snake Snake = new Snake();
window.add(Snake);
window.repaint();
window.revalidate();
}
});
//exit button
JButton bexit = new JButton ("Exit");
panel.add(bexit);
bexit.setBounds(290, 200, 70, 60);
bexit.setVisible(true);
//exit button - close on click
bexit.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
System.exit(0);
}
});
}
}
The Snake class, when I click start the frame gets cleared and shows the rect but when I try to move the rect aroud the screen it wont move.
public class Snake extends JPanel implements ActionListener, KeyListener {
public void thicks () {}
public Snake () {
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
}
private static final long serialVersionUID = 1L;
Timer FPS = new Timer( 5, this);
double x =0 , y = 0, SpeedX = 0, SpeedY = 0;
public void paint(Graphics g) {
FPS.start();
super.paintComponent(g);
g.setColor(Color.blue);
Graphics2D graphics = (Graphics2D) g;
Rectangle2D rect = new Rectangle2D.Double(x, y, 40, 40);
graphics.fill(rect);
}
public void actionPerformed(ActionEvent e) {
if(x < 0 || x > 740 ) {
SpeedX= -SpeedX;
}
if(y < 0 || y > 520) {
SpeedY = -SpeedY;
}
x += SpeedX;
y += SpeedY;
repaint();
}
public void down() {
SpeedY = 2;
SpeedX = 0;
}
public void up() {
SpeedY = -2;
SpeedX = 0;
}
public void right() {
SpeedY = 0;
SpeedX = 2;
}
public void left() {
SpeedY = 0;
SpeedX = -2;
}
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_DOWN) {
down();
}
if(keyCode == KeyEvent.VK_UP) {
up();
}
if(keyCode == KeyEvent.VK_RIGHT) {
right();
}
if(keyCode == KeyEvent.VK_LEFT) {
left();
}
}
public void keyReleased(KeyEvent e) {}
public void keyTyped(KeyEvent e) {}
}
I have a simple ball bounce program in which the balls bounce of the sides of my frame fine. I tried to add a way for the balls to bounce off each other by checking if two balls were touching by creating a rectangle around each ball and checking if any other ball intersects that rectangle, and if they do switch their velocities. It works fine when I add the code that has ** around it and there is only one ball but as soon as I add more than one they start moving together until they get stuck out of the frame. I have no idea what is wrong.
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.*;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
public class BallBounceFrame
{
public static void main(String[] args)
{
new BallBounceFrame();
}
JFrame frame;
JPanel controlPanel;
JButton stop, start;
JSpinner ballNum;
Timer t;
BallCanvas c;
static int WIDTH = 500;
static int HEIGHT = 500;
public BallBounceFrame()
{
frame = new JFrame("Bouncing Balls");
frame.setSize(WIDTH, HEIGHT);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setResizable(false);
c = new BallCanvas(0, 20);
frame.add(c, BorderLayout.CENTER);
addPanels();
frame.setVisible(true);
t = new Timer(10, new animator());
t.start();
}
public void addPanels()
{
controlPanel = new JPanel();
start = new JButton("Start");
start.addActionListener(new buttonControlListener());
controlPanel.add(start);
stop = new JButton("Stop");
stop.addActionListener(new buttonControlListener());
controlPanel.add(stop);
ballNum = new JSpinner(new SpinnerNumberModel(0, 0, 1000, 1));
ballNum.addChangeListener(new spinnerControlListener());
controlPanel.add(ballNum);
frame.add(controlPanel, BorderLayout.NORTH);
}
class BallCanvas extends JPanel
{
private static final long serialVersionUID = 1L;
ArrayList<Ball> balls = new ArrayList<Ball>();
public BallCanvas(int ballNum, int ballSize)
{
setBalls(ballNum, ballSize);
}
public void paint(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(Color.RED);
for(Ball b : balls)
{
b.move(this.getSize());
g2.fill(b);
}
}
public void animate()
{
while(true)
{
try
{
frame.repaint();
Thread.sleep(10);
}
catch(Exception e)
{
System.out.println(e);
}
}
}
public void setBalls(int ballNum, int ballSize)
{
balls.clear();
for(int i = 0; i < ballNum; i++)
{
balls.add(new Ball(ballSize, balls));
}
}
}
class Ball extends Ellipse2D.Float
{
private int xVel, yVel;
private int size;
private ArrayList<Ball> balls;
public Ball(int size, ArrayList<Ball> balls)
{
super((int) (Math.random() * (BallBounceFrame.WIDTH /(1.1)) + 1), (int) (Math.random() * (BallBounceFrame.WIDTH /(1.3)) + 7), size, size);
this.size = size;
this.xVel = (int) (Math.random() * 7 + 2);
this.yVel = (int) (Math.random() * 7 + 2);
this.balls = balls;
}
public void move(Dimension panelSize)
{
**Rectangle2D r = new Rectangle2D.Float(super.x, super.y, size, size);
for(Ball b : balls)
{
if(b != this && b.intersects(r));
{
int tempx = xVel;
int tempy = yVel;
xVel = b.xVel;
yVel = b.yVel;
b.xVel = tempx;
b.yVel = tempy;
break;
}
}**
if(super.x < 0 || super.x > panelSize.getWidth() - size) xVel *= -1;
if(super.y < 5 || super.y > panelSize.getHeight() - size) yVel *= -1;
super.x += xVel;
super.y += yVel;
}
}
class animator implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
frame.repaint();
}
}
class buttonControlListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == stop) t.stop();
if(e.getSource() == start) t.start();
}
}
class spinnerControlListener implements ChangeListener
{
public void stateChanged(ChangeEvent e) {
if(e.getSource() == ballNum)
{
int balls = (int) ballNum.getValue();
c.setBalls(balls, 20);
frame.revalidate();
frame.repaint();
}
}
}
}
Your code has a single ArrayList<Ball> inside BallCanvas - the 'master' list - and then each Ball has its own ArrayList<Ball> representing the list of balls the were created up until that time. Ball then only uses its own ArrayList<Ball> inside the move() method.
May I suggest that you only have one, master ArrayList<Ball> inside BallCanvas? Instead of passing it in to the Ball constructor, pass it in to the move() call.
I have my program running where I have a variable radius so that the balls can be of a size int, but I would like to know how to make this program more complex with adding random sizes of balls. small,medium,big etc. On line 148 I tried changing it to int radius = (int)(5*Math.random); but it did not work. Must I do something else to my code in order for this to work? And if there are any other hints you may have, they'd be much appreciated. Thanks
import javax.swing.Timer;
import java.util.ArrayList;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class MultipleBallApp extends JApplet
{
public MultipleBallApp()
{
add(new BallControl());
}
class BallControl extends JPanel {
private BallPanel ballPanel = new BallPanel();
private JButton jbtSuspend = new JButton("Suspend");
private JButton jbtResume = new JButton("Resume");
private JButton jbtAdd = new JButton("+1");
private JButton jbtSubtract = new JButton("-1");
private JScrollBar jsbDelay = new JScrollBar();
public BallControl() {
// Group buttons in a panel
JPanel panel = new JPanel();
panel.add(jbtSuspend);
panel.add(jbtResume);
panel.add(jbtAdd);
panel.add(jbtSubtract);
// Add ball and buttons to the panel
ballPanel.setBorder(new javax.swing.border.LineBorder(Color.red));
jsbDelay.setOrientation(JScrollBar.HORIZONTAL);
ballPanel.setDelay(jsbDelay.getMaximum());
setLayout(new BorderLayout());
add(jsbDelay, BorderLayout.NORTH);
add(ballPanel, BorderLayout.CENTER);
add(panel, BorderLayout.SOUTH);
// Register listeners
jbtSuspend.addActionListener(new Listener());
jbtResume.addActionListener(new Listener());
jbtAdd.addActionListener(new Listener());
jbtSubtract.addActionListener(new Listener());
jsbDelay.addAdjustmentListener(new AdjustmentListener()
{
#Override
public void adjustmentValueChanged(AdjustmentEvent e) {
ballPanel.setDelay(jsbDelay.getMaximum() - e.getValue());
}
});
}
class Listener implements ActionListener
{
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == jbtSuspend)
ballPanel.suspend();
else if (e.getSource() == jbtResume)
ballPanel.resume();
else if (e.getSource() == jbtAdd)
ballPanel.add();
else if (e.getSource() == jbtSubtract)
ballPanel.subtract();
}
}
}
class BallPanel extends JPanel
{
private int delay = 10;
private ArrayList<Ball> list = new ArrayList<Ball>();
// Create a timer with the initial dalay
protected Timer timer = new Timer(delay, new ActionListener() {
#Override /** Handle the action event */
public void actionPerformed(ActionEvent e)
{
repaint();
}
});
public BallPanel()
{
timer.start();
}
public void add()
{
list.add(new Ball());
}
public void subtract()
{
if (list.size() > 0)
list.remove(list.size() - 1); // Remove the last ball
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
for (int i = 0; i < list.size(); i++)
{
Ball ball = (Ball)list.get(i); // Get a ball
g.setColor(ball.color); // Set ball color
// Check boundaries
if (ball.x < 0 || ball.x > getWidth())
ball.dx = -ball.dx;
if (ball.y < 0 || ball.y > getHeight())
ball.dy = -ball.dy;
// Adjust ball position
ball.x += ball.dx;
ball.y += ball.dy;
g.fillOval(ball.x - ball.radius, ball.y - ball.radius,
ball.radius * 2, ball.radius * 2);
}
}
public void suspend()
{
timer.stop();
}
public void resume()
{
timer.start();
}
public void setDelay(int delay)
{
this.delay = delay;
timer.setDelay(delay);
}
}
class Ball
{
int x = 0;
int y = 0; // Current ball position
int dx = 10; // Increment on ball's x-coordinate
int dy = 10; // Increment on ball's y-coordinate
int radius = 5; // Ball radius
Color color = new Color((int)(Math.random() * 256),
(int)(Math.random() * 256), (int)(Math.random() * 256));
}
/** Main method */
public static void main(String[] args)
{
JFrame frame = new JFrame();
JApplet applet = new MultipleBallApp();
frame.add(applet);
frame.setTitle("MultipleBallApp");
frame.setLocationRelativeTo(null); // Center the frame
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 200);
frame.setLocationRelativeTo(null); // Center the frame
frame.setVisible(true);
}
}
Make sure you do not get 0 as a radius when trying to randomize the ball's radius.
int radius = (int)(4*Math.random()+1);