So I'm playing around with java GUI. I'm doing a program that bounces a ball when it hits the end of the window. How do I go about updating the secondBall to update and show its new location? secondBall.action(); does not work. Refer to THIS DOES NOT WORK in the below code.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
// Ball. This class describes the concept of ball. A ball has a position
// (given by a coordinate (x,y)), a velocity (given by a
// differential (dx,dy)) and a color.
class Ball {
// Default constants (for all instances of Ball)
static int defaultDiameter = 10;
static Color defaultColor = Color.yellow;
static Rectangle defaultBox = new Rectangle(0,0,100,100);
// Position
private int x, y;
// Speed and direction
private int dx, dy;
// Diameter (size)
private int diameter;
// Color
private Color color;
// Bounding rectangular area within which the ball bounces
private Rectangle box;
// Construction of new balls requires position and direction
public Ball( int x0, int y0, int dx0, int dy0 ) {
x = x0;
y = y0;
dx = dx0;
dy = dy0;
color = defaultColor;
diameter = defaultDiameter;
}
// Set new color
public void setColor( Color c ) {
color = c;
}
// Set new bounding rectangular area
public void setBoundingBox( Rectangle r ) {
box = r;
}
// Set new diameter
public void setDiameter(int newDiameter) {
diameter = newDiameter;
}
// Draw a ball on given graphic area
public void paint( Graphics g ) {
// Change to the color of the ball
g.setColor( color.WHITE );
// The ball is represented as a filled circle, i.e. an ellipse (oval)
// with equal height and width
g.fillOval( x, y, diameter, diameter );
}
// Constrain the ball within the rectangular area. Update the speed
// if necessary.
void constrain() {
// Give absolute coordinates of the rectangular area
int x0 = box.x;
int y0 = box.y;
int x1 = x0 box.width - diameter;
int y1 = y0 box.height - diameter;
// Change speed and direction if the ball is outside of it
// rectangular area
if (x < x0) {
dx = Math.abs(dx);
}
if (x > x1) {
dx = -Math.abs(dx);
}
if (y < y0) {
dy = Math.abs(dy);
}
if (y > y1) {
dy = -Math.abs(dy);
}
}
// Move the ball with the current direction and speed one step
public void action() {
x = x dx;
y = y dy;
constrain();
}
}
// The BallPanel class defines a drawing surface where the balls are drawn. The
// inherits the JPanel class and implements ActionListener. By
// implement ActionListener you can let a Timer with even
// spaces give a 'tick' when updating the panel should be done.
class BallPanel extends JPanel implements ActionListener {
// Width and height
private int width, height;
// A ball
private Ball ball;
private Ball secondBall;
// Timer. Sends a signal every 50 milliseconds to the panel which
// sent along as ActionListener.
private Timer timer = new Timer(50, this);
// Initialize the attributes
public BallPanel(int width, int height) {
// Find out the width and height of the artboard
this.width = width;
this.height = height;
// Create a new ball
ball = new Ball( width / 10, height / 5, 5, 5 );
secondBall = new Ball( width / 10, height / 5, 5, 5 );
// Set the ball's rectangular bounding box
ball.setBoundingBox( new Rectangle( 0, 0, width, height ) );
// Start the timer.
timer.start();
}
// Update (called on repaint, repaint())
public void paintComponent( Graphics g ) {
// Clear the entire drawing surface (with black color)
g.setColor( Color.black );
g.fillRect( 0, 0, getWidth(), getHeight() );
// Draw the ball (on black background)
ball.paint(g);
ball.setDiameter(15);
secondBall.paint(g);
secondBall.setDiameter(10);
}
// When we get a signal from the timer...
public void actionPerformed(ActionEvent e) {
if(width != getWidth() || height != getHeight())
wasResized();
ball.action();// Do whatever is relevant with the ball
// secondBall.action(); THIS DOES NOT WORK
repaint(); // Automatically make another call
// paintComponent()
}
// Called if window resizes
public void wasResized( ) {
//width = newWidth;
// height = newHeight;
ball.setBoundingBox(new Rectangle(0, 0, getWidth(), getHeight()));
}
}
// This class defines the window created by the program. One
// window (JFrame) is created where an instance of BallPanel (the artboard)
// placed.
public class BallWorld extends JFrame {
// Create a panel
private BallPanel panel = new BallPanel (180, 180);
public BallWorld() {
// Add the ball panel to the center of the frame.
Container c = getContentPane();
c.add(panel, BorderLayout.CENTER);
setSize(200, 200); // Frame size.
setLocation(100, 100); // So that the frame does not end up in a corner.
setVisible(true); // Make the frame visible.
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
// This method is started by the Java virtual machine when java is called
// BallWorld
public static void main(String args[]) {
// This command provides better animation in a part
// Olympics. Comment if the ball moves jerkily.
// System.setProperty("sun.java2d.opengl", "true");
BallWorld world = new BallWorld();
}
}
When trying to animate the secondBall object I just run in to errors.
I tried adding secondBall.action(); right under ball.action(); in the actionPerformed method.
CodePudding user response:
When trying to animate the
secondBallobject I just run in to errors.
I tried adding
secondBall.action();right underball.action();in theactionPerformedmethod.
You should post the error details in your question.
When I ran your code (including the secondBall.action() line) I got:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException: Cannot read field "x" because "this.box" is null
at swingprj/swngtsts.Ball.constrain(BallWorld.java:64)
at swingprj/swngtsts.Ball.action(BallWorld.java:88)
at swingprj/swngtsts.BallPanel.actionPerformed(BallWorld.java:139)
at java.desktop/javax.swing.Timer.fireActionPerformed(Timer.java:311)
at java.desktop/javax.swing.Timer$DoPostEvent.run(Timer.java:243)
at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:771)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:722)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:716)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:741)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
The first line in method constrain() (of class Ball) is throwing the exception, i.e. this line:
int x0 = box.x;
That's because box is null and it is null because you didn't call method setBoundingBox for secondBall in the constructor of class BallPanel.
So in order to fix your NullPointerException, just add this line to BallPanel class constructor:
secondBall.setBoundingBox();
Here is your code with the added line (indicated by the comment: ADDED THIS LINE)
package swngtsts;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
// Ball. This class describes the concept of ball. A ball has a position
// (given by a coordinate (x,y)), a velocity (given by a
// differential (dx,dy)) and a color.
class Ball {
// Default constants (for all instances of Ball)
static int defaultDiameter = 10;
static Color defaultColor = Color.yellow;
static Rectangle defaultBox = new Rectangle(0, 0, 100, 100);
// Position
private int x, y;
// Speed and direction
private int dx, dy;
// Diameter (size)
private int diameter;
// Color
private Color color;
// Bounding rectangular area within which the ball bounces
private Rectangle box;
// Construction of new balls requires position and direction
public Ball(int x0, int y0, int dx0, int dy0) {
x = x0;
y = y0;
dx = dx0;
dy = dy0;
color = defaultColor;
diameter = defaultDiameter;
}
// Set new color
public void setColor(Color c) {
color = c;
}
// Set new bounding rectangular area
public void setBoundingBox(Rectangle r) {
box = r;
}
// Set new diameter
public void setDiameter(int newDiameter) {
diameter = newDiameter;
}
// Draw a ball on given graphic area
public void paint(Graphics g) {
// Change to the color of the ball
g.setColor(color.WHITE);
// The ball is represented as a filled circle, i.e. an ellipse (oval)
// with equal height and width
g.fillOval(x, y, diameter, diameter);
}
// Constrain the ball within the rectangular area. Update the speed
// if necessary.
void constrain() {
// Give absolute coordinates of the rectangular area
int x0 = box.x;
int y0 = box.y;
int x1 = x0 box.width - diameter;
int y1 = y0 box.height - diameter;
// Change speed and direction if the ball is outside of it
// rectangular area
if (x < x0) {
dx = Math.abs(dx);
}
if (x > x1) {
dx = -Math.abs(dx);
}
if (y < y0) {
dy = Math.abs(dy);
}
if (y > y1) {
dy = -Math.abs(dy);
}
}
// Move the ball with the current direction and speed one step
public void action() {
x = x dx;
y = y dy;
constrain();
}
}
// The BallPanel class defines a drawing surface where the balls are drawn. The
// inherits the JPanel class and implements ActionListener. By
// implement ActionListener you can let a Timer with even
// spaces give a 'tick' when updating the panel should be done.
class BallPanel extends JPanel implements ActionListener {
// Width and height
private int width, height;
// A ball
private Ball ball;
private Ball secondBall;
// Timer. Sends a signal every 50 milliseconds to the panel which
// sent along as ActionListener.
private Timer timer = new Timer(50, this);
// Initialize the attributes
public BallPanel(int width, int height) {
// Find out the width and height of the artboard
this.width = width;
this.height = height;
// Create a new ball
ball = new Ball(width / 10, height / 5, 5, 5);
secondBall = new Ball(width / 10, height / 5, 5, 5);
// Set the ball's rectangular bounding box
ball.setBoundingBox(new Rectangle(0, 0, width, height));
secondBall.setBoundingBox(new Rectangle(0, 0, width, height)); // ADDED THIS LINE
// Start the timer.
timer.start();
}
// Update (called on repaint, repaint())
public void paintComponent(Graphics g) {
// Clear the entire drawing surface (with black color)
g.setColor(Color.black);
g.fillRect(0, 0, getWidth(), getHeight());
// Draw the ball (on black background)
ball.paint(g);
ball.setDiameter(15);
secondBall.paint(g);
secondBall.setDiameter(10);
}
// When we get a signal from the timer...
public void actionPerformed(ActionEvent e) {
if (width != getWidth() || height != getHeight())
wasResized();
ball.action();// Do whatever is relevant with the ball
secondBall.action(); //THIS DOES NOT WORK
repaint(); // Automatically make another call
// paintComponent()
}
// Called if window resizes
public void wasResized() {
// width = newWidth;
// height = newHeight;
ball.setBoundingBox(new Rectangle(0, 0, getWidth(), getHeight()));
}
}
// This class defines the window created by the program. One
// window (JFrame) is created where an instance of BallPanel (the artboard)
// placed.
public class BallWorld extends JFrame {
// Create a panel
private BallPanel panel = new BallPanel(180, 180);
public BallWorld() {
// Add the ball panel to the center of the frame.
Container c = getContentPane();
c.add(panel, BorderLayout.CENTER);
setSize(200, 200); // Frame size.
setLocation(100, 100); // So that the frame does not end up in a corner.
setVisible(true); // Make the frame visible.
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
// This method is started by the Java virtual machine when java is called
// BallWorld
public static void main(String args[]) {
// This command provides better animation in a part
// Olympics. Comment if the ball moves jerkily.
// System.setProperty("sun.java2d.opengl", "true");
BallWorld world = new BallWorld();
}
}
Refer to What is a NullPointerException, and how do I fix it?
CodePudding user response:
...nice, and do not forget to modify bounding area for second ball, too.
public void wasResized() {
// width = newWidth;
// height = newHeight;
ball.setBoundingBox(new Rectangle(0, 0, getWidth(), getHeight()));
secondBall.setBoundingBox(new Rectangle(0, 0, getWidth(), getHeight()));
//Adding new bounding to secondball
