拖动窗口时未调用Libgdx暂停/恢复(Windows)

时间:2014-02-04 13:07:02

标签: java windows libgdx game-engine

我正在用libgdx创建一个Java游戏。到目前为止真的很喜欢引擎,但我在拖动游戏窗口时发现了一个问题。渲染似乎停止(这是可以的)但我无法找到在此状态期间调用的任何事件。我有什么方法可以捕获它吗?因为我限制了deltaTime,所以渲染并不是什么大问题,但是对于输入,keyUp事件不会被触发,这会扰乱播放器的移动代码(如果要在拖动窗口时释放按键)。有什么我能做的吗?谢谢!

1 个答案:

答案 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);

}