0

我只是想为我的 java2d 游戏在 swing 中创建一个多线程渲染器的想法,其中每个线程负责渲染自己的 swingcomponent 并想出了一个简单的程序来尝试并实现这一点。

*我知道 Thread.sleep 不是首选方法,但它在我使用主动渲染的单线程渲染上运行良好,我没有使用 swingtimer 进行测试,但据我所知 Thread.sleep 使调用线程休眠所以这不是问题。

问题)程序在四个线程中创建了四个面板,每个面板都有一个弹跳球,但只有第一个创建的线程会做任何事情,其他线程根本没有启动(可通过运行方法中的 sysout 验证)。所以只有一个线程进行渲染,其他线程永远没有机会运行,sysout:System.out.println("Ballbouncer: " + this + " running.");确认这一点,视觉(添加图像)也是如此。

BallBouncer(可运行)

public class BallBouncer implements Runnable {
private ColoredPanel ballContainer;
private List<Ellipse2D.Double> balls;
public static final Random rnd = new Random();
private double speedX, speedY;

public BallBouncer(ColoredPanel container) {
    this.ballContainer = container;
    this.balls = new ArrayList<>();
    balls.add(container.getBall());
    this.speedX = 10 * rnd.nextDouble() - 5;
    this.speedY = 10 * rnd.nextDouble() - 5;
}

public BallBouncer(List<ColoredPanel> containers) {
    for (ColoredPanel p : containers) {
        new BallBouncer(p).run();
    }
}

@Override
public void run() {
    while (true) {
        System.out.println("Ballbouncer: " + this + " running.");
        moveBall();
        ballContainer.repaint();
        try {
            Thread.sleep(15);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

private void moveBall() {
    for (Ellipse2D.Double ball : balls) {
        ball.x += speedX;
        ball.y += speedY;

        if (ball.x < 0
                || ball.x + ball.getWidth() > ballContainer.getWidth()) {
            speedX *= -1;
        }
        if (ball.y < 0
                || ball.y + ball.getHeight() > ballContainer.getHeight()) {
            speedY *= -1;
        }
    }


}

容器

public class ColoredPanel extends JPanel {
private Ellipse2D.Double circle;

public ColoredPanel(Color color) {
    circle = new Ellipse2D.Double(0, 0, 10, 10);
    setBackground(color);
}

public Ellipse2D.Double getCircle() {
    return circle;
}

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2d = (Graphics2D) g.create();
    g2d.setColor(getBackground().darker());
    g2d.fill(circle);
}

@Override
@Transient
public Dimension getPreferredSize() {
    return new Dimension(400, 400);
}

public Double getBall() {
    return getCircle();
}

主要的

public class ColoredPanelContainer extends JPanel {

private List<ColoredPanel> panels = new ArrayList<>();

public ColoredPanelContainer() {
    setUpPanels();
    setBackground(Color.black);
}

private void setUpPanels() {
    for (int i = 0; i < 4; i++) {
        Color color = new Color(BallBouncer.rnd.nextInt(256),
                BallBouncer.rnd.nextInt(256), BallBouncer.rnd.nextInt(256));
        panels.add(new ColoredPanel(color));
    }
    for (int i = 0; i < 4; i++) {
        add(panels.get(i));
    }
}

@Override
@Transient
public Dimension getPreferredSize() {
    return new Dimension(1000, 1000);
}

public List<ColoredPanel> getPanels() {
    return panels;
}

public static void main(String[] args) {
    JFrame frame = new JFrame();
    ColoredPanelContainer container = new ColoredPanelContainer();
    frame.getContentPane().add(container);
    frame.pack();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);
    new BallBouncer(container.getPanels());
}
}

请注意,球仅在左侧面板中弹跳(第一个开始线程),其他球始终处于静止状态。 在此处输入图像描述

4

1 回答 1

4

你这样做:

public BallBouncer(List<ColoredPanel> containers) {
    for (ColoredPanel p : containers) {
        new BallBouncer(p).run();
    }
}

这不是启动线程的正确方法。您所做的只是run直接顺序地运行该方法。这意味着代码在调用构造函数的同一线程中的该循环中运行。

您应该阅读本教程。 它解释了如何在 Swing 中使用线程。即如何使用javax.swing.SwingWorkerSwingUtilities.invoke*还有这个教程,它解释了如何使用 SwingTimer类。

而且,只是为了进一步了解线程:以下是在不使用 swing 时在 java 中启动线程的方法在编写 Swing 应用程序时,您不想使用这些示例

于 2013-06-04T00:24:18.493 回答