繁体   English   中英

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

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

所以我在玩 java GUI。 我正在编写一个程序,当球击中 window 的末端时,它会弹起。go 如何更新secondBall以更新并显示其新位置? secondBall.action(); 不起作用。 请参阅以下代码中的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();

    }
}

当尝试为secondBall object 设置动画时,我遇到了错误。

我尝试添加secondBall.action(); 就在ball.action(); actionPerformed方法中。

当尝试为secondBall object 设置动画时,我遇到了错误。

我尝试添加secondBall.action(); 就在ball.action(); actionPerformed方法中。

您应该在问题中发布错误详细信息。

当我运行您的代码(包括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)

constrain()方法(属于 class Ball )的第一行抛出异常,即这一行:

int x0 = box.x;

那是因为box是 null 而它是 null 因为您没有在 class BallPanel的构造函数中为secondBall调用方法setBoundingBox

因此,为了修复您的NullPointerException ,只需将此行添加到BallPanel class 构造函数中:

secondBall.setBoundingBox();

这是带有添加行的代码(由注释表示: 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();
    }
}

请参阅什么是 NullPointerException,我该如何修复它?

...很好,不要忘记修改第二个球的边界区域。

    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