我正在用libgdx创建一个Java游戏。到目前为止真的很喜欢引擎,但我在拖动游戏窗口时发现了一个问题。渲染似乎停止(这是可以的)但我无法找到在此状态期间调用的任何事件。我有什么方法可以捕获它吗?因为我限制了deltaTime,所以渲染并不是什么大问题,但是对于输入,keyUp事件不会被触发,这会扰乱播放器的移动代码(如果要在拖动窗口时释放按键)。有什么我能做的吗?谢谢!
答案 0 :(得分:5)
您描述的问题在于LWJGL Display的本机窗口实现:这个轻量级窗口在移动时不会失去焦点。因此,请致电
Display.isActive()
虽然显示不再更新,但移动窗口仍然会返回true。
我找到了适用于我自己项目的此问题的解决方法。可以通过调用
将父Canvas添加到LWJGL显示中Display.setParent(canvas);
通过这种方法,人们可以通过监听父类来监听窗口事件。将父画布添加到显示中也是LwjglApplet所做的,因此可以在applet中运行libgdx应用程序。
我编写了一个LwjglFrame类,它基本上遵循与LwjglApplet相同的方法,区别在于画布被添加到JFrame中:
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Dimension;
import javax.swing.JFrame;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
public class LwjglFrame extends JFrame{
private final Canvas canvas;
private LwjglApplication app;
public LwjglFrame(final ApplicationListener listener, final LwjglApplicationConfiguration config) {
canvas = new Canvas(){
public final void addNotify () {
super.addNotify();
app = new LwjglApplication(listener, config, canvas);
}
public final void removeNotify () {
app.stop();
super.removeNotify();
}
};
canvas.setIgnoreRepaint(true);
canvas.setFocusable(true);
setLayout(new BorderLayout());
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
add(canvas, BorderLayout.CENTER);
setPreferredSize(new Dimension(config.width, config.height));
pack();
}
public LwjglFrame(final ApplicationListener listener, final boolean useGL2) {
canvas = new Canvas(){
public final void addNotify () {
super.addNotify();
app = new LwjglApplication(listener, useGL2, canvas);
}
public final void removeNotify () {
app.stop();
super.removeNotify();
}
};
canvas.setIgnoreRepaint(true);
canvas.setFocusable(true);
setLayout(new BorderLayout());
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
add(canvas, BorderLayout.CENTER);
}
}
使用此类,可以在JFrame中运行libgdx,然后侦听ComponentEvents。下面是一些示例代码,用于在框架移动时如何创建LwjglFrame并暂停游戏:
public static void main(String[] args) {
// create the config as usual
final LwjglApplicationConfiguration cfg = createConfig();
// create your ApplicationListener as usual
final ApplicationListener application = createApplication();
// create an LwjglFrame with your configuration and the listener
final LwjglFrame frame = new LwjglFrame(application, cfg);
// add a component listener for when the frame gets moved
frame.addComponentListener(new ComponentAdapter() {
@Override
public void componentMoved(ComponentEvent e) {
// somehow pause your game here
MyGame.getInstance().pauseGame();
}
});
// set the frame visible
frame.setVisible(true);
}
这种方法的缺点是,需要一些专用的暂停状态,一旦窗口移动就会进入。然后,用户必须手动退出该暂停状态以继续游戏。好处是,即使一个人没有暂停游戏,屏幕也会至少得到更新,而一个人正在移动窗口(除了使用lwjgl原生帧时)。
我还没有找到一种可靠的方法,只能在窗口移动期间暂停游戏,并在移动完成后自动继续循环。这里的问题是,JFrame没有发送用于移动帧的开/关事件,而是在窗口移动时连续通知移动事件。
修改强>
你也可以让你的com.badlogic.gdx.Game实现ComponentListener:
public class MayGame extends Game implements ComponentListener{
public void componentResized(ComponentEvent e) {}
public void componentMoved(ComponentEvent e) {
System.out.println("Window moved!");
// pause the game somehow
}
public void componentShown(ComponentEvent e) {}
public void componentHidden(ComponentEvent e) {}
}
然后你就像这样创建你的游戏:
public static void main(String[] args) {
// create the config as usual
final LwjglApplicationConfiguration cfg = createConfig();
// create your Game
final game MyGame = new MyGame();
// create an LwjglFrame with your game and the configuration
final LwjglFrame frame = new LwjglFrame(game, cfg);
// add the game as a component listener
frame.addComponentListener(game);
// set the frame visible
frame.setVisible(true);
}