简体   繁体   English

如何为两个独立的球制作动画 Java AWT & Swing

[英]How to animate two separate balls Java AWT & Swing

So I'm playing around with java GUI.所以我在玩 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?我正在编写一个程序,当球击中 window 的末端时,它会弹起。go 如何更新secondBall以更新并显示其新位置? secondBall.action(); does not work.不起作用。 Refer to THIS DOES NOT WORK in the below code.请参阅以下代码中的THIS DOES NOT WORK

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.当尝试为secondBall object 设置动画时,我遇到了错误。

I tried adding secondBall.action();我尝试添加secondBall.action(); right under ball.action();就在ball.action(); in the actionPerformed method.actionPerformed方法中。

When trying to animate the secondBall object I just run in to errors.当尝试为secondBall object 设置动画时,我遇到了错误。

I tried adding secondBall.action();我尝试添加secondBall.action(); right under ball.action();就在ball.action(); in the actionPerformed method.actionPerformed方法中。

You should post the error details in your question.您应该在问题中发布错误详细信息。

When I ran your code (including the secondBall.action() line) I got:当我运行您的代码(包括secondBall.action()行)时,我得到:

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, ie this line: constrain()方法(属于 class Ball )的第一行抛出异常,即这一行:

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 .那是因为box是 null 而它是 null 因为您没有在 class BallPanel的构造函数中为secondBall调用方法setBoundingBox

So in order to fix your NullPointerException , just add this line to BallPanel class constructor:因此,为了修复您的NullPointerException ,只需将此行添加到BallPanel class 构造函数中:

secondBall.setBoundingBox();

Here is your code with the added line (indicated by the comment: ADDED THIS LINE )这是带有添加行的代码(由注释表示: 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?请参阅什么是 NullPointerException,我该如何修复它?

...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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM