为什么我不能向 JPanel 添加多个对象?
Why I can't add more than one Object to the JPanel?
当我向 GameScreen 添加多个对象时 class Duck 只有一个出现在屏幕上。当我在 GameScreen class 中添加 Duck 外部构造函数时,我有很多 Duck 对象,但是 mouseClicked 方法在 Duck 上不起作用。
看看How to Use BorderLayout。 BorderLayout
将只显示添加到任何单个位置的最后一个组件。
话虽如此,我认为这不是您真正想要进入的方向。相反,从单个 JPanel
开始并覆盖其 paintComponent
方法,然后渲染所有您游戏对象直接通过。组件是非常复杂的重物,通常不适合这种操作。
此外,您也不需要 3 个以上的线程(Swing Timer
使用一个线程来安排对 UI 的调用)。使用单个 Swing Timer
作为您的“主游戏循环”,它应该负责更新状态和安排绘制通道。 Swing 不是线程安全的,因此不建议使用 Thread
更新标签。
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
BufferedImage img = ImageIO.read(getClass().getResource("/images/Duck.png"));
List<Duck> ducks = new ArrayList<>();
ducks.add(new Duck(img));
ducks.add(new Duck(img));
JFrame frame = new JFrame();
frame.add(new GamePane(ducks));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException ex) {
ex.printStackTrace();
}
}
});
}
public class Duck {
private BufferedImage image;
private int x;
private int y;
private int xDelta = 0;
private int yDelta = 0;
public Duck(BufferedImage image) {
this.image = image;
}
public BufferedImage getImage() {
return image;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public void setLocation(int x, int y) {
setX(x);
setY(y);
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public int getWidth() {
return image == null ? 0 : image.getWidth();
}
public int getHeight() {
return image == null ? 0 : image.getHeight();
}
public void setDelta(int x, int y) {
xDelta = x;
yDelta = y;
}
public int getXDelta() {
return xDelta;
}
public int getYDelta() {
return yDelta;
}
public void move(Rectangle bounds) {
int xDelta = getXDelta();
int yDelta = getYDelta();
int x = getX() + xDelta;
int y = getY() + yDelta;
if (x < bounds.x) {
x = bounds.x;
xDelta *= -1;
} else if (x + getWidth() >= bounds.x + bounds.width) {
x = (bounds.x + bounds.width) - getWidth();
xDelta *= -1;
}
if (y < bounds.y) {
y = bounds.y;
yDelta *= -1;
} else if (y + getWidth() >= bounds.y + bounds.height) {
y = (bounds.y + bounds.height) - getHeight();
yDelta *= -1;
}
setDelta(xDelta, yDelta);
setLocation(x, y);
}
public void paint(Graphics2D g2d, ImageObserver observer) {
g2d.drawImage(getImage(), getX(), getY(), observer);
}
}
public class GamePane extends JPanel {
private List<Duck> ducks;
public GamePane(List<Duck> ducks) {
this.ducks = ducks;
Random rnd = new Random();
for (Duck duck : ducks) {
int width = 400 - duck.getWidth();
int height = 400 - duck.getHeight();
int x = rnd.nextInt(width);
int y = rnd.nextInt(height);
int xDelta = rnd.nextBoolean() ? 1 : -1;
int yDelta = rnd.nextBoolean() ? 1 : -1;
duck.setLocation(x, y);
duck.setDelta(xDelta, yDelta);
}
Timer timer = new Timer(5, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Rectangle bounds = new Rectangle(getSize());
for (Duck duck : ducks) {
duck.move(bounds);
}
repaint();
}
});
timer.start();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Duck duck : ducks) {
Graphics2D g2d = (Graphics2D) g.create();
duck.paint(g2d, this);
g2d.dispose();
}
}
}
}
由此,您可以根据需要开始添加更多实体,例如,我可以修改 Main
方法以包含很多鸭子...
BufferedImage img = ImageIO.read(getClass().getResource("/images/Duck.png"));
List<Duck> ducks = new ArrayList<>(100);
for (int index = 0; index < 100; index++) {
ducks.add(new Duck(img));
}
这显然是一个过于简化的示例,仅用于演示核心概念,您需要对基本游戏开发和 2D 图形进行更多研究。
当我向 GameScreen 添加多个对象时 class Duck 只有一个出现在屏幕上。当我在 GameScreen class 中添加 Duck 外部构造函数时,我有很多 Duck 对象,但是 mouseClicked 方法在 Duck 上不起作用。
看看How to Use BorderLayout。 BorderLayout
将只显示添加到任何单个位置的最后一个组件。
话虽如此,我认为这不是您真正想要进入的方向。相反,从单个 JPanel
开始并覆盖其 paintComponent
方法,然后渲染所有您游戏对象直接通过。组件是非常复杂的重物,通常不适合这种操作。
此外,您也不需要 3 个以上的线程(Swing Timer
使用一个线程来安排对 UI 的调用)。使用单个 Swing Timer
作为您的“主游戏循环”,它应该负责更新状态和安排绘制通道。 Swing 不是线程安全的,因此不建议使用 Thread
更新标签。
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
BufferedImage img = ImageIO.read(getClass().getResource("/images/Duck.png"));
List<Duck> ducks = new ArrayList<>();
ducks.add(new Duck(img));
ducks.add(new Duck(img));
JFrame frame = new JFrame();
frame.add(new GamePane(ducks));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (IOException ex) {
ex.printStackTrace();
}
}
});
}
public class Duck {
private BufferedImage image;
private int x;
private int y;
private int xDelta = 0;
private int yDelta = 0;
public Duck(BufferedImage image) {
this.image = image;
}
public BufferedImage getImage() {
return image;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public void setLocation(int x, int y) {
setX(x);
setY(y);
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public int getWidth() {
return image == null ? 0 : image.getWidth();
}
public int getHeight() {
return image == null ? 0 : image.getHeight();
}
public void setDelta(int x, int y) {
xDelta = x;
yDelta = y;
}
public int getXDelta() {
return xDelta;
}
public int getYDelta() {
return yDelta;
}
public void move(Rectangle bounds) {
int xDelta = getXDelta();
int yDelta = getYDelta();
int x = getX() + xDelta;
int y = getY() + yDelta;
if (x < bounds.x) {
x = bounds.x;
xDelta *= -1;
} else if (x + getWidth() >= bounds.x + bounds.width) {
x = (bounds.x + bounds.width) - getWidth();
xDelta *= -1;
}
if (y < bounds.y) {
y = bounds.y;
yDelta *= -1;
} else if (y + getWidth() >= bounds.y + bounds.height) {
y = (bounds.y + bounds.height) - getHeight();
yDelta *= -1;
}
setDelta(xDelta, yDelta);
setLocation(x, y);
}
public void paint(Graphics2D g2d, ImageObserver observer) {
g2d.drawImage(getImage(), getX(), getY(), observer);
}
}
public class GamePane extends JPanel {
private List<Duck> ducks;
public GamePane(List<Duck> ducks) {
this.ducks = ducks;
Random rnd = new Random();
for (Duck duck : ducks) {
int width = 400 - duck.getWidth();
int height = 400 - duck.getHeight();
int x = rnd.nextInt(width);
int y = rnd.nextInt(height);
int xDelta = rnd.nextBoolean() ? 1 : -1;
int yDelta = rnd.nextBoolean() ? 1 : -1;
duck.setLocation(x, y);
duck.setDelta(xDelta, yDelta);
}
Timer timer = new Timer(5, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Rectangle bounds = new Rectangle(getSize());
for (Duck duck : ducks) {
duck.move(bounds);
}
repaint();
}
});
timer.start();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Duck duck : ducks) {
Graphics2D g2d = (Graphics2D) g.create();
duck.paint(g2d, this);
g2d.dispose();
}
}
}
}
由此,您可以根据需要开始添加更多实体,例如,我可以修改 Main
方法以包含很多鸭子...
BufferedImage img = ImageIO.read(getClass().getResource("/images/Duck.png"));
List<Duck> ducks = new ArrayList<>(100);
for (int index = 0; index < 100; index++) {
ducks.add(new Duck(img));
}
这显然是一个过于简化的示例,仅用于演示核心概念,您需要对基本游戏开发和 2D 图形进行更多研究。