我正在尝试用Java 8创建一个简单的游戏,但我遇到了Swing线程处理问题。
我已经决定编写自己的游戏循环,但是Swing很难理解我想要达到的目标。
下面,我包括程序的精简版本。只是一些初始化和我的游戏循环。
public class Main extends JFrame {
App app;
public Main () {
createApp ();
add ( app );
pack ();
}
private void createApp () {
app = new App ();
}
public void start () {
setVisible ( true );
SwingUtilities.invokeLater ( new Runnable () {
public void run () {
app.run ();
}
});
}
public static void main ( String [] args ) {
SwingUtilities.invokeLater ( new Runnable () {
public void run () {
Main main = new Main ();
main.start ();
}
});
}
}
public class App extends JPanel {
private boolean _running;
private int _maxFPS = 1;
private int _draw_dt;
public App () {
setFocusable ( true );
requestFocus ();
addKeyListener ( new _KeyAdapter () );
}
public void run () {
/*
* enter the game loop
*/
long nextUpdateTime = System.currentTimeMillis ();
long nextRenderTime = nextUpdateTime;
long lastUpdateTime = nextUpdateTime;
int TPF = 1000 / _maxFPS;
int TPU = 1000 / 60;
_running = false;
while ( _running ) {
/*
* update till the game catches up
*/
while ( nextUpdateTime <= System.currentTimeMillis () ) {
_update ();
lastUpdateTime = nextUpdateTime;
nextUpdateTime += TPU;
}
/*
* draw, if it won't exceed _maxFPS
*/
long currentTime = System.currentTimeMillis ();
if ( nextRenderTime <= currentTime ) {
paintImmediately (0, 0, getWidth (), getHeight ());
nextRenderTime = currentTime + TPF;
_draw_dt = (int) (currentTime - lastUpdateTime);
}
/*
* don't burn cycles unneccessary
*/
long waitTime = Math.min ( nextUpdateTime, nextRenderTime ) - System.currentTimeMillis ();
if ( waitTime > 0 )
try {
Thread.sleep ( waitTime );
} catch ( Exception e ) {
e.printStackTrace ();
}
}
}
private void _update () {
}
public void paintComponent ( Graphics g_ ) {
}
private class _KeyAdapter extends KeyAdapter {
public void keyPressed ( KeyEvent e ) {
System.out.println ( "genetating an event" );
}
}
}
问题是,java忙于运行我的循环(即使Thread.sleep()),以至于它从不处理事件。
如果我关闭游戏循环,它将按预期工作。
我实际上在渲染上也遇到了类似的问题,因此我正在使用renderImmediately()。我实际上正在寻找一种对Java说的方式:“停止!我在这里等待,直到您在每个循环周期内处理所有事件为止,但是到目前为止我还没有运气...
答案 0 :(得分:0)
不确定程序打算做什么(因为_update
方法为空)。
无论如何,App.run
方法当前由摆动线程执行。您不应占用过多的摆动线程(否则,您的窗口不会被重新绘制,事件不会被处理等)。而且此方法永远不会返回,因此摆动线程始终被占用。
作为解决方法,我们可以打破大循环并使用执行程序服务定期运行它:
public class App extends JPanel {
private static final long serialVersionUID = 1L;
public App() {
setFocusable(true);
requestFocus();
addKeyListener(new _KeyAdapter());
}
ScheduledExecutorService es = Executors.newScheduledThreadPool(4);
public void run() {
es.scheduleAtFixedRate(this::appLoop, 100, 100, TimeUnit.MILLISECONDS);
}
private void appLoop() {
/*
* draw, if it won't exceed _maxFPS
*/
paintImmediately(0, 0, getWidth(), getHeight());
}
private void _update() {}
public void paintComponent(Graphics g_) {}
private class _KeyAdapter extends KeyAdapter {
public void keyPressed(KeyEvent e) {
System.out.println("genetating an event");
}
}
}