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!
-
Maybe this 2 links help you: https://github.com/libgdx/libgdx/pull/294 and http://code.google.com/p/libgdx/issues/detail?id=188. I stil don'T know if pause is now fired on desktop when window is loosing focus or not. Hope it helps – Robert P Feb 04 '14 at 13:35
-
Hey thanks for the links. It seems pause and resume are not fired when the window looses focus from dragging. However minimize/maximize do seem to work. – Arbel Feb 12 '14 at 04:46
-
But are there really problems with the keyevents? IF you press a key, while you are dragging the window, shouldn'T the keyPress be fired when you stop draging? Just a little idea how you could solve that: The delta time should be verry big, if you drag the window right? So if you drag the window arround for 5 sec delta is 5 sec right? If that is so you could say: `if(delta >= 1) pauseGame()`. Maybe instead of 1 sec use 1.5 or something like that. I don't think that delta gets this value while playing normal :P – Robert P Feb 12 '14 at 07:00
-
Key down/up wont fire while dragging the window. If I hold down say W to move my character and then drag the window and release the key, I wont get a key up event. I feel like the delta solution might not be the best way to solve it because its a bit arbitrary. Ideally Id like to capture the event so I can cancel all input. Im thinking this might be some type of Windows event. – Arbel Feb 12 '14 at 12:50
-
Yea i know it is not a real clean solution... Just an idea. Does the mousPressed event gets fired? If so you could look for the mouse coordinates and if they are outside the window (if it is possible to get coordinates from outside) you could pause the game. Just another idea. – Robert P Feb 12 '14 at 12:59
1 Answers
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()
while moving the window around will still return true, even though the display is no longer updated.
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);
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.
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);
}
}
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);
}
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).
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.
EDIT
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);
}

- 8,623
- 4
- 39
- 61
-
Ill check this out after work and then mark you for the credit. Thanks for the detailed answer. – Arbel Feb 13 '14 at 01:20
-
That does indeed seem to capture the events! Thank you. I had a further question if you don't mind. In my DesktopGame java file I added the code to test this but how would I combine it with my class that extends Game? What Im doing now is something like this: `new LwjglApplication( new MainGame(), "Game", 800, 600, true );` – Arbel Feb 15 '14 at 09:29
-
1I added an example how you could directly add your Game as a ComponentListener. In your case you should also create an LwjglApplicationConfiguration and use it as an argument when creating the LwjglFrame. Something like this: `LwjglApplicationConfiguration cfg = new LwjglApplicationConfiguration(); cfg.useGL20=true; cfg.width=800; cfg.height=600; cfg.title = "Game";` – Balder Feb 15 '14 at 09:52
-
Excellent! Thank you so much for the help and taking the time to write out the code. Got it implemented and working with my game nicely :) – Arbel Feb 16 '14 at 15:47