Disposing assets and Screens in libgdx - java

I programmed a game made of multiple screens and every time I need a new screen I use the code
dispose();
game.setScreen(new GameScreen(game));
Inside the dispose method I called the dispose method of each asset like Textures and so on.
I also use the asset manager to load the assets required for the game play screen. In that case when I close the game play screen I also call AssetManager.clear().
Now when I start the game I only have the menu screen and the used memory is about 20MB, then in the game play screen I reach 212MB and when I come back to the menu screen, after disposing the AssetManger, I still have 186MB.
The main problem is that if I start a new game play screen the memory reaches 320MB so after some game play screens the game reaches 700MB!
What's wrong with my code?

You should never have to manually call your Game class's dispose() method. It's called automatically upon changing screens or closing the app. Instead, you should override the Game dispose() like this (code taken from a project I'm working on):
#Override
public void dispose()
{
super.dispose();
assets.dispose();
}
The assets object is my AssetManager. Upon closing the app, I want all my loaded textures to be destroyed from memory. I can't promise anything, but I'm pretty sure that's your problem.

Related

Disposing Assets in Libgdx

I am managing my assets using Assets class which has assetManager
In game screens(eg. SplashScreen or MenuScreen) I am loading assets which I will use in this screen using assetManager.load() and when game setScreen to another screen I call dispose() of the previous one ?
Should I call assetManager.clear() in dispose() of screen ?
Or calling it in dispose of my game class (which I use right now) ?
something like this :
public class GameMain extends Game {
#Override
public void dispose(){
super.dispose();
Assets.dispose();
}
}
Sounds like you'll want to call it at the screen level. Calling clear on the asset manager will dispose ALL assets the manager knows about. So each screen will have to load all the assets it needs to use, as the manager is effectively cleared each screen.
If you dispose your assets at the game level like you do now, sounds like you may have a lot of extra assets loaded that you don't need and could affect performance (ie, your menu assets are still loaded when you're showing your play screen) .
If you have assets you share between screens, keep that in mind. Calling clear at the screen level will have you reloading those assets every screen switch - which may be just fine depening on the amount/size of your assets.

libgdx updating scene when app goes invisible

