I noticed if I use GDXs Timer class on a default, newly created LibGDX project it will not fire at all while the application is minimized or not in focus.
At least this is true on Desktop deployment Windows 10.
JAVAs own timer class, meanwhile, fires regardless of focus.
A simple example app to demonstrate the difference;
#Override
public void create () {
//gdx timer (does not update when focus lost);
//------------------
com.badlogic.gdx.utils.Timer.schedule(new com.badlogic.gdx.utils.Timer.Task(){
#Override
public void run() {
long currentTime = System.currentTimeMillis();
Log.info("____GDX_____________________:"+currentTime+"_________");
}
}
, 0
, 1.0f );
//java timer (updates when focus lost);
//-----------------
Timer test = new Timer();
test.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
long currentTime = System.currentTimeMillis();
Log.info("___JAVA____________________:"+currentTime+"_________");
}
}, 0, 1000);
}
Running this you can clearly see both logs firing when in focus, and only Javas when not in focus.
My questions are;
a) Is the behavior of LibGDXs timer expected, or have I done something wrong in setup? The description of LibGDXs timer doesn't seem to mention the auto-pause.
b) I wish my application to run in the background unless explicitly paused. Merely,say, alt+tabbing should not be enough.
Should I just switch to using JAVAs timer? Does this have cross-platform implications?
Thanks,
Darkflame
a) Yes, the documentation of TimerThread, which handles Timer, says:
Manages the single timer thread. Stops thread on libgdx application
pause and dispose, starts thread on resume.
b) Since libGDX Timer is nothing special than just a Thread, which listen for application change (pause, resume etc.), with list of tasks, it should be fine to use Java's Timer. Since it is from 1.3 (and the libGDX target is 1.6) it should not have any cross-platform implications.
Related
Here is my Desktop Launcher code:
public class DesktopLauncher {
public static void main (String[] arg) {
Lwjgl3ApplicationConfiguration config = new Lwjgl3ApplicationConfiguration();
config.setForegroundFPS(60);
config.setTitle("Game10");
config.setWindowedMode(1240, 760);
config.forceExit = false; // ERROR!!!
new Lwjgl3Application(new GdxGame10(), config);
}
}
In new LWJGL3 config.forceExit not working. I can't find any solution so far. Any help is appreciated.
There is no forceExit in config. So presumably you have a master application that runs a child libGDX component and when you end that child component you find that the entire application shuts down, when you want the master application to continue. I guess you are on desktop because Android would be OK. So you must want to avoid a full System.exit
i.e.
Gdx.app.exit()
shuts down everything.
So when you instantiate a libGDX application you instantiate based on the application type, so for me, I use the same as you
final Lwjgl3Application application = new Lwjgl3Application(Services.GAME_CONTROLLER,config);
and the implementation for exit is
#Override
public void exit () {
running = false;
}
This finished the while loop that drives the application i.e. kills the main thread. If you have -other threads- running in the background they keep going.
If on the other hand you were instantiating LwglAWTCanvas then your shutdown would be this.
#Override
public void exit () {
postRunnable(new Runnable() {
#Override
public void run () {
stop();
System.exit(-1);
}
});
}
which would shut down the entire application. Anyway so forceExit being -false- was to stop a full system exit killing all your threads. The forceExit was to "force" the other threads to finish. It doesn't do that anymore so the fact it is now missing should not matter, your background threads should keep going.
In other words, config.forceExit = false; is now the default behaviour for your application type so you don't need it.
I am currently working on a basic utility software that has the ability to record Keyboard & Mouse input, save the input to a .txt file, and playback the data on a file. I am revising the program for added file and playback functionality. The problem I'm having is with the Robot.mousePress() method within the mouse movement method:
public static void executeMouseMovementData() {
mouseRobot.mousePress(InputEvent.BUTTON1_MASK);
for (int i=0; i < MouseDataHandler.mouseData.size(); i++) {
mouseRobot.moveMouse(MouseDataHandler.mouseData.get(i).getX(), MouseDataHandler.mouseData.get(i).getY());
mouseRobot.delay(MouseDataHandler.mouseData.get(i).getTimeElapsed());
}
mouseRobot.releaseMouse();
}
This program follows a basic sequence of events: 1 Data initialization, 2 Press mouse, 3 Move mouse, 4 Release mouse. Unlike another method I've successfully implemented, this method does not press the mouse at any time for no obvious reason. Mouse movement works beautifully with the playback feature. I just can't seem to get the Robot to execute any type of mouse event other than movement, even if I restructure the method.
I've tried editing the method to make sure the Robot doesn't press the mouse at the time in which the "playback" button on the GUI is pressed, as to not mess with the focus of the mouse event. The error likely isn't related to other aspects of the code, because everything else in the program runs smoothly. The object "mouseRobot" is an basic extension class of the Java.awt.Robot class with a basic interface for compound Robot mouse methods(), and I even directly call the mousePress method from the Robot class.
What could be the malfunction that occurs with within this method?
Solved. Improved the method in which mouse movements are handled to do one mouse movement per frame. The class can now accurately perform various checks and data changes in between mouse movements, while also allowing other classes to function without being held up from a lengthy for loop. The method in the question was extremely inefficient, impractical and basically acted as a 'while' loop.
public void handleMouseMovements() {
if (shouldAttemptToMoveMouse) {
if (!targetHasBeenReached(currentAdjustedX, currentAdjustedY, targetX, targetY)) {
if (!movementCreated) {
calculateDirection(startX, startY, targetX, targetY);
getLineIndexToUse();
initializeMoveData(repositoryFileIndex, fileIndex);
movementCreated = true;
firstTime = System.currentTimeMillis();
}
if (CMMI >= Main.mouseDataHandler.getSizeOfRepositoryIndex(repositoryFileIndex, fileIndex)){
CMMI =0;
loopMovement();
}
if (movementfileIndexTimeHasElapsed(repositoryFileIndex, fileIndex)) {
moveMouse(repositoryFileIndex, fileIndex);
CMMI++;
firstTime = System.currentTimeMillis();
}
}
else {
resetData();
}
}
}
public void moveMouse(int repositoryFileIndex, int fileIndex) {
currentX = MouseDataHandler.mdr.get(repositoryFileIndex).get(fileIndex).get(CMMI).getX();
currentY = MouseDataHandler.mdr.get(repositoryFileIndex).get(fileIndex).get(CMMI).getY();
currentAdjustedX = currentX + distanceX;
currentAdjustedY = currentY + distanceY;
Main.bot.moveMouse(currentAdjustedX + Main.getX(), currentAdjustedY + Main.getY() + 25);
}
This method is vastly more efficient and handles all criteria necessary to determine direction, determine file index of mouse data to be used, calculates target-file index offsets, and has proper time intervals inbetween mouse movements.
We're providing a library that needs to run code on its own custom threads. Once done, I want these threads to call callbacks (event handlers) through a Dispatcher (System.Windows.Threading.Dispatcher). The library user shall use the Dispatcher to dispatch event handling to.
We could simply always dispatch on CoreApplication.MainView.CoreWindow.Dispatcher but not all programs (e.g. Windows 10 IoT Core apps) provide an UI and thus they lack a main window.
Can the user simply refer to System.Windows.Threading.Dispatcher.CurrentDispatcher to get his thread's Dispatcher? Or can't all threads have a Dispatcher?
Edit: Here's more context for this question. Hopefully it makes the question easier to grasp: https://github.com/getsenic/nuimo-windows/issues/2
For first, I'm not sure, that you should execute event handlers on UI thread, because only client knows if he needed access UI elements.
For second, before invoking CoreApplication.MainView property you can check CoreApplication.Views.Count > 0 (I'm not absolutely sure that it will work because currently I don't have device to test it).
And also you can solve this issue in another way: in constructor of you object save the SynchronizationContext of executing thread and then use it to raise events. It will work if your object instantiates from UI thread (in most cases it's true). That way you can completely refuse from Dispatcher.
public class NotifierExample
{
private readonly SynchronizationContext _synchronizationContext;
public event EventHandler SomethingHappened;
public NotifierExample()
{
_synchronizationContext = SynchronizationContext.Current;
}
public void Do()
{
Task.Factory.StartNew(() =>
{
//do something
OnSomethingHappened();
});
}
private void OnSomethingHappened()
{
if (_synchronizationContext != null)
{
_synchronizationContext.Post(o => RaiseSomethingHappened(), null);
}
else
{
RaiseSomethingHappened();
}
}
private void RaiseSomethingHappened()
{
var somethingHappened = SomethingHappened;
somethingHappened?.Invoke(this, EventArgs.Empty);
}
}
Or can't all threads have a Dispatcher?
Dispatcher threads are always tied to UI threads. IoT headless mode app does not have an UI so it does not have a Dispatcher thread.
Can the user simply refer to System.Windows.Threading.Dispatcher.CurrentDispatcher to get his thread's Dispatcher
System.Windows.Threading.Dispatcher.CurrentDispatcher is only supported in legacy .NET platform. The UWP alternative is CoreApplication.MainView.CoreWindow.Dispatcher as you pointed out.
If you want to to do async callbacks in Headless(without GUI) mode, you can probably refer to Task Parallel Library(TPL), the ContinueWhenAll ContinueWhenAny etc API... might well suits your needs. Refer to https://msdn.microsoft.com/en-us/library/system.threading.tasks.taskfactory.aspx.
The Sound API seems to be missing a function to indicate that a sound is finished playing. Is there some other way of finding out if the sound is done?
Not without submitting a patch to libgdx as far as I know the underlying Sound Backends for both OpenAL and Android don't even track the information internally, though the Music API has an isPlaying() function and getPosition() function as per the documentation.
just set this
sound.setLooping(false);
this way it will not run again and again.
and to check whether sound is playing or
not do this.
make a boolean variable
boolean soundplaying;
in render method do this
if(sound.isPlaying()){
soundplaying =true
}
and make a log
gdx.app.log("","sound"+soundplaying);
You can track this by storing the sound instance id that e.g. play() and loop() return. Example code:
private Sound sound;
private Long soundId;
...
public void startSound() {
if (soundId != null) {
return;
}
soundId = sound.loop(); // or sound.play()
}
public void stopSound() {
sound.stop(soundId);
soundId = null;
}
If you didn't want to have to call stopSound() from client code, you could just call it from startSound() instead of the return, to ensure any previous sound is stopped.
I have a client-server application and i am using swing in the client side. My swing client has one main window (jframe) and lots of panels, toolbars and menubar in it.
I want to remove all client action/mouse events (or simply grab and do nothing) while client is waiting response from server by means of glasssPane.
Here is the code i wrote:
private final static MouseAdapter mouseAdapter = new MouseAdapter()
{
public void mouseClicked(MouseEvent e)
{
System.out.println("MouseClicked..!");
}
};
private static Cursor WAIT_CURSOR = Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR);
private static Cursor DEFAULT_CURSOR = Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR);
and
public static void startWaitCursor(JComponent comp)
{
MainWindow root = ((MainWindow) comp.getTopLevelAncestor());
root.getGlassPane().setCursor(WAIT_CURSOR);
root.getGlassPane().addMouseListener(mouseAdapter);
root.getGlassPane().setVisible(true);
}
public static void stopWaitCursor(JComponent comp)
{
MainWindow root = ((MainWindow) comp.getTopLevelAncestor());
root.getGlassPane().setCursor(DEFAULT_CURSOR);
root.getGlassPane().setVisible(false);
}
but i am not able to manage the grab mouse events. Changing cursors at the glassPane is working fine but either i am not able to add mouseAdapter or am not able to make glasssPane become to the top level component.
Any idea?
Thanks.
I realized that my code is working but my problem is threading related. My code was something like:
startWaitCursor();
work(); // server request that takes time
stopWaitCursor();
and changed it to:
startWaitCursor();
SwingUtilities.invokeLater(new Runnable() {
poblic void run() {
try
{
work(); // server request
}
finally
{
stopWaitCursor();
}
by doing this modification i could see the settings i made in the startWaitCursor() method while client is waiting response from the server.
But stil there is a small problem. In startWaitCursor() method i desabled key, mouse and focus events for the glass pane but events are still captured by main frame even glassPane is displayed.
addMouseListener(new MouseAdapter() {});
addMouseMotionListener(new MouseMotionAdapter() {});
addKeyListener(this);
setFocusTraversalKeysEnabled(false);
After server response reached to client and stopWaitCursor() method is invoked the events handled in the main frame.
If i disable the main frame of my application while client is waiting than cursor is not being changed to wait_cursor, if i am not disable the main frame then cursor is being changed but the events are queued.
cheers...
After digging swing threads issues couple of days, i finally found the real answer: SwingWorker
Now my final code is something like,
startWaitCursor();
SwingWorker worker = new SwingWorker() {
public Object doInBackground()
{
doWork(); // time consuming server request
return null;
}
public void done()
{
stopWaitCursor();
}
};
worker.execute();
In startWaitCursor() method i set the glasspane visible (with alpha valued background), display a message to warn the user time consuming job is doing, set the cursor to wait_cursor (hourglass) and consume all the key, mouse events. That is it.
And by using SwingWorker my client is actually responsive (it is working as if no server request is made) but since i display the glasspane and consume all key and mouse events it feels like irresponsive.
What a relief.. SwingWorker rocks...
cheers..