Help with adding a paddle to a JFrame - java

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");

Related

Space Invaders Alien Array Issue - Java

I am developing a space invaders application for a college assignment and I've come into a problem where the aliens change direction one by one as they hit a wall rather than the whole array of objects switching direction when any alien touches the boundary. I hae a feeling it is an issue in my for loop where my move method containing reverseDirection() method acts on each element individually but I do not know how to fix this and any help would be greatly appreciated. Here is my code for you;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.*;
import javax.swing.*;
import java.awt.image.*;
public class InvadersApplication extends JFrame implements Runnable {//, KeyListener {
private static final Dimension WindowSize = new Dimension(800, 600);
private static final int NUMALIENS = 16;
private Alien AliensArray[] = new Alien[NUMALIENS];
private Image alienImage;
private Image playerImage;
private String workingDirectory = "C:\\Users\\brads\\IdeaProjects\\Assignment3\\src\\workingDirectory\\";
private Player playerShip;
private BufferStrategy strategy;
public InvadersApplication() {
System.out.println(System.getProperty("user.dir"));
setDefaultCloseOperation(EXIT_ON_CLOSE);
Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
int x = screenSize.width / 2 - WindowSize.width / 2;
int y = screenSize.height / 2 - WindowSize.height / 2;
setBounds(x, y, WindowSize.width, WindowSize.height);
this.setTitle("Alien Invaders App");
ImageIcon playerIcon = new ImageIcon(workingDirectory + "player_ship.png");
playerImage = playerIcon.getImage();
ImageIcon alienIcon = new ImageIcon(workingDirectory + "alien_ship_1.png");
alienImage = alienIcon.getImage();
playerShip = new Player(playerImage);
// addKeyListener(this);
setVisible(true);
createBufferStrategy(2);
strategy = getBufferStrategy();
for (int i = 0; i < NUMALIENS; i++) {
AliensArray[i] = new Alien(alienImage);
AliensArray[i].setPosition(70 * (i%4), 70 * (i/4));
AliensArray[i].setXspeed(1);
}
Thread thread1 = new Thread(this);
thread1.start();
repaint();
}
#Override
public void run(){
while(true){
try{
for(int i = 0; i < NUMALIENS; i++) {
AliensArray[i].move();
}
repaint();
Thread.sleep(5);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/* public void keyPressed(KeyEvent e) {
int KeyCode = e.getKeyCode();
if (KeyCode == KeyEvent.VK_LEFT) {
playerShip.movePlayer(-8);
} else if (KeyCode == KeyEvent.VK_RIGHT) {
playerShip.movePlayer(8);
}
}
*/
public void keyReleased(KeyEvent e){
}
public void keyTyped(KeyEvent e){}
public void paint(Graphics g){
g = strategy.getDrawGraphics();
g.setColor(Color.BLACK);
g.fillRect(0,0,800,600);
for(int i=0; i < NUMALIENS; i++){
AliensArray[i].paint(g);
}
// playerShip.paint(g);
//playerShip.paintPlayer(g);
strategy.show();
this.repaint();
}
public static void main(String[] args){
InvadersApplication x = new InvadersApplication();
}
}
Sprite2D class;
public class Sprite2D{
protected int x = 0,y = 30;
protected Image myImage;
public Sprite2D(Image myImage){
this.x = x;
this.y = y;
this.myImage = myImage;
}
public void setPosition(int xx, int yy){
x = xx;
y = yy;
}
public void paint(Graphics g){
g.drawImage(myImage, x,y, null);
}
}
Alien subclass of sprite2D;
import java.awt.*;
import java.util.Random;
import javax.swing.*;
public class Alien extends Sprite2D {
private int xi;
private int xj;
public Alien(Image myImage) {
super(myImage);
this.myImage = myImage;
this.x = x;
this.y = y;
this.xi = xi;
this.xj = xj;
}
// #Override
// public void setPosition(int xx, int yy){
// xx = x;
// yy = y;
//
// }
public void move() {
y+=xj;
x+= xi;
if(x >= 750) {
reverseDirection();
x = x + xi;
}
else if (x < 0)
{
reverseDirection();
x = x + xi;
}
}
public void setXspeed(int xi) {
this.xi = xi;
}
public void setYspeed(int xj) {
this.xj = xj;
}
public void reverseDirection() {
xi = -xi;
System.out.println("reverse");
}
// #Override
// public void paint(Graphics g) {
//
//
// g.drawImage(myImage, xx, yy, null);
// }
}

Swing threading vs timers in my program Java

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);
}
}
}

