I have a splash screen and a menu screen class that loads all my texture atlases and skins for the menu and processes lots of stuff. If I put the constructor for the menu screen in the SplashScreen constructor or in the create() method of my main game class (MyGame class) then it would pass a lot of time with no splash screen render image on the phone while the whole stuff loads so I have delayed the loading of the menu class to the second frame render (gets called in the SplashScreen render method in the second frame); I simply check if I passed the first frame then I call a method on the main game class that loads the menus.
It all works fine , as expected , but only if the SplashScreen load process is not interrupted. If I get a call or I simple press the HOME button of the mobile and then I re-enter the game by clicking the icon on the home screen I get an AndroidGraphics error : "waiting for pause synchronization took too long: assuming dead lock and killing"; this is just after I can see the splash screen on the screen for about a second;
I tried to dispose the MyGame in the hide() and pause() methods of both the main game class and the splash screen class so it's terminated if I press the HOME button but they never get called.
How can I fix this? It would be annoying to get a call while loading the game and after you finish the call and try to re-enter the game it crashes.
public class MyGame extends Game{
...
public MainMenu menu;
...
#Override
public void create(){
this.screen_type == SCREEN_TYPE.SPLASH;
splashScreen = new SplashScreen();
setScreen(splashScreen);
}
...
#Override
public void pause(){
//never gets called if I press the HOME button in middle of splash screen
if(this.screen_type == SCREEN_TYPE.SPLASH)
{
this.dispose();
}
}
...
public void LoadMenuTimeConsumingConstructor(){
//load all menus and process data
main_menu = new MainMenu();
loaded_menu = true;
}
}
public class SplashScreen implements InputProcessor, Screen{
public MyGame main_game;
...
public SplashScreen(MyGame game){
this.main_game = game;
}
#Override
public void pause(){
//never gets called if I press the HOME button in middle of splash screen
if(main_game.screen_type == SCREEN_TYPE.SPLASH)
{
main_game.dispose();
}
}
#Override
public void hide(){
//never gets called if I press the HOME button in middle of splash screen
if(main_game.screen_type == SCREEN_TYPE.SPLASH)
{
main_game.dispose();
}
}
#Override
public void render(delta float){
...
//wait 1.5 sec
if(TimeUtils.millis() - startTime > 1500){
{
if(main_game.loaded_menu = true){
main_game.setScreen(main_game.main_menu);
}
}
...
if(is_this_second_frame){ // we start loading menus in the second frame so we already have the splash onscreen
main_game.LoadMenuTimeConsumingConstructor();
}
...
}
}
I do not understand your question very well, but if you are not using AssetManger Class, I think this read can help, I hope so.
If this response is not valid or not useful to you, tell me, and delete
wiki LibGDX
https://github.com/libgdx/libgdx/wiki/Managing-your-assets
video on YouTUBE
https://www.youtube.com/watch?v=JXThbQir2gU
other example in GitHub
https://github.com/Matsemann/libgdx-loading-screen
NEW look this:
Proper way to dispose screens in Libgdx
What's the right place to dispose a libgdx Screen
It can help you decide if you need to call dipose, and how, I hope it will help.
Related
I just want to check that the power button is pressed or not in LibGDX and if it is pressed then exit/close the game or something else like change screen.
I used this code:
#Override
public void render(SpriteBatch sb) {
sb.begin();
if(Gdx.input.isKeyPressed(Input.Keys.POWER)){
Gdx.app.exit();
}
sb.end();
}
but this is not working. After I press the button screen turns off and when I turn it back on the game resumes from exactly where I left it.
I wanted to keep the screen on on power button press but I didn't find any solution on that.
Now I at least want to access the button and then do something on button press.
the same code works for volume up/down button.
Code:
#Override
public void render(SpriteBatch sb) {
sb.begin();
if(Gdx.input.isKeyPressed(Input.Keys.VOLUME_UP)){
Gdx.app.exit();
}
sb.end();
}
Please describe if I'm doing anything wrong and what shall I do.
You can do all saves in pause method that is available in Screen and ApplicationListener classes. It will be called when you exit the app or block device.
#Override
public void pause () {
// save here
}
I have a big problem.I wrote the whole game in same(one) class MyGdxGame extends from the ApplicationAdapter. How do I make the main menu? So that when opening the game, the main menu opens, in which 1 button, when pressed, opens the game itself (MyGdxGame)? Just tell me how to do it (what to create, what to change)
It's better to achieve high cohesion but when you code inside one class, cohesiveness become very low.
Use Screen and Game class to implement more than one screen as in your case like MainScreen, GameScreen, LevelScreen...
But if you don't want to implement that use flags for different screen in your MyGdxGame class.
public enum GameScreen{
MENU_SCREEN, GAME_SCREEN, LEVELSCREEN;
}
In render method of your MyGdxGame
public GameScreen currentScreen=GameScreen.MENU_SCREEN;
#Override
public void render() {
Gdx.gl.glClearColor(1,1,1,1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
if(currentScreen==GameScreen.MENU_SCREEN){
//render objects for Menu Screen
}else if(currentScreen==GameScreen.GAME_SCREEN){
//render objects for Game Screen
}
}
Change value of currentScreen when you want to move on other screen.
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
if(currentScreen==GameScreen.MENU_SCREEN){
//detect button of MenuScreen by bounds or any other way
if(check in bound){
currentScreen==GameScreen.GAME_SCREEN;
}
}else if(currentScreen==GameScreen.GAME_SCREEN){
// for Game Screen
}
return false;
}
EDIT
Pelocho suggested to use abstract method inside enum.
public enum GameScreen{
MENU_SCREEN{
#Override
public void render(MyGdxGame gdxGame) {
}
}, GAME_SCREEN{
#Override
public void render(MyGdxGame gdxGame) {
}
}, LEVELSCREEN{
#Override
public void render(MyGdxGame gdxGame) {
}
};
public abstract void render(MyGdxGame gdxGame);
}
And inside render method of MyGdxGame
#Override
public void render() {
Gdx.gl.glClearColor(1,1,1,1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
currentScreen.render(this);
}
You should do it properly instead of hacking a menu in. If you look at the Screen class it has the about the same methods as the ApplicationAdapter (show, render, resize, dispose, hide, pause, resume). If you would create a new class and have it implement Screen you can start to cut/paste from your main class to this screen class. If you have something in the Create method then either put it in the Show method or in the constructor. You then create another Screen for your main menu, options, credits, etc.
Have you main class MyGdxGame extend from Game instead of ApplicationAdapter delete all methods except the create method. In the create method you can load your assets and call your first screen like this setScreen(new MenuScreen()). For changing screens you have several options.
Pass the Game object allong with the screens so you can do game.setScreen(..)
Have some sort of screen manager with public static methods to change screens.
Gdx.app.getApplicationListener can be casted into game. This way you can change screen from anywhere in your LibGDX app. ((Game)Gdx.app.getApplicationListener).setScreen(myScreen)
If you are feeling scared you will destroy functionality, make a backup of you game in its current state. Abstracting code from big classes to new smaller classes is a important task for each programmer so it will be good practice. If you feel at any point that a certain piece of code should belong to another/new class feel free to do so. There are many ways to do things and keeping your code readable and understandable is your number 1 priority.
I am having a problem with libGDX where when I resume the application after exiting with the back button, I get only a white screen.
The actual app runs, accepts touch input, and plays sounds, but the screen is just white.
I have read that keeping static references to Textures may cause this problem but I am not doing that.
Below is a simplified version of how my asset code works.
public class GdxGame extends Game {
private Assets assets;
#Override
public void onCreate() {
assets = new Asstes();
assets.startLoading();
/*
*Within SplashScreen, GdxGame.getAssets() is accessed, and
*manager.update() is called
*/
setScreen(new SplashScreen());
}
#Override
public void dispose() {
assets.dispose();
assets = null;
}
//Perhaps a problem??
public static Assets getAssets() {
return ((GdxGame) Gdx.app.getApplicationListener()).assets;
}
}
public class Assets implements Disposable{
private AssetManager manager;
public Assets() {
manager = new AssetManager();
}
public void startLoading() {
manager.load(....);
}
#Override
public void dispose() {
manager.dispose();
}
}
Upon returning to the application after the back button is pressed, the AssetManager is recreated, the SplashScreen is reopened (as white), and the AssetManager updates until all assets are reloaded (takes about 2 seconds).
So when the application is reopened, a new AssetManager is loading all of the necessary textures, but for some reason everything is still white.
Could it have something to do with how I access the AssetManager from my UI and Game classes?
//In GdxGame
public Assets getAssets() {
return ((GdxGame) Gdx.app.getApplicationListener()).assets;
}
That is the only place where I could see something going wrong, but even still, I don't understand what could be wrong with that.
Any help would be much appreciated.
Edit:
Here is the SplashScreen class. This makes the issue even more confusing. In the SplashScreen class I load, draw, and dispose a new Texture for the logo. Nothing to do with the AssetManager. Returning after the back button is pressed, this new Texture does not appear either.
public class SplashScreen extends Screen {
private Texture logo;
private Assets assets;
#Override
public void show() {
assets = GdxGame.getAssets();
logo = new Texture(Gdx.files.internal("data/logo.png"));
}
#Override
public void render(float delta) {
super.render(float delta);
if(assets.load()) {
//Switch screens
}
//getBatch() is the same form as getAssets() ((GdxGame) Gdx.app.getApplicationListener()).batch)
GdxGame.getBatch().draw(logo, 100, 100, 250, 250);
}
#Override
public void hide() {
super.hide();
logo.dispose();
}
}
It turns out the issue was to do with how I was managing screens. I had a convenience method in my GdxGame class that allowed me to switch screens based on a ScreenType enum.
Within the enum, I would create a new screen with reflection, given the screen's class in the enum constructor.
The problem is that I stored the screens in the enums, and only created them once. This means that I was keeping and using screens from the old context when I returned after pressing back.
To solve this, I simply had to change it so that a new screen is created every time the enum is accessed, instead of storing one at the start.
im making a quiz for a project and when someone wants to answer the question on a video piece, i need to pause the video and make the screen black so other people can't watch more of the video.
Pausing works perfectly, but is there any way how i can make the screen black? I've tried changing it's brightness but that isn't working.
This is what my run/pause/resume functions look like :
/**
* Run the media player
*/
public void run(){
ourMediaPlayer.getMediaPlayer().playMedia(mediaPath);
}
/**
* Pause the media player
*/
public void pause() {
ourMediaPlayer.getMediaPlayer().pause();
}
public void resume() {
ourMediaPlayer.getMediaPlayer().play();
}
Thanks!
Hello I am working out a game and I wonder how to dispose resources as I am experiencing memory problems.
I have something like this:
public SplashScreen implements Screen {
#Override
public void render(float delta) {
}
#Override
public void dispose() {
if (batch != null)
batch.dispose();
batch = null;
}
}
public MapScreen implements Screen {
#Override
public void render(float delta) {
}
#Override
public void show() {
splashScreenInstance.dispose();
}
#Override
public void dispose() {
if (mesh != null)
mesh.dispose();
mesh = null;
}
}
And I am disposing the splash screen as soon as the show method of MapScreen is called. Previously I'd settled the screen to the MapScree. Still the render method of the splashScreenInstance is called and I'd received null pointer exceptions. Why this is so?
I'd expect that once I set another screen, the previous one is no longer rendered. This is not seemingly so. I'd tried disposing right after setting the screen using the game instance, right after the hide method is called on the screen I want to dispose and finally on the show method of the next screen. All of these cases still renders the previous screen a few times before rendering the current one.
I really need to recover memory and also I don't want to test each time (On the render method) for null pointers as this has performance penalties.
Any suggestions?
Thanks
This is how I usually handle this problem:
public SplashScreen implements Screen {
#Override
public void render(float delta) {
// I assume that you have a reference to the game somewhere to switch the screen
game.setScreen(new MapScreen());
dispose();
return;
}
}
I first set the new Screen, then dispose() the current one and then immediately stop any further execution of the current screen via return. This way the current render cycle should be stopped and in the next cycle the render() of your next screen will be called.
Another approach might be to call dispose() in your hide() method of the Screens, because that is going to be the last method being called before the Game will use the next screen. This is especially useful when there could be several different next screens. In that case there will still be only a single place of dispose() and that will be in the hide() method.
Where are you calling setScreen? Since everything should be happening in the rendering thread (even InputListeners) you should be able to call setScreen in your first Screen and then return from the render method. The Game instance will automatically call hide on your first Screen which is where you can call dispose.