I am using libgdx's render() function to update scene with time delta, and then draw the scene. However, when the app goes invisible, the render() function is no longer being called, which causes the scene to stop updating, E.g., an animation will stuck at the last frame, until app goes back to foreground.
The problem is that I am building an online real-time game which cannot be 'paused' on client. When the app switches to background, the game must keep updating the scene even without drawing the scene, so that when the user switches back to the app, he can see the most up-to-date scene, instead of a pause-and-resume scene that lags back.
My question is how to achieve this in libgdx, so that the scene keeps updating even when app goes background? Does anyone experience the same problem as mine?
In a Libgdx app, the render thread is only invoked when rendering, thus only when it has the screen. For most games this is the only time the game should be doing any computations, so combining the update and render makes a lot of sense.
In Android, an app generally only gets CPU cycles assigned to it by the OS when its "foreground". To run an app in the background requires using a different platform API (See, for example, https://developer.android.com/training/best-background.html.) Simply creating additional threads will not be sufficient to keep your app running in the background (the OS may decide to terminate it completely if it wants the RAM back for something else).
Generally, users do not expect an Android application to continue running (and using battery) when not in the foreground.
Additionally, even if your app is coded to run in the background correctly, when the foreground app is using the CPU significantly, your background app may not be run.
You can hook into the suspend and resume events to pause your game and then "fast-forward" your game state as necessary. Or, do your computations in the cloud if you require that they run in real-time.
You can try to update your scene from other thread if it doesn't need GL context in it.
Or you can override onPause() method in your AndroidApplication class in Android projects, and keep using render() method for updating.
In onPause() method of AndroidApplication graphics are told to stop rendering.
Maybe you can create interface class to update your scene, without constant rendering when the app is paused, concerning the battery life.
This is the code from onPause() method.
Maybe this will lead you to correct solution.
#Override
protected void onPause () {
boolean isContinuous = graphics.isContinuousRendering();
graphics.setContinuousRendering(true);
graphics.pause();
input.onPause();
if (isFinishing()) {
graphics.clearManagedCaches();
graphics.destroy();
}
graphics.setContinuousRendering(isContinuous);
graphics.onPauseGLSurfaceView();
super.onPause();
}

Many events are registered on a single touch in libgdx?

I have a game in which if user touches sound button and that should toggle sound on and off but with every touch many touches are registered. For this reason sound is sometimes off and sometime on.
You are probably using Gdx.input.isTouched();
The problem is that you are using that in your update or render method, and you keep your finger on the screen for more than 1 frame, and the audio changes very fast.
In your show method (or create) use
Gdx.input.setInputProcessor(new InputProcessor(...) );
And in the TouchDown method add your code, because that function is called just once whenever the touch is down, not every frame you are touching your screen.

Prevent LibGDX game from completely stopping when paused

In my LibGDX game for android, if the user backs out of the game (either by pressing the home button or switching to another application) LibGDX's built in pause() method is supposed to run. Now, this is fine, and it works fine as well. My problem is that if I back out of the game to do whatever, and then rejoin the game, it has restarted the app completely (kind of like if every time you exited and rejoined in the middle of a game of Pacman your score would be zero and all the dots would be back). For my screen switching, it is necessary that the game NOT restart every time the user exits, but simply enter the corresponding state to actually simulate the 'paused' game. How do I stop LibGDX/Android from killing the game altogether upon user exit, but simply pausing it?
The libGDX application lifecycle matches the lifecycle of the Android Activity as documented in the ApplicationListener interface so you should expect the same behavior. When you press the home button while in a libGDX game then the pause method will be called, which is the same as onPause in Android. The game will go to the background but will stay in memory. However this is not guaranteed and the OS might release the games memory for other applications, there really is no way to get around this. In the case when the game comes back to the foreground and the game restarts you'll need to load the games state from when it was paused.
I've written my own article on how to save and load the game state using Json in libGDX, maybe that will be useful to you.
You should use Asset Manager to prevent it, here a good tutorial :
http://code.google.com/p/libgdx/wiki/AssetManager
the official doc :
http://code.google.com/p/libgdx/wiki/AssetManager
Load all of your textures with assets manager
I have the same problem, but I found the solution by:
Disable option in Developer options called
- Don't keep activities (Destroy every activity as soon as the user leaves it)

Proper way to dispose screens in Libgdx

What is the proper way of completely disposing of a screen in Libgdx? Currently If I click where a button was on my previous screen the button still does what it would of done if I were on that screen. Should I be .dispose()-ing everything I can in the dispose() method? or is there a simpler way to dispose of everything on screen?
Unfortunately there is no easier way. These classes do not share any kind of common "Disposable" interface, or anything like that, to do it automatically. Everything that has a dispose() method needs to be disposed manually when it's not needed anymore.
This is also valid for the Screens themselves. When switching Screens they do not get disposed automatically, but you need to do that yourself (before calling Game.setScreen()).
On the other hand, this is not a big deal. Just look through everything in your Screen and check whether it has to be disposed or not. If there is a dispose method, call it in dispose() of the Screen.
BUT this does not explain your behaviour about invisible buttons from the last Screen. I suppose you use a Stage and used Gdx.input.setInputProcessor(stage);. This setting will not be changed when you change the screen and you have to set the input processor to the Stage of your current Screen, or to whatever that handles the input in your current Screen. That way the "old" stage will not catch any inputs anymore.
I can confirm that this issue is not passing the inpur processor a new stage. this will result in "ghost" buttons as described.
Unfortunately LibGDX API documentation says
Note that dispose() is not called automatically.
So what I do is disposing all disposables (such as Stage, Skin, Texture ... etc) inside the hide() method in the Screen because hide() is called automatically and it works very well!
example:
public class GameScreen implements Screen {
...
#Override
public void hide() {
mainStage.dispose();
playGroundStage.dispose();
controller.dispose();
labelActor.dispose();
}
...
}

Categories