拖动窗口时未调用 Libgdx 暂停/恢复 (Windows)
我正在使用 libgdx 创建一个 Java 游戏.到目前为止真的很喜欢这个引擎,但我在拖动游戏窗口时发现了一个问题.渲染似乎停止了(没关系),但我找不到在此状态下调用的任何事件.有什么办法可以诱捕它吗?当我限制 deltaTime 时,渲染并不是什么大问题,但是对于输入,不会触发 keyUp 事件,这会弄乱我的播放器移动代码(如果您要在拖动窗口时释放键).有什么我可以做的吗?谢谢!
I am creating a Java game with libgdx. Really liking the engine so far but I noticed an issue when dragging the game window. Rendering seems to stop (which is okay) but I cant find any events that get called during this state. Is there any way I can trap it? It not a big deal for rendering as I cap the deltaTime, but for input the keyUp events don't get fired which messes up my movement code for the player (if you are to release the keys while dragging the window). Is there anything I can do? Thanks!
推荐答案
你描述的问题在于LWJGL的原生窗口实现Display:这个轻量级窗口在移动时不会失去焦点.因此调用
The problem you describe lies in the native window implementation of the LWJGL Display: This lightweight window does not loose focus while it is being moved around. Therefore calling
Display.isActive()
在移动窗口时仍会返回 true,即使显示不再更新.
while moving the window around will still return true, even though the display is no longer updated.
我找到了一种适用于我自己的项目的解决方法.可以将父 Canvas 添加到 LWJGL调用显示
I have found a workaround for this problem that works for my own project. One can add a parent Canvas to the LWJGL Display by calling
Display.setParent(canvas);
使用这种方法,可以通过监听父类来监听窗口事件.向显示添加父画布也是,LwjglApplet 可以,因此可以在小程序中运行 libgdx 应用程序.
With this approach one is able to listen to window events by listening to the parent class. Adding a parent canvas to the display is also, what LwjglApplet does, so one is able to run libgdx applications inside an applet.
我编写了一个 LwjglFrame 类,它基本上遵循与 LwjglApplet 相同的方法,不同之处在于将画布添加到 JFrame:
I have written an LwjglFrame class, that does essentially follow the same approach as LwjglApplet, with the difference, that the canvas is added to a 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 并在框架移动时暂停游戏:
With this class, one is able to run libgdx inside a JFrame and then listen for ComponentEvents. Here is some example code for how to create an LwjglFrame and pause the game, whenever the frame is moved around:
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 原生框架时除外).
The downside of this approach is, that one needs some dedicated pause state, that gets entered once the window is moved. This pause state must then be manually exited by the user to continue the game. The upside is, that even if one does not pause the game, the screen will at least get updated, while one is moving the window (other than when using the lwjgl native frame).
我还没有找到可靠的方法,仅在窗口移动时暂停游戏,并在移动完成后自动继续循环.这里的问题是,JFrame 不会发送移动框架的开/关事件,而是在窗口移动时不断通知移动事件.
I have not yet found a reliable way, to pause the game only during movements of the window, and automatically continue the loop once the movement is finished. The problem here is, that JFrame is not sending on/off events for moving the frame, but instead continuously notifies movement events while a window gets moved around.
编辑
你也可以让你的 com.badlogic.gdx.Game 实现 ComponentListener:
You could also make your com.badlogic.gdx.Game implement 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) {}
}
然后你像这样创建你的游戏:
Then you create your Game like this:
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);
}
相关文章