Я пытаюсь создать игру на Swing, я знаю, что могу использовать другие инструменты, но это только для целей обучения. Проблема, с которой я сталкиваюсь, связана с темами.
По сути, основной поток запускает свойство setVisible JFrame (класс Window) до того, как в JPanel (класс GamePanel) будет сделано любое рисование. После того, как я провел некоторое исследование, я обнаружил, что могу решить эту проблему, используя метод SwingUtilities.invokeLater()
, который должен дать игровому потоку некоторое время для подготовки рисунков, сделанных на JPanel.
Я также пытался поместить свойство setVisible (true)
в другой поток и заставил этот поток спать в течение 2, 3 секунд. Оба эти метода работают иногда, а иногда нет.
Я не знаю, если это имеет значение, но моя операционная система: macOS Catalina.
Тривиальный пример, который вызывает эту проблему потока .
GameLauncher
public class GameLauncher {
public GameLauncher(){
new Window("MyGame");
}
public static void main(String[] args) {
new GameLauncher();
}
}
Окно
public class Window extends JFrame {
public Window(String title){
setTitle(title);
setContentPane(new GamePanel(1280, 1280));
setLocationRelativeTo(null);
setIgnoreRepaint(true);
pack();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// setVisible(true);
SwingUtilities.invokeLater(()->setVisible(true));
}
}
GamePanel
package com.progresso.games;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
public class GamePanel extends JPanel implements Runnable {
public int width;
public int height;
private BufferedImage bufferedImage;
private Thread gameThread;
private boolean isRunning = false;
Graphics2D graphics2D = null;
public GamePanel(int width, int height){
this.width = width;
this.height = height;
setPreferredSize(new Dimension(width, height));
setFocusable(true);
requestFocus();
}
@Override
public void addNotify() {
super.addNotify();
if(gameThread == null){
gameThread = new Thread(this, "GameThread");
gameThread.start();
}
}
private void init(){
isRunning = true;
bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
graphics2D = (Graphics2D) bufferedImage.getGraphics();
}
@Override
public void run() {
init();
while (isRunning) {
update();
render(graphics2D);
draw();
}
}
private void update(){ }
private void render(Graphics2D g){
if(g != null){
g.setColor(Color.BLACK);
g.fillRect(0,0, width, height);
}
}
private void draw(){ }
}