Animate a Java Line drawing using a timer

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.

JFrame add only one class

I'am making a game, and my JFrame add only one class, i don't getting error, but one of two classes dosen't show. I am try to make JFrame frame 2 = new JFrame();, but nothing.
Game.java:
import java.awt.Component;
import javax.swing.JFrame;
public class Game{
private static final int WIDTH = 800;
private static final int HEIGHT = 600;
private static final String TITLE = "Game Dev [ Week #1 ]";
public static void main(String[] args){
JFrame frame = new JFrame();
Player player = new Player();
Rabbit rabbit = new Rabbit();
// Draw on the map
player.setPlayer(250,250);
rabbit.setRabbit(200,200);
// Draw on the map
frame.add(player);
frame.add(rabbit); // Add only this
// Window
frame.setVisible(true);
frame.setSize(WIDTH,HEIGHT);
frame.setTitle(TITLE);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Player.java:
public class Player extends JPanel implements ActionListener, KeyListener{
// Varibles
Timer time = new Timer(5, this);
static int x; double velX = 0;
static int y; double velY = 0;
private BufferedImage player;
boolean W = false;
boolean A = false;
boolean S = false;
boolean D = false;
public void setPlayer(int x, int y){
this.x = x;
this.y = y;
}
public Player(){
time.start();
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
try {
player = ImageIO.read(getClass().getResourceAsStream("/Player.png"));
} catch (IOException e){
e.printStackTrace();
}
}
// Draw player
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(player, (int)x, (int)y, 100, 100, null);
}
// Set the start up position of player
public void actionPerformed(ActionEvent e){
x += velX;
y += velY;
repaint();
}
// Functions for keyEvent
public void keyPressed(KeyEvent e){
int key = e.getKeyCode();
if(key == KeyEvent.VK_W) // UP
velY = -0.5;
if(key == KeyEvent.VK_A) // LEFT
velX = -0.5;
if(key == KeyEvent.VK_S) // DOWN
velY = 1.5;
if(key == KeyEvent.VK_D) // RIGHT
velX = 1.5;
}
public void keyTyped(KeyEvent e){}
// IF any key released
public void keyReleased(KeyEvent arg0) {
velX = 0;
velY = 0;
W = false;
A = false;
S = false;
D = false;
}
}
Rabbit.java:
public class Rabbit extends JPanel implements ActionListener{
static int x; double velX = 0;
static int y; double velY = 0;
BufferedImage rabbit;
public void setRabbit(int x, int y){
this.x = x;
this.y = y;
}
public Rabbit(){
try {
rabbit = ImageIO.read(getClass().getResourceAsStream("/Rabbit.png"));
} catch (IOException e){
e.printStackTrace();
}
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(rabbit, (int)x, (int)y, 100, 100, null);
}
public void actionPerformed(ActionEvent e){
x += velX;
y += velY;
repaint();
}
}
What's happening is that the JFrame is not combining the graphics for Player and Rabbit; rather, it is placing the player as a panel, and then placing the rabbit. So, the player and the rabbit are always separated. What you want is the Player and Rabbit classes NOT to extend JPanel, but to have a method called paint(Graphics). That way, you can make a class called GamePanel that extends JPanel, and create new methods setPlayer(Player) and setRabbit(Rabbit). The GamePanel class should look like this:
public class GamePanel extends JPanel {
Player player;
Rabbit rabbit;
public void setPlayer(Player player) {
this.player = player;
}
public void setRabbit(Rabbit rabbit) {
this.rabbit = rabbit;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
player.paint(g);
rabbit.paint(g);
}
}
and your Player class should look like this:
public class Player {
public void paint(Graphics g) {
// How to paint the graphics in the player class
}
}
and your Rabbit class should look the same, except as public class Rabbit.
Hope that helps!
EDIT: Full Script
package game;
import java.awt.Graphics;
public interface Displayable {
public void paint(Graphics graphics);
}
package game;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.ImageObserver;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class Rabbit implements Displayable {
private int x, y;
private Image image;
public Rabbit(int x, int y) throws IOException {
this.x = x;
this.y = y;
this.image = ImageIO.read(new File("RABBIT_FILE")); // Replace
// "RABBIT_FILE"
// with the image
// file you have
}
public void paint(Graphics graphics) {
graphics.drawImage(this.image, this.x, this.y, new ImageObserver() {
public boolean imageUpdate(Image img, int infoflags, int x, int y,
int width, int height) {
return false;
}
});
/**
* Optional: JDK 8 only:
*
* graphics.drawImage(this.image, this.x, this.y, (Image img, int
* infoflags, int x0, int y0, int width0, int height0) -> false);
* //Lambda Expression
*/
}
public void setCoordinates(int x, int y) {
this.x = x;
this.y = y;
}
}
package game;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.ImageObserver;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class Player implements Displayable {
private int x, y;
private Image image;
public Player(int x, int y) throws IOException {
this.x = x;
this.y = y;
this.image = ImageIO.read(new File("PLAYER_FILE")); // Replace
// "PLAYER_FILE"
// with the image
// file you have
}
public void paint(Graphics graphics) {
graphics.drawImage(this.image, this.x, this.y, new ImageObserver() {
public boolean imageUpdate(Image img, int infoflags, int x, int y,
int width, int height) {
return false;
}
});
/**
* Optional: JDK 8 only:
*
* graphics.drawImage(this.image, this.x, this.y, (Image img, int
* infoflags, int x0, int y0, int width0, int height0) -> false);
* //Lambda Expression
*/
}
public void setCoordinates(int x, int y) {
this.x = x;
this.y = y;
}
}
package game;
import java.awt.Graphics;
import javax.swing.JPanel;
public final class GamePanel extends JPanel {
private static final long serialVersionUID = -385535147711891740L;
private Player player;
private Rabbit rabbit;
public void setPlayer(Player player) {
this.player = player;
}
public void setRabbit(Rabbit rabbit) {
this.rabbit = rabbit;
}
public GamePanel(Player player, Rabbit rabbit) {
this.setPlayer(player);
this.setRabbit(rabbit);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
this.player.paint(g);
this.rabbit.paint(g);
}
}
package game;
import javax.swing.JFrame;
public final class Main {
public static void main(String... args) {
try {
JFrame frame = new JFrame("Player & Rabbit Game"); // Or whatever
// title
// you have in mind
GamePanel panel = new GamePanel(new Player(0, 0), new Rabbit(0, 0));
frame.add(panel);
frame.setVisible(true);
frame.setDefaultCloseOperation(3);
frame.setExtendedState(6);
} catch (Exception e) {
// Handle Exception if file is corrupted, unable to be read to an
// image, or does not exist
}
}
}

Breakout game, rectagle collision detection

I am trying to make a copy of the breakout game, but I have problems with checking if two objects (the ball and paddle) intersects.
I have this method for collision detection for now:
public static void handleCollisions() {
System.out.println(ball.getBounds()); // just to check that they
System.out.println(paddle.getBounds()); //are there and moving correct
if (ball.getBounds().intersects(paddle.getBounds())) {
System.out.println("collision");
}
}
But even though the rectangles for sure intersect at some points, the method never detects anything. I suppose I have done something wrong with some of the classes.
Here is the main classes:
package assignment1;
import java.awt.*;
import java.awt.event.*;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;
import javax.swing.*;
import javax.swing.plaf.basic.BasicBorders.RadioButtonBorder;
import java.util.Random;
public class Breakout extends TimerTask implements KeyListener {
public static Vector bricks;
public static Ball ball;
public static Paddle paddle;
public static PaintingPanel panel;
public static boolean gameRunning;
public static Breakout game;
public Breakout()
{
}
public static void setupGame()
{
Paddle paddle = new Paddle(350, 790, 100, 10); //initial paddle creation
Ball ball = new Ball(393, 790, 7);
showGUI();
}
public static void beginGame()
{
gameRunning = true;
}
public void run()
{
if(gameRunning == true)
{
Ball.move();
Paddle.move();
handleCollisions();
if(Ball.x < 0 || Ball.x > 800 || Ball.y < 0 || Ball.y > 790){
gameRunning = false;
System.out.println("Game over");
}
}
}
public static void stopGame()
{
}
public static void handleCollisions()
{
System.out.println(ball.getBounds());
System.out.println(paddle.getBounds());
if (ball.getBounds().intersects(paddle.getBounds()))
{
System.out.println("Yay");
}
}
public static void main(String[] args)
{
Timer t = new Timer();
t.schedule(new Breakout(), 0, 40);
panel = new PaintingPanel(PaintingPanel.contents);
setupGame();
beginGame();
while (gameRunning == true)
{
panel.repaint();
}
// TODO a lot
}
private static void showGUI()
{
JFrame frame = new JFrame("Breakout");
game = new Breakout();
frame.addKeyListener(game);
frame.add(panel);
frame.setSize(1000,1000);
frame.setLocationRelativeTo(null); // create game window
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void keyPressed(KeyEvent e) {
Paddle.keyPressed(e);
}
public void keyReleased(KeyEvent e) {
Paddle.keyReleased(e);
}
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
}
package assignment1;
import java.awt.*;
import java.util.Vector;
import javax.swing.*;
public class PaintingPanel extends JPanel{
public static Vector contents;
public PaintingPanel(Vector contents)
{
contents = new Vector();
contents.addElement(Breakout.paddle);
contents.addElement(Breakout.ball);
System.out.println(contents);
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setBackground(Color.GREEN);
g2d.drawRect(2, 2, 800, 800);
Breakout.paddle.paintThis(g2d);
Breakout.ball.paintThis(g2d);
}
}
package assignment1;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
public class Paddle {
public static int PADDLE_SIZE = 100;
public static int PADDLE_THICKNESS = 10;
public static int centreX = 400; // X Centre of the paddle
public static int centreY = 795; // Y Centre of the paddle
public static int paddleX = centreX - (PADDLE_SIZE/2); // Top left X coordinate
public static int paddleY = centreY -(PADDLE_THICKNESS/2); // Top left Y coordinate
public static int dirX;
public Paddle(int paddleX, int paddleY, int PADDLE_SIZE, int PADDLE_THICKNESS)
{
this.paddleX = paddleX;
this.paddleY = paddleY;
this.PADDLE_SIZE = PADDLE_SIZE;
this.PADDLE_THICKNESS = PADDLE_THICKNESS;
System.out.println("Paddle created at " + paddleX + ", " + paddleY + ", " + PADDLE_SIZE + ", " + PADDLE_THICKNESS);
}
public static void paintThis(Graphics g)
{
g.setColor(Color.BLACK);
g.fillRect(paddleX, paddleY, PADDLE_SIZE, PADDLE_THICKNESS);
g.drawRect(paddleX, paddleY, PADDLE_SIZE, PADDLE_THICKNESS);
}
public static Rectangle getBounds()
{
return new Rectangle(paddleX, paddleX, PADDLE_SIZE, PADDLE_THICKNESS);
}
public static void move()
{
paddleX = paddleX + dirX;
}
public static void keyPressed(KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_LEFT)
{
dirX = -10;
}
if (e.getKeyCode() == KeyEvent.VK_RIGHT)
{
dirX = 10;
}
else {}
}
public static void keyReleased(KeyEvent e)
{
dirX = 0;
}
}
package assignment1;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.util.Random;
public class Ball {
public static int x;
public static int y;
public static int radius;
public final static Color colour = Color.RED;
public static double dirX;
public static double dirY;
public static int speed = 0;
public Ball(int x, int y, int radius)
{
this.x = x;
this.y = y;
this.radius = radius;
dirX = 0;
dirY = -Math.sqrt(1 - dirX*dirX);
System.out.println("Ball created at " + x + ", " + y + ", " + dirX + ", " + dirY);
}
public static void paintThis(Graphics g)
{
g.setColor(colour);
int width = radius*2;
g.fillOval(x, y, width, width);
g.drawOval(x, y, width, width);
}
public static Rectangle getBounds()
{
return new Rectangle(x, y, radius*2, radius*2);
}
public static void move()
{
x = (int) (x-dirX*speed); //check for inaccuracy
y = (int) (y-dirY*speed);
System.out.println("Moved, New X = " + x + ", new Y = "+ y);
}
public void reflect(boolean horizontal, boolean vertical)
{
if (vertical == true)
{
dirX = 0-dirX;
}
if (horizontal == true)
{
dirY = 0-dirY;
}
}
public boolean intersects(Paddle paddle) {
if (getBounds().intersects(Paddle.getBounds())){
return true;
}
else return false;
}
}
https://dl.dropboxusercontent.com/u/65678182/assignment1.rar
The getBounds() method in the Paddle class seems to be the problem. You are returning a Rectangle with upper left coordinates of paddleX and paddleX. I think you meant
return new Rectangle(paddleX, paddleY, PADDLE_SIZE, PADDLE_THICKNESS);
instead.

Categories

Resources