Let's say I have a screen A with Skin that was loaded in memory by asset manager:
private Skin skin;
...
skin = (Skin)MyGame.ResourceManager.getAsset(AssetEnum.UISkin);
//UISkin("Menu/UISkin.json", Skin.class),
I need to load the next screen B that also refers to AssetEnum.UISkin. The simple way is
dispose screen A
unload resources of screen A
load resources of screen B
initialize screen B
But I want to show some loading wheel on the screen A while resources of screen B are still loading. With this extension steps look like
load resources of screen B
initialise and set screen B
dispose screen A
unload resources of screen A
The problem is when I call dispose on third step, skin.dispose() removes texture of previous screen that I also need on current. And this situation appears every time when "dispose screen A" is after "load resources of screen B". Does anyone have any suggestions? Please help
You can create a separate static class that loads your assets and keep it until you don't need it anymore.
Lets call this class AssetLoader.
I assume that you know how java works and how libgdx works.
Within the class, AssetLoader, you create 2 methods
Public static void load() {}
and
Public static void dispose() {}
Also declare your skin as a static member
Public static Skin skin;
Within your load() method do the loading of your skin, and within your dispose() method you write your disposal method.
When your want to want to load your assets, call
AssetLoader.load();
the methods are all static you don't need to initialize AssetLoader in your entire code. Just call it.
When you want to use the skin (for example, your Screen1() method)
UISkin("Menu/UISkin.json", AsssetLoader.Skin.class);
Finally when your game ends, you call
Assetoader.dispose();
You can literally put anything in the AssetLoader that is static. Such as textures and soundtracks. The benefit is that you only need to call the load() method once in your entire code and you can use it for the entire duration of your game. Just remember to dispose it when you don't need it anymore.
EDIT: Another thing you can do is to use AssetManager
More details here
Related
In libgdx, screen.setScreen() doesn't call dispose automatically right. Inside a overridden setScreen, do I have to call screen.dispose first and then call super.setScreen or call the later first?
I know this may seem like duplicate question but still I wanted to know because super.setScreen calls screen.hide. Is calling hide after dispose run-time safe?
Is it a bad practice?
I am making a 3D game based on this and this example .
Here I am extending GameName class by Game and trying to override setScreen so as to call dispose if screen is not null and then call super.setScreen .
screen.dispose() is never called by LibGDX. You must do it manually yourself before dropping the reference to your screen. If you don't plan to reuse the Screen instance, having screen.hide() call screen.dispose() is the perfect place to do it.
screen.hide() is never called in response to Android events.
I don't recommend overriding game.setScreen() to dispose of screens unless you know for sure you never want to reuse any screen instances. In most simple games, you do want to reuse them rather than waste time unloading and reloading assets repeatedly.
Two type of disposable assets(SpriteBatch, Texture, Stage, ...), one is shared on different screen and another one is specific for particular screen.
Shared Assets should be disposed from Game's dispose() method.
Screen specific assets should be disposed through dispose() method of Screen but screen's dispose() never called so you need to call it explicitly.
When you change your screen hide() method of Screen called so you should call dispose() method from hide() method.
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.
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.
This is the class that I am initializing via my desktop and android main class. I am actually passing this current instance of Game to GameScreen objects so that I can use its setScreen method to change screens.
public class childGame extends Game {
#Override
public void create() {
setScreen(new AScreen(this));
}
}
And at somepoint at AScreen I am changing Screen to another Screen say BScreen when the button is pressed, I am also using the same trick that I have previously here, and it works fine. but when from BScreen I change setScreen to AScreen, it goes there shows everything correctly but none of the buttons do work.
disposing the screen would solve thiss,
call dispose method when you are switching screens
game.setScreen(new PlayScreen(game));
dispose();
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();
}
...
}