I'm looking for some guidance in finishing my program for my project. It is a simple simulation where multiple graphical objects are drawn at runtime and using a button to add another ball in this case to the jpanel, I had to rewrite my whole code to take in multiple objects at once just 2 days ago and last night I did some research when I got an exception...changed some code then got another exception in thread AWT EventQueue 0, after doing some more research many people suggested that dynamically drawing objects on a jpanel at runtime with a thread is a pain in the.... and I should just use a timer instead so this is where I am at right now. The Grid_Bag_Constraints can be ignored for the time being as its just to lay it out at the moment.
My question is how could i make it so a new ball is added at runtime on the press of a button...sorry forgot to mention
Ps yeh i tried playing round with validating the jpanels already :/
All guidance is appreciated :)
Sim
=============
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.*;
public class Sim extends JPanel
private static final int UPDATE_RATE = 60; // Number of refresh per second
public static int X = 640;
public static int Y = 480;
public static int numberOfBall = 3;
public static boolean isRunning = true;
public Sim() {
// have some code here all commented out
}
public static void main(String[] args) {
// Run GUI in the Event Dispatcher Thread (EDT) instead of main thread.
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// Set up main window (using Swing's Frame)
JFrame frame = new JFrame("Simulation");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.gridwidth = 3;
c.gridheight = 3;
balls balls = new balls();
frame.add(balls);
gui GUI = new gui();
frame.add(GUI);
frame.setPreferredSize(new Dimension(1280,720));
frame.setResizable(false);
//frame.setContentPane(new Sim());
frame.pack();
frame.setVisible(true);
new Thread(new bounceEngine(balls)).start();
}
});
}
public static int random(int maxRange) {
return (int) Math.round((Math.random() * maxRange));
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
invalidate();
repaint();
}
gui
---------
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class gui extends JPanel {
boolean shouldFill;
public gui(){
setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
if(shouldFill){
c.fill = GridBagConstraints.HORIZONTAL;
}
AbstractButton addBallButton = new JButton("Add Ball");
addBallButton.setMultiClickThreshhold(1500);
addBallButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent actionEvent) {
balls.listBalls.add(new Ball((new Color(Sim.random(255),Sim.random(255), Sim.random(255))),20));
for(Ball ball : balls.listBalls){
System.out.print("I work ");
}
invalidate();
//repaint();
}
});
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 1;
c.weighty = 0.5;
add(addBallButton);
bounceEngine
------------------
import java.awt.*;
import javax.swing.*;
public class bounceEngine implements Runnable {
private balls parent;
private int UPDATE_RATE = 144;
public bounceEngine(balls parent) {
this.parent = parent;
}
public void run() {
int width = Sim.X;
int height = Sim.Y;
// Randomize the starting position...
for (Ball ball : getParent().getBalls()) {
int x = Sim.random(width);
int y = Sim.random(height);
int size = ball.getRadius();
if (x + size > width) {
x = width - size;
}
if (y + size > height) {
y = height - size;
}
ball.setLocation(new Point(x, y));
}
while (getParent().isVisible()) {
// Repaint the balls pen...
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
getParent().repaint();
}
});
//I know this is dangerous to update it as the repaint method is called
for (Ball ball : getParent().getBalls()) {
move(ball);
}
try{
Thread.sleep(1000/UPDATE_RATE);
}catch (InterruptedException e){
}
}
}
public balls getParent() {
return parent;
}
public void move(Ball ball) {
Point p = ball.getLocation();
Point speed = ball.getSpeed();
int size = ball.getRadius();
int vx = speed.x;
int vy = speed.y;
int x = p.x;
int y = p.y;
if (x + vx < 0 || x + (size*2) + vx > getParent().getWidth()) {
vx *= -1;
}
if (y + vy < 0 || y + (size*2) + vy > getParent().getHeight()) {
vy *= -1;
}
x += vx;
y += vy;
ball.setSpeed(new Point(vx, vy));
ball.setLocation(new Point(x, y));
}
balls(for all the balls)
---------------------------------
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.*;
public class balls extends JPanel {
public static ArrayList<Ball> listBalls;
public balls() {
setPreferredSize(new Dimension(640,480));
setBackground(Color.white);
listBalls = new ArrayList<Ball>(10);
for(int i = 0; i < Sim.numberOfBall; i++){
listBalls.add(new Ball((new Color(Sim.random(255),Sim.random(255), Sim.random(255))),20));
}
}
public ArrayList<Ball> getBall(){
return listBalls;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
for (Ball ball : listBalls) {
ball.paint(g2d);
}
g2d.dispose();
}
public ArrayList<Ball> getBalls(){
return listBalls;
}
Ball(for 1 ball object blank class with basic constructor)
----------------------------------------------------------------------
import java.awt.*;
public class Ball {
private Color color;
private Point location;
private int radius;
private Point speed;
public Ball(Color color, int radius) {
setColor(color);
speed = new Point(5 - Sim.random(20), 5 - Sim.random(20));
this.radius = radius;
}
public int getRadius() {
return radius;
}
public void setColor(Color color) {
this.color = color;
}
public void setLocation(Point location) {
this.location = location;
}
public Color getColor() {
return color;
}
public Point getLocation() {
return location;
}
public Point getSpeed() {
return speed;
}
public void setSpeed(Point speed) {
this.speed = speed;
}
protected void paint(Graphics2D g2d) {
Point p = getLocation();
if (p != null) {
g2d.setColor(getColor());
g2d.fillOval(p.x, p.y, radius*2, radius*2);
}
}
}
Related
So I created a simple simple simulation where squares are spawned randomly with random vectors and bounce of the edges of the window.
I wanted it to take into account the window being resized. So that if I change the dimensions of the window from 600x600 to 1200x600 the squares will bounce of the new border rather than 600x600.
I tried doing getWidth() getHeight() but it would return 0.
So I put it in the pain() (since it gets called on window resize) method and saved the return values as local variables. But I cannot call getjpWidth() from the Rect class.
So basically what I need is to get new window dimension into the move() method in the Rect class.
Please feel free to point out any other mistakes and things that can be done better. I'm new to 2D programming (studying Computer Science)
Application
import javax.swing.*;
public class Application {
private Application(){
//create a JFrame window
JFrame frame = new JFrame("Moving Squares");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//add a JPanel
GamePanel gamePanel = new GamePanel();
frame.add(gamePanel);
//pack the window around the content
frame.pack();
//center
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String args[]){
new Application();
}
}
GamePanel
import java.awt.*;
import java.util.ArrayList;
import javax.swing.*;
public class GamePanel extends JPanel implements Runnable{
private int jpWidth=0, jpHeight=0;
//set JPanel size
private static final Dimension DESIRED_SIZE = new Dimension(600,600);
#Override
public Dimension getPreferredSize(){
return DESIRED_SIZE;
}
//constructor
GamePanel(){
Thread t = new Thread(this);
t.start();
}
private ArrayList <Rect> rect=new ArrayList<>();
public void run(){
for(int i=0; i<15; i++){
rect.add(new Rect());
}
while(true){
for(Rect rect:rect){
rect.move();
}
//repaint still image for better frames
//should be 100fps instead it's >144fps
repaint();
try{Thread.sleep(10);}
catch(InterruptedException e){/**/};
repaint();
try{Thread.sleep(10);}
catch(InterruptedException e){/**/};
repaint();
try{Thread.sleep(10);}
catch(InterruptedException e){/**/};
}
}
public void paint(Graphics g){
Graphics2D g2d = (Graphics2D) g.create();
jpWidth=getWidth();
jpHeight=getHeight();
g2d.setColor(Color.white);
g2d.fillRect(0,0,jpWidth,jpHeight);
for(Rect rect:rect) {
g2d.setColor(Color.black);
g2d.fillRect(rect.getXcord()-1, rect.getYcord()-1, rect.getWidth()+2, rect.getHeight()+2);
g2d.setColor(Color.getHSBColor(rect.getR(), rect.getG(), rect.getB()));
g2d.fillRect(rect.getXcord(), rect.getYcord(), rect.getWidth(), rect.getHeight());
}
}
public int getJpWidth() {
return jpWidth;
}
public int getJpHeight() {
return jpHeight;
}
}
Rect
import java.util.Random;
public class Rect {
//properties
private int width=30, height=30;
private int R, G, B;
//movement
private int xCord, yCord;
private int xVector, yVector;
private int xSlope, ySlope;
public Rect(){
Random rand = new Random();
//random color
R=rand.nextInt(255);
G=rand.nextInt(255);
B=rand.nextInt(255);
//random spawn position
xCord=rand.nextInt(600-width);
yCord=rand.nextInt(600-height);
//direction
do{
xVector=rand.nextInt(3) - 1;
yVector=rand.nextInt(3) - 1;
}while(xVector==0 || yVector==0);
//slope
do{
xSlope=rand.nextInt(3);
ySlope=rand.nextInt(3);
}while(xSlope==0 || ySlope==0);
xVector*=xSlope;
yVector*=ySlope;
}
public void move(){
//if(xCord>=//how to get screen width ? ){}
if((xCord>=600-width) || (xCord<=0)){
bounceX();
}
if((yCord>=600-height) || (yCord<=0)) {
bounceY();
}
xCord+=xVector;
yCord+=yVector;
}
public void bounceX(){
xVector*=-1;
}
public void bounceY(){
yVector*=-1;
}
public int getR() {
return R;
}
public int getG() {
return G;
}
public int getB() {
return B;
}
public int getXcord() {
return xCord;
}
public int getYcord() {
return yCord;
}
public int getWidth(){
return width;
}
public int getHeight(){
return height;
}
}
So basically what I need is to get new window dimension into the move() method in the Rect class.
Don't know if it is the best design but I pass the "panel" as a parameter to the "move()" method so its width/height can be used.
Here is some old code I have lying around that shows this approach:
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
import javax.swing.*;
import javax.swing.Timer;
public class BallAnimation4
{
private static void createAndShowUI()
{
BallPanel panel = new BallPanel();
JFrame frame = new JFrame("BallAnimation4");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( panel );
frame.pack();
frame.setLocationRelativeTo( null );
//frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setVisible( true );
panel.addBalls(5);
panel.startAnimation();
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
class BallPanel extends JPanel implements ActionListener
{
private ArrayList<Ball> balls = new ArrayList<Ball>();
public BallPanel()
{
setLayout( null );
// setBackground( Color.BLACK );
}
public void addBalls(int ballCount)
{
Random random = new Random();
for (int i = 0; i < ballCount; i++)
{
Ball ball = new Ball();
ball.setRandomColor(true);
ball.setLocation(random.nextInt(getWidth()), random.nextInt(getHeight()));
// ball.setMoveRate(32, 32, 1, 1, true);
ball.setMoveRate(16, 16, 1, 1, true);
// ball.setSize(32, 32);
ball.setSize(64, 64);
balls.add( ball );
}
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
for (Ball ball: balls)
{
ball.draw(g);
}
}
#Override
public Dimension getPreferredSize()
{
return new Dimension(800, 600);
}
public void startAnimation()
{
Timer timer = new Timer(1000/60, this);
timer.start();
}
public void actionPerformed(ActionEvent e)
{
move();
repaint();
}
private void move()
{
for (Ball ball : balls)
{
ball.move(this);
}
}
class Ball
{
public Color color = Color.BLACK;
public int x = 0;
public int y = 0;
public int width = 1;
public int height = 1;
private int moveX = 1;
private int moveY = 1;
private int directionX = 1;
private int directionY = 1;
private int xScale = moveX;
private int yScale = moveY;
private boolean randomMove = false;
private boolean randomColor = false;
private Random myRand = null;
public Ball()
{
myRand = new Random();
setRandomColor(randomColor);
}
public void move(JPanel parent)
{
int iRight = parent.getSize().width;
int iBottom = parent.getSize().height;
x += 5 + (xScale * directionX);
y += 5 + (yScale * directionY);
if (x <= 0)
{
x = 0;
directionX *= (-1);
xScale = randomMove ? myRand.nextInt(moveX) : moveX;
if (randomColor) setRandomColor(randomColor);
}
if (x >= iRight - width)
{
x = iRight - width;
directionX *= (-1);
xScale = randomMove ? myRand.nextInt(moveX) : moveX;
if (randomColor) setRandomColor(randomColor);
}
if (y <= 0)
{
y = 0;
directionY *= (-1);
yScale = randomMove ? myRand.nextInt(moveY) : moveY;
if (randomColor) setRandomColor(randomColor);
}
if (y >= iBottom - height)
{
y = iBottom - height;
directionY *= (-1);
yScale = randomMove ? myRand.nextInt(moveY) : moveY;
if (randomColor) setRandomColor(randomColor);
}
}
public void draw(Graphics g)
{
g.setColor(color);
g.fillOval(x, y, width, height);
}
public void setColor(Color c)
{
color = c;
}
public void setLocation(int x, int y)
{
this.x = x;
this.y = y;
}
public void setMoveRate(int xMove, int yMove, int xDir, int yDir, boolean randMove)
{
this.moveX = xMove;
this.moveY = yMove;
directionX = xDir;
directionY = yDir;
randomMove = randMove;
}
public void setRandomColor(boolean randomColor)
{
this.randomColor = randomColor;
switch (myRand.nextInt(3))
{
case 0: color = Color.BLUE;
break;
case 1: color = Color.GREEN;
break;
case 2: color = Color.RED;
break;
default: color = Color.BLACK;
break;
}
}
public void setSize(int width, int height)
{
this.width = width;
this.height = height;
}
}
}
Also, note that for animation you should be using a Swing Timer to schedule the animation. Updates to Swing components should be done on the Event Dispatch Thread (EDT). While not likely to cause a problem with this simple application it is a good habit to make sure this basic rule is followed otherwise you can have random problems and it is never easy to debug a random problem.
I'm generating a hexagon grid and am able to do so but when I add a MouseListener to the individual hexagons (when they're created) it's almost as if they're behind something because hovering/clicking on a hexagon will not register or do anything for that matter. I want to be able to eventually interact with the hexagons but can't do that if I can't get this to work.
My main GUI elements:
import java.awt.*;
import javax.swing.*;
public class Game2
{
public Game2(int radius,int num_hexes)
{
if(num_hexes%2==0) throw new AssertionError("Can't generate map with
an even number of hexagons.");
JFrame frame=new JFrame();
JPanel panel=new JPanel();
panel.setBorder(BorderFactory.createLineBorder(Color.RED));
panel.setLayout(new BoxLayout(panel,1));
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setTitle("HexGame");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setLayout(new BorderLayout());
Rectangle r=frame.getBounds();
int screen_height=r.height;
int screen_width=r.width;
Hexes2 hexes2=new Hexes2(num_hexes,radius,screen_width,screen_height);
panel.add(hexes2);
JScrollPane scroll_pane=new JScrollPane(panel);
frame.getContentPane().add(scroll_pane);
panel.setOpaque(false);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args)
{
Runnable r=new Runnable()
{
#Override
public void run()
{
new Game2(100,11);
}
};
SwingUtilities.invokeLater(r);
}
}
My multiple hexagons:
import java.awt.*;
import java.util.LinkedList;
import java.util.List;
import javax.swing.JPanel;
public class Hexes2 extends JPanel
{
private static final long serialVersionUID=1L;
private static List<Polygon> hexagons;
private static int[] rows;
private int radius;
public Hexes2(int num_columns,int radius,int screen_width,int screen_height)
{
super();
this.radius=radius;
hexagons=new LinkedList<Polygon>();
rows=Functions.columns(num_columns);
int x=screen_width/6;
int y=screen_height/2;
double height=radius*Math.sqrt(3);
double range=num_columns-rows[0];
//build by columns, first
for(int j=0;j<num_columns;j++)
{
x+=((3/2)*radius)*1.5015;
if(j<=Math.floor(num_columns/2)) y=(int) (100-(j*(height/2)));
else y=(int) ((100-(height*(range/2))+(num_columns-rows[j])*(height/2)));
for(int i=0;i<rows[j];i++)
{
y+=height;
Hex2 hex=new Hex2(i,radius,x,y);
hexagons.add(hex.getHex());
}
}
}
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2=(Graphics2D) g;
setOpaque(false);
for(int i=0;i<hexagons.size();i++)
{
Stroke stroke=new BasicStroke(radius/20, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
g2.setStroke(stroke);
g2.setColor(Color.BLACK);
g2.drawPolygon(hexagons.get(i));
}
}
};
My singular hexagon class:
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JLabel;
public class Hex2 extends JLabel implements MouseListener
{
private static final long serialVersionUID = 1L;
private int ID;
private Polygon hexagon;
public Hex2(int ID,int r,int x,int y)
{
super();
this.ID=ID;
hexagon=generateHex(r,x,y);
addMouseListener(this);
}
public Polygon generateHex(int r, int x, int y)
{
Polygon hexagon=new Polygon();
for(int i=0;i<6;i++)
{
/*int _x=(int) (x + r*Math.cos(Math.PI / 3.0 * i));
int _y=(int) (y + r*Math.sin(Math.PI / 3.0 * i));*/
int _x=(int) (x + r*Math.cos(i*2*Math.PI/6));
int _y=(int) (y + r*Math.sin(i*2*Math.PI/6));
hexagon.addPoint(_x,_y);
}
return hexagon;
}
public int getID()
{
return ID;
}
public Polygon getHex()
{
return hexagon;
}
#Override
public void mouseClicked(MouseEvent arg0) {
System.out.println("Clicked on hexagon "+ID);
}
#Override
public void mouseEntered(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mousePressed(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseReleased(MouseEvent arg0) {
// TODO Auto-generated method stub
}
};
Functions:
import java.awt.Dimension;
public class Functions
{
//takes in the max width, n (# hexagons), of the largest row (in the middle)
public static int[] columns(int n)
{
int[] columns=new int[n];
int deviation=(int) java.lang.Math.floor(n/2);
for(int i=0;i<n;i++)
{
columns[i]=n-(java.lang.Math.abs(i-deviation));
}
return columns;
}
public static Dimension getScreenSize()
{
return java.awt.Toolkit.getDefaultToolkit().getScreenSize();
}
}
I apologize for the long code, just wanted to be thorough. Any help greatly appreciated, thanks in advance.
You're adding your MouseListener to your Hex2 JLabels:
public Hex2(int ID, int r, int x, int y) {
super();
this.ID = ID;
hexagon = generateHex(r, x, y);
addMouseListener(this);
}
These are JLabels that you never add to the GUI, since you create them here in line A:
for (int j = 0; j < num_columns; j++) {
x += ((3 / 2) * radius) * 1.5015;
if (j <= Math.floor(num_columns / 2))
y = (int) (100 - (j * (height / 2)));
else
y = (int) ((100 - (height * (range / 2)) + (num_columns - rows[j]) * (height / 2)));
for (int i = 0; i < rows[j]; i++) {
y += height;
Hex2 hex = new Hex2(i, radius, x, y); // ****** [A] *****
hexagons.add(hex.getHex()); // ****** [B] *****
}
}
But hex never is added to the GUI. Instead something else, returned by getHex() is added, so the MouseListener won't work. A MouseListener needs to be added to a component that is visualized within the GUI for its actions to do anything.
I think that you're using too many components here. Only one component, a JPanel, should do all the drawings and should have the MouseLIstener added to it. Everything else should be logical classes that don't extend Swing component classes.
For example, run the code below. It shows that the hex as a non-component class, one that responds to a MouseListener since the listener is added only to the single drawing JLabel. Polygons are shapes and have a contains(Point p) method that can be used inside of the mouse listener to allow them to "know" when they've been pressed:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.Toolkit;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import javax.swing.*;
public class HexPanel extends JPanel {
private static final long serialVersionUID = 1L;
private List<Hex2b> hex2bs = new ArrayList<>();
private int radius;
private int[] rows;
public HexPanel(int num_columns, int radius, int screen_width, int screen_height) {
super();
setBackground(Color.WHITE);
this.radius = radius;
hex2bs = new LinkedList<Hex2b>();
rows = Functions.columns(num_columns);
int x = screen_width / 6;
int y = screen_height / 2;
double height = radius * Math.sqrt(3);
double range = num_columns - rows[0];
// build by columns, first
for (int j = 0; j < num_columns; j++) {
x += ((3 / 2) * radius) * 1.5015;
if (j <= Math.floor(num_columns / 2))
y = (int) (100 - (j * (height / 2)));
else
y = (int) ((100 - (height * (range / 2)) + (num_columns - rows[j]) * (height / 2)));
for (int i = 0; i < rows[j]; i++) {
y += height;
Hex2b hex = new Hex2b(i, radius, x, y);
hex2bs.add(hex);
}
}
addMouseListener(new MyMouse());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // smooth graphics
// setOpaque(false); // doesn't belong in here
for (int i = 0; i < hex2bs.size(); i++) {
Stroke stroke = new BasicStroke(radius / 20, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
Hex2b hex2b = hex2bs.get(i);
Color color = hex2b.getColor();
g2.setColor(color);
g2.fill(hex2b.getHex());
g2.setStroke(stroke);
g2.setColor(Color.BLACK);
g2.draw(hex2b.getHex());
}
}
private class MyMouse extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
for (Hex2b hex2b : hex2bs) {
if (hex2b.getHex().contains(e.getPoint())) {
hex2b.changeColor();
repaint();
break;
}
}
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("Game2b");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Toolkit toolKit = Toolkit.getDefaultToolkit();
Dimension screen = toolKit.getScreenSize();
int width = screen.width;
int height = screen.height;
frame.getContentPane().add(new HexPanel(11, 100, width, height));
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
class Hex2b {
private static final Color INIT_COLOR = Color.white;
private static final Color SELECTED_COLOR = Color.red;
private int ID;
private Polygon hexagon;
private Color color = INIT_COLOR;
public Hex2b(int ID, int r, int x, int y) {
super();
this.ID = ID;
hexagon = generateHex(r, x, y);
}
public Color getColor() {
return color;
}
public void changeColor() {
color = color == INIT_COLOR ? SELECTED_COLOR : INIT_COLOR;
}
public Polygon generateHex(int r, int x, int y) {
Polygon hexagon = new Polygon();
for (int i = 0; i < 6; i++) {
int _x = (int) (x + r * Math.cos(i * 2 * Math.PI / 6));
int _y = (int) (y + r * Math.sin(i * 2 * Math.PI / 6));
hexagon.addPoint(_x, _y);
}
return hexagon;
}
public int getID() {
return ID;
}
public Polygon getHex() {
return hexagon;
}
}
I am trying to draw two circle on a panel with a line joining them, all after a button is pressed. So far (apart from tweaking locations of the line) this is ok. However, I would like to animate it using a timer. The first circle should appear, then gradually the line will be revealed, and finally the second circle.
I have looked at many examples of timers, but I can't seem to get it to work for me. I must be misunderstanding something.
here is the ball class (for each circle):
package twoBalls;
import java.awt.Color;
import java.awt.Point;
public class Ball {
private int x;
private int y;
private int r;
private Color color;
private Point location;
private Ball parent;
public Ball(int x, int y, int r) {
this.x = x;
this.y = y;
this.r = r;
Point p = new Point(x, y);
setLocation(p);
}
public void setParent(Ball b) {
parent = b;
}
public Ball getParent() {
return parent;
}
public void setx(int x) {
this.x = x;
}
public void sety(int y) {
this.y = y;
}
public int getx() {
return x;
}
public int gety() {
return y;
}
public int getr() {
return r;
}
public void setPreferedSize() {
}
public void setLocation(Point p) {
setx(p.x);
sety(p.y);
location = p;
}
public Point getLocation() {
return location;
}
public void setColor(Color color) {
this.color = color;
}
public Color getColor() {
return color;
}
}
then the class that will store balls in an arrayList. And I think that this is where the actual drawing should take place, along with the timer.
I am trying to set the start and end point of the line to be the same, and increment the end point until it is where it should be, using the timer. I'm probably way of track, but that was the intention!
I have change this class, the if statements in the while loop can now be entered, as I am now comparing different point. But the line doesn't get drawn at all still.
package twoBalls;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.util.ArrayList;
import javax.swing.JPanel;
import javax.swing.Timer;
public class BallsArray extends JPanel implements ActionListener {
private ArrayList<Ball> balls;
private Timer timer;
private final int DELAY = 25;
private int xDest;
private int yDest;
private Point dest;
private Point starts;
private int xStart;
private int yStart;
public BallsArray() {
balls = new ArrayList<Ball>();
timer = new Timer(DELAY, this);
yDest = 0;
xDest = 0;
dest = new Point(xDest, yDest);
starts = new Point(xStart, yStart);
}
public void setDestXY(int x, int y) {
xDest = x;
yDest = y;
dest = new Point(xDest, yDest);
setDest(dest);
}
public void setDest(Point p) {
dest = p;
}
public Point getDest() {
return dest;
}
public void setStartsXY(int x, int y) {
xStart = x;
yStart = y;
starts = new Point(xStart, yStart);
setStarts(starts);
}
public void setStarts(Point p) {
starts = p;
}
public Point getStarts() {
return starts;
}
public void addBall(Ball b) {
balls.add(b);
}
public void addBall(int x, int y, int r) {
balls.add(new Ball(x, y, r));
}
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
for (int i = 0; i < balls.size(); i++) {
if (i == 0) {
paintBall(balls.get(0), g2);
}
if (i != 0) {
int j = i - 1;
Ball bp = balls.get(j);
Ball bc = balls.get(i);
bc.setParent(bp);
paintLine(bc, g2);
paintBall(bc, g2);
}
}
}
public void paintBall(Ball b, Graphics2D g2d) {
Ellipse2D circ = new Ellipse2D.Float(b.getx(), b.gety(), b.getr(),
b.getr());
g2d.draw(circ);
}
public void paintLine(Ball b, Graphics2D g2d) {
timer.start();
if (b != null && b.getLocation() != null) {
Ball parent = b.getParent();
if (parent != null) {
g2d.setColor(Color.GRAY);
if (parent.getLocation() != null && b.getLocation() != null) {
setDest(parent.getLocation());
setStarts(parent.getLocation());
g2d.draw(new Line2D.Float(starts, dest));
}
}
}
}
#Override
public void actionPerformed(ActionEvent e) {
// Not sure what I need to do here
// increment second location somehow
// Point s = getStarts();
Point p = getDest();
Point t = this.getLocation();
while (p != t) {
if (p.x != t.x && p.y != t.y) {
System.out.println("hello");
int x = dest.x;
int y = dest.y;
x++;
y++;
setDestXY(x, y);
p = getDest();
repaint();
} else if (p.x == t.x && p.y != t.y) {
System.out.println("part 2");
int y = dest.y;
y++;
setDestXY(dest.x, y);
p = getDest();
repaint();
} else if (p.x != t.x && p.y == t.y) {
System.out.println("part 3");
int x = dest.x;
x++;
setDestXY(x, dest.y);
p = getDest();
repaint();
}
repaint();
}
}
}
I have had a lot of help online getting this far, I worry I am just beyond my depth now!. I am unsure about the EventQueue/run part below. Here is the class to set it all up:
package twoBalls;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
public class Display implements ActionListener {
private JFrame frame;
private JButton button;
private BallsArray b;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
Display ex = new Display();
}
});
}
public Display() {
b = new BallsArray();
frame = new JFrame();
frame.setSize(800, 500);
frame.setTitle("Show balls");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
button = new JButton("New Ball");
frame.add(button, BorderLayout.SOUTH);
frame.setVisible(true);
button.addActionListener(this);
}
#Override
public void actionPerformed(ActionEvent e) {
Ball ball1 = new Ball(100, 100, 50);
b.addBall(ball1);
b.addBall(200, 200, 50);
frame.add(b, BorderLayout.CENTER);
frame.revalidate();
frame.repaint();
}
}
At the moment it draws the two circles, but not the line at all.
When you make an animation, it helps to use the model / view / controller pattern.
Here's the GUI I created from your code.
I simplified your Ball class. This is all you need to define a ball.
package twoBalls;
import java.awt.Color;
import java.awt.Point;
public class Ball {
private final int radius;
private final Color color;
private final Point center;
public Ball(int x, int y, int radius, Color color) {
this(new Point(x, y), radius, color);
}
public Ball(Point center, int radius, Color color) {
this.center = center;
this.radius = radius;
this.color = color;
}
public int getRadius() {
return radius;
}
public Color getColor() {
return color;
}
public Point getCenter() {
return center;
}
}
I created the GUIModel class to hold all of the information your GUI needs. This separates the model from the view.
package twoBalls;
import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
public class GUIModel {
private double direction;
private double distance;
private List<Ball> balls;
private Point lineStartPoint;
private Point lineEndPoint;
public GUIModel() {
this.balls = new ArrayList<>();
}
public void addBall(Ball ball) {
this.balls.add(ball);
}
public List<Ball> getBalls() {
return balls;
}
public void calculatePoints() {
this.lineStartPoint = balls.get(0).getCenter();
this.lineEndPoint = balls.get(1).getCenter();
this.distance = Point.distance(lineStartPoint.x, lineStartPoint.y,
lineEndPoint.x, lineEndPoint.y);
this.direction = Math.atan2(lineEndPoint.y - lineStartPoint.y,
lineEndPoint.x - lineStartPoint.x);
}
public Point getCurrentPoint(int pos, int total) {
double increment = distance / total;
double length = increment * pos;
double x = lineStartPoint.x + Math.cos(direction) * length;
double y = lineStartPoint.y - Math.sin(direction) * length;
x = Math.round(x);
y = Math.round(y);
return new Point((int) x, (int) y);
}
public Point getLineStartPoint() {
return lineStartPoint;
}
}
This class holds the two Ball instances, and calculates the length and direction of the line, divided into total increments.
Now that we've defined the model classes, let's look at the view classes. The first is your Display class.
package twoBalls;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Display implements Runnable {
private GUIModel guiModel;
private JFrame frame;
public static void main(String[] args) {
EventQueue.invokeLater(new Display());
}
public Display() {
this.guiModel = new GUIModel();
Ball ball1 = new Ball(150, 200, 50, Color.BLUE);
Ball ball2 = new Ball(450, 200, 50, Color.GREEN);
guiModel.addBall(ball1);
guiModel.addBall(ball2);
guiModel.calculatePoints();
}
#Override
public void run() {
frame = new JFrame();
frame.setTitle("Show Balls Animation");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
DrawingPanel drawingPanel = new DrawingPanel(guiModel);
panel.add(drawingPanel, BorderLayout.CENTER);
panel.add(createButtonPanel(drawingPanel), BorderLayout.SOUTH);
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
private JPanel createButtonPanel(DrawingPanel drawingPanel) {
JPanel panel = new JPanel();
JButton startButton = new JButton("Start Animation");
startButton.addActionListener(new StartAnimation(drawingPanel));
panel.add(startButton);
return panel;
}
public class StartAnimation implements ActionListener {
private DrawingPanel drawingPanel;
public StartAnimation(DrawingPanel drawingPanel) {
this.drawingPanel = drawingPanel;
}
#Override
public void actionPerformed(ActionEvent event) {
LineRunnable runnable = new LineRunnable(drawingPanel);
new Thread(runnable).start();
}
}
}
The constructor of the Display class sets up the GUI model.
The run method of the Display class constructs the GUI, and starts the animation.
See how I've separated the model and view.
The StartAnimation class is your controller. It starts the animation when you left click on the JButton. I'll discuss the LineRunnable class later.
Next, let's take a look at the DrawingPanel class.
package twoBalls;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import javax.swing.JPanel;
public class DrawingPanel extends JPanel {
private static final long serialVersionUID = -3709678584255542338L;
private boolean drawLine;
private int pos;
private int total;
private GUIModel guiModel;
public DrawingPanel(GUIModel guiModel) {
this.guiModel = guiModel;
this.drawLine = false;
this.setPreferredSize(new Dimension(600, 400));
}
public boolean isDrawLine() {
return drawLine;
}
public void setDrawLine(boolean drawLine) {
this.drawLine = drawLine;
}
public void setPos(int pos) {
this.pos = pos;
repaint();
}
public void setTotal(int total) {
this.total = total;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
for (Ball ball : guiModel.getBalls()) {
g2d.setColor(ball.getColor());
Point center = ball.getCenter();
int radius = ball.getRadius();
g2d.fillOval(center.x - radius, center.y - radius, radius + radius,
radius + radius);
}
if (isDrawLine()) {
g2d.setColor(Color.BLACK);
g2d.setStroke(new BasicStroke(5.0F));
Point a = guiModel.getLineStartPoint();
Point b = guiModel.getCurrentPoint(pos, total);
g2d.drawLine(a.x, a.y, b.x, b.y);
}
}
}
The only thing this view class does is draw the balls and the line. The responsibility for calculating the length of the line belongs in the model.
I set the preferred size here, and use the pack method in the Display class to get the size of the JFrame. You usually want to know the dimensions of the drawing area, rather than the entire window.
Finally, let's look at the LineRunnable class. This is the class that controls the animation.
package twoBalls;
import java.awt.EventQueue;
public class LineRunnable implements Runnable {
private int total;
private DrawingPanel drawingPanel;
public LineRunnable(DrawingPanel drawingPanel) {
this.drawingPanel = drawingPanel;
this.total = 240;
}
#Override
public void run() {
setDrawLine();
for (int pos = 0; pos <= total; pos++) {
setPos(pos);
sleep(50L);
}
}
private void setDrawLine() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
drawingPanel.setDrawLine(true);
drawingPanel.setTotal(total);
}
});
}
private void setPos(final int pos) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
drawingPanel.setPos(pos);
}
});
}
private void sleep(long delay) {
try {
Thread.sleep(delay);
} catch (InterruptedException e) {
}
}
}
In the run method, we divide the line into 240 segments, and draw a segment every 50 milliseconds. It takes the GUI 12 seconds to draw the line. You can play with these numbers if you wish.
The for loop is a classic animation loop. First you update the model, which I'm doing through the drawing panel. Then you sleep.
This animation loop is running on a different thread from the GUI thread. This keeps the GUI responsive. Since the loop is running on a different thread, we have to use the invokeLater method to draw on the Event Dispatch thread.
I hope this was helpful to you. Divide and conquer. Don't let a class do more than one thing.
I am trying to display the two circles moving together on a single frame
through two different classes. But only one is shown moving at a time,even though value of "x" is changing continuously in class child1, paintComponent() is only taking the value of "x1" and showing the circle in moving from class child2.
If two separate frames are assigned to both the classes they works perfectly fine.
Here is my code
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Test13
{
public static void main(String[] args)
{
child1 c1 = new child1();
child2 c2 = new child2();
JFrame f1 = new JFrame("Frame Test1");
f1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//passing a single JFrame to both methods as parameters
c1.cfunc1(f1);
c2.cfunc2(f1); // but this line always hides the upper one
f1.setSize(1000,700);
f1.setVisible(true);
}
}
class child1 extends JPanel implements ActionListener
{
int x,y;
int delay1;
Timer timer1; //timer for 1st class constructor
child1()
{
x=1;
y=100;
timer1 = new Timer(50,this);
}
#Override
public void actionPerformed(ActionEvent e)
{
if(x <= 500)
{
x += 1;
y = 100;
repaint();
}
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.fillOval(x, y, 10, 10);
}
void cfunc1(JFrame f1)//passing JFrame as parameter
{
child1 c1 = new child1();
f1.add(c1);
c1.timer1.start(); //timer started at the end of class1
}
}
class child2 extends JPanel implements ActionListener
{
int x1,y1;
int delay2;
Timer timer2;
child2()
{
x1 = 500;
y1 = 100;
timer2 = new Timer(50,this);//timer for 2nd class constructor
}
#Override
public void actionPerformed(ActionEvent e)
{
if(x1 <= 500)
{
x1 -= 1;
y1 = 100;
repaint();
}
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.fillOval(x1, y1, 10, 10);
}
void cfunc2(JFrame f1)//passing JFrame as parameter
{
child2 c2 = new child2();
f1.add(c2);
c2.timer2.start();//timer started for 2nd class
}
}
When two components are added to a single constraint of a BorderLayout (the default layout for a JFrame), only one is displayed.
The typical way to do this is not to design the custom painting in a JComponent (like JPanel) but instead to have them as simple classes which can paint(Graphics) or draw(Graphics) when requested to do so.
Then extend a single JComponent that iterates a list of the drawable components and paints each one.
Don't create individual classes (child1, child2) for each object. What if you want 50 objects? Instead you create a class that accepts parameters that allows you to customize the object.
This example shows how you might:
create a generic Ball class.
uses a Swing Timer for animation of the balls
create a panel that does custom painting by invoking the draw(...) method of each Ball.
Here is the code:
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
import javax.swing.*;
import javax.swing.Timer;
public class BallAnimation4
{
private static void createAndShowUI()
{
BallPanel panel = new BallPanel();
JFrame frame = new JFrame("BallAnimation4");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( panel );
frame.setSize(800, 600);
frame.setLocationRelativeTo( null );
//frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setVisible( true );
panel.addBalls(5);
panel.startAnimation();
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
class BallPanel extends JPanel implements ActionListener
{
private ArrayList<Ball> balls = new ArrayList<Ball>();
public BallPanel()
{
setLayout( null );
setBackground( Color.BLACK );
}
public void addBalls(int ballCount)
{
Random random = new Random();
for (int i = 0; i < ballCount; i++)
{
Ball ball = new Ball();
ball.setRandomColor(true);
ball.setLocation(random.nextInt(getWidth()), random.nextInt(getHeight()));
ball.setMoveRate(32, 32, 1, 1, true);
// ball.setMoveRate(16, 16, 1, 1, true);
ball.setSize(32, 32);
balls.add( ball );
}
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
for (Ball ball: balls)
{
ball.draw(g);
}
}
public void startAnimation()
{
Timer timer = new Timer(75, this);
timer.start();
}
public void actionPerformed(ActionEvent e)
{
move();
repaint();
}
private void move()
{
for (Ball ball : balls)
{
ball.move(this);
}
}
class Ball
{
public Color color = Color.BLACK;
public int x = 0;
public int y = 0;
public int width = 1;
public int height = 1;
private int moveX = 1;
private int moveY = 1;
private int directionX = 1;
private int directionY = 1;
private int xScale = moveX;
private int yScale = moveY;
private boolean randomMove = false;
private boolean randomColor = false;
private Random myRand = null;
public Ball()
{
myRand = new Random();
setRandomColor(randomColor);
}
public void move(JPanel parent)
{
int iRight = parent.getSize().width;
int iBottom = parent.getSize().height;
x += 5 + (xScale * directionX);
y += 5 + (yScale * directionY);
if (x <= 0)
{
x = 0;
directionX *= (-1);
xScale = randomMove ? myRand.nextInt(moveX) : moveX;
if (randomColor) setRandomColor(randomColor);
}
if (x >= iRight - width)
{
x = iRight - width;
directionX *= (-1);
xScale = randomMove ? myRand.nextInt(moveX) : moveX;
if (randomColor) setRandomColor(randomColor);
}
if (y <= 0)
{
y = 0;
directionY *= (-1);
yScale = randomMove ? myRand.nextInt(moveY) : moveY;
if (randomColor) setRandomColor(randomColor);
}
if (y >= iBottom - height)
{
y = iBottom - height;
directionY *= (-1);
yScale = randomMove ? myRand.nextInt(moveY) : moveY;
if (randomColor) setRandomColor(randomColor);
}
}
public void draw(Graphics g)
{
g.setColor(color);
g.fillOval(x, y, width, height);
}
public void setColor(Color c)
{
color = c;
}
public void setLocation(int x, int y)
{
this.x = x;
this.y = y;
}
public void setMoveRate(int xMove, int yMove, int xDir, int yDir, boolean randMove)
{
this.moveX = xMove;
this.moveY = yMove;
directionX = xDir;
directionY = yDir;
randomMove = randMove;
}
public void setRandomColor(boolean randomColor)
{
this.randomColor = randomColor;
switch (myRand.nextInt(3))
{
case 0: color = Color.BLUE;
break;
case 1: color = Color.GREEN;
break;
case 2: color = Color.RED;
break;
default: color = Color.BLACK;
break;
}
}
public void setSize(int width, int height)
{
this.width = width;
this.height = height;
}
}
}
Normally you wouldn't make the classes static.
This is an excerise i have to complete for a uni course, its not a marked assignment and i could do with a bit of help. I can get the ball to appear on the screen and bounce of the sides, it doesnt matter at the moment if it falls through the bottom of the screen and i can get the paddle to appear on the screen at different times but i cant get them both to appear at the same time. Help please
Here are my classes
MainClass
package movingball;
public class Main
{
public static void main (String []args)
{
MovingBall world = new MovingBall("Moving Ball");
world.setVisible(true);
world.move();
}
}
BallClass
package movingball;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
public class Ball
{
private final int RADIUS = 10;
private Point pos;
private Color ballColour;
private int yChange = 2;
private int xChange = 1;
private int height, width;
private int change;
public Ball (int frameWidth, int frameHeight)
{
change = 3;
ballColour = Color.RED;
width = frameWidth;
height = frameHeight;
pos = new Point();
pos.x = (int)(Math.random() * (width - RADIUS)) + RADIUS;
pos.y = (int)(Math.random() * (height/2 - RADIUS)) + RADIUS;
}
//There are lots of ways you can updateBallState
//Note that the menu bar occupies some of the visible space
public void move()
{
if(pos.y < RADIUS)
{
yChange = - yChange;
}
if(pos.x < RADIUS)
{
xChange = -xChange;
}
if(pos.x > width - RADIUS)
{
xChange = -xChange;
}
if(pos.y < height - RADIUS)
{
pos.translate(xChange, yChange);
}
if(pos.x < width - RADIUS)
{
pos.translate(xChange, yChange);
}
}
public void updateBallState()
{
if (pos.y + change < height - 3*RADIUS)
{
pos.translate(0, change);
// change++; //accelerate
}
}
//This method can be called with a provided graphics context
//to draw the ball in its current state
public void draw(Graphics g)
{
g.setColor(ballColour);
g.fillOval(pos.x - RADIUS, pos.y - RADIUS, 2*RADIUS, 2*RADIUS);
}
public void bounce()
{
yChange = -yChange;
pos.translate(xChange, yChange);
}
public Point getPosition()
{
return pos;
}
}
BallGame
package movingball;
import java.awt.Graphics;
import java.awt.event.*;
public class BallGame extends MovingBall
{
private Paddle myPaddle = new Paddle(FRAME_WIDTH, FRAME_HEIGHT);
public BallGame(String title)
{
super(title);
addKeyListener(new KeyList());
}
public void paint(Graphics g)
{
super.paint(g);
myPaddle.paint(g);
if(isContact())
{
myBall.bounce();
}
else
{
myPaddle.paint(g);
}
}
public boolean isContact()
{
if (myPaddle.area().contains(myBall.getPosition()))
{
return true;
}
else
{
return false;
}
}
public class KeyList extends KeyAdapter
{
public void keyPressed(KeyEvent k)
{
if(k.getKeyCode() == KeyEvent.VK_LEFT)
{
myPaddle.moveLeft();
}
if(k.getKeyCode() == KeyEvent.VK_RIGHT)
{
myPaddle.moveRight();
}
}
}
}
MovingBall class
package movingball;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MovingBall extends JFrame
{
protected final int FRAME_WIDTH = 240;
protected final int FRAME_HEIGHT = 320;
protected Ball myBall = new Ball(FRAME_WIDTH, FRAME_HEIGHT);
public MovingBall (String title)
{
super(title);
setSize(FRAME_WIDTH, FRAME_HEIGHT);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void paint(Graphics g)
{
super.paint(g);
myBall.draw(g);
}
public void move()
{
while(true)
{
myBall.move();
repaint();
try
{
Thread.sleep(50);
}
catch(InterruptedException e)
{
System.exit(0);
}
}
}
}
Paddle class
package movingball;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Paddle
{
private Color paddleColour = Color.GREEN;
private int x,y;
private int paddleWidth = 20;
private int paddleHeight = 10;
private int move = 5;
/** Creates a new instance of Paddle */
public Paddle(int frameWidth, int frameHeight)
{
x =(int)(Math.random()*(frameWidth - paddleWidth));
y = frameHeight - paddleHeight;
}
public void moveRight()
{
x = x + move;
}
public void moveLeft()
{
x = x - move;
}
public Rectangle area()
{
return new Rectangle(x,y, paddleWidth, paddleHeight);
}
public void paint(Graphics g)
{
g.setColor(paddleColour);
g.fillRect(x,y,paddleWidth, paddleHeight);
}
}
Here are a couple of pointers to get you started. I have a lot of things to suggest but I'll just say this to get you further than you are now. You want your JFrame to be double-buffered. That's the first step. To do this, create a new buffer strategy for your JFrame after making it visible:
world.setVisible(true);
world.createBufferStrategy(2);
As for why your Paddle isn't painting? You're going to kick yourself. Look at this line:
MovingBall world = new MovingBall("Moving Ball");
You're not actually creating a BallGame, which is where the logic for painting the paddle is contained! (BallGame.paint()) Try:
BallGame world = new BallGame("Moving Ball");