我正在使用 Swing 在 Java 中制作 Brick Breaker 类型的游戏,但我的 J组件都不可见,除非它们是在构造函数中创建的。另一个奇怪的注意事项是,只有在将当前组件添加到面板后立即运行
setVisible()
时,我当前的组件才可见。我怎样才能稍后通过方法添加它们(例如在startGame()
内)?
Main.java
public class Main {
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
BrickBreaker gameInstance = new BrickBreaker();
gameInstance.startGame();
}
});
}
}
BrickBreaker.java
import java.awt.BorderLayout;
import java.awt.Color;
import java.net.URL;
import java.util.ArrayList;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class BrickBreaker {
boolean gameOver = false;
int frameBoundX = 500;
int frameBoundY = 600;
JFrame frame;
JPanel panel;
Ball ball;
Slider slider;
ArrayList<Brick> brickList = new ArrayList<Brick>();
public BrickBreaker() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(frameBoundX, frameBoundY);
frame.setLocationRelativeTo(null);
frame.setResizable(false);
// Add new panel
panel = new JPanel(new BorderLayout());
frame.setContentPane(panel);
// Add slider
slider = new Slider(200, frameBoundY - 100, 100, 30);
panel.add(slider);
frame.setVisible(true);
// Add ball
ball = new Ball(this, frameBoundX, frameBoundY);
panel.add(ball);
frame.setVisible(true);
// Add Bricks
generateBricks();
for (Brick brick : brickList) {
panel.add(brick);
frame.setVisible(true);
}
// Add background
URL backgroundUrl = BrickBreaker.class.getResource("background.jpg");
ImageIcon backgroundIcon = new ImageIcon(backgroundUrl);
JLabel backgroundLabel = new JLabel(backgroundIcon);
backgroundLabel.setBounds(0, 0, backgroundIcon.getIconWidth(),
backgroundIcon.getIconHeight());
panel.add(backgroundLabel);
frame.setVisible(true);
}
public void startGame() {
// Add ball
// ball = new Ball(this, frameBoundX, frameBoundY);
// panel.add(ball);
// setVisible(true);
// panel.repaint();
// panel.revalidate();
slider.start();
ball.start();
}
public void endGame() {
System.out.println("GAME OVER");
// JLabel endSign = new JLabel("MY TEXT HERE");
// endSign.setText("GAME OVER");
// endSign.setBounds(frameBoundX/2, frameBoundY/2, 200, 200);
// endSign.setForeground(Color.white);
// endSign.setVisible(true);
// panel.add(endSign);
// panel.setVisible(true);
// // Repaint the panel
// panel.revalidate();
// panel.repaint();
slider.end();
}
public boolean isGameOver() {
return gameOver;
}
public void generateBricks() {
// Unique starting and iterating numbers are due to the window size
// while also spacing out the bricks evenly
for (int row = 10; row <= 85; row += 35) {
for (int b = 5; b < frameBoundX; b += 99) {
System.out.println("Generating brick #" + b);
Brick brick = new Brick(b, row);
brickList.add(brick);
}
}
}
}
Brick.java(查看组件是如何实现的)
import javax.swing.JComponent;
import java.awt.Rectangle;
import java.awt.Color;
import java.awt.Graphics;
public class Brick extends JComponent {
private int x;
private int y;
private int width = 94;
private int height = 30;
private int health = 1;
public Brick(int startingX, int startingY) {
this.x = startingX;
this.y = startingY;
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.MAGENTA);
g.fillRect(x, y, width, height);
g.dispose();
}
public Rectangle getBounds() {
return new Rectangle(x, y, width, height);
}
public int reduceHealth(){
this.health--;
if (this.health < 1){
System.out.println("Brick has zero health! Disappearing!");
setVisible(false);
}
return this.health;
}
}
如果我尝试在构造函数之外的其他任何地方声明滑块、球或砖块,它们将不会出现在屏幕上。最初,我还通过调用
invokeLater()
使用 EDT 获得了 Main java 文件,但我删除了这种想法,认为这可能是一个问题,但它仍然在发生。
“...除非在构造函数中创建,否则我的 JComponent 都不可见。...仅当我将其添加到面板后立即运行
时才可见。以后如何通过以下方式添加它们方法(例如在setVisible()
内)?...”startGame()
数据模块化。
为每个任务创建一个方法或类。
我建议封装GUI相关数据。
此外,由于 Ball 正在访问 this、frameBoundX 和 frameBoundY,因此只需将 nest 放在该类中即可。
这是一个例子。
class BrickBreaker {
GUI gui;
boolean gameOver = false;
static class GUI extends JFrame {
int frameBoundX, frameBoundY;
JPanel panel;
Ball ball;
Slider slider;
ArrayList<Brick> brickList;
GUI() {
initialize();
// Add new panel
add(panel);
// Add slider
panel.add(slider);
// Add ball
panel.add(ball);
// Add Bricks
for (Brick b : brickList) panel.add(b);
// Add background
URL backgroundUrl = BrickBreaker.class.getResource("background.jpg");
ImageIcon backgroundIcon = new ImageIcon(backgroundUrl);
JLabel backgroundLabel = new JLabel(backgroundIcon);
backgroundLabel.setBounds(0, 0, backgroundIcon.getIconWidth(),
backgroundIcon.getIconHeight());
panel.add(backgroundLabel);
panel.setVisible(true);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(frameBoundX, frameBoundY);
setLocationRelativeTo(null);
setResizable(false);
}
void initialize() {
frameBoundX = 500;
frameBoundY = 600;
panel = new JPanel(new BorderLayout());
ball = new Ball();
slider = new Slider(200, frameBoundY - 100, 100, 30);
generateBricks();
}
public void generateBricks() { ... }
private class Ball extends JComponent {
}
private class Slider extends JComponent {
public Slider(int x, int y, int w, int h) {
}
}
}
public void startGame() { ... }
public void endGame() { ... }
public boolean isGameOver() { ... }
}
SwingUtilities.invokeLater(() -> {
BrickBreaker gameInstance = new BrickBreaker();
gameInstance.gui = new BrickBreaker.GUI();
gameInstance.startGame();
while (!gameInstance.isGameOver()) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
gameInstance.endGame();
});