SergeLover
SergeLover

Reputation: 83

Libgdx: how to return to a previous screen

I'm working on a game, and during the initial phase I want the user to be able to switch between two/three screens freely.
From what I've seen online you switch screens by calling the setScreen function on your game instance. The problem is that it seems to work only when you pass a new instance of a screen as the parameter (I tried to pass the whole screen to A a new screen B, but calling myGame.setScreen(A) while on B doesn't do anything), and I'd like to store the changes applied by a user even after he leaves the screen.
I thought about storing these informations in a class that I'll pass as a parameter everytime the user switches screens, but this solution seems inefficient and wrong.
Is there any standard way to return to a previous screen without losing all the changes done to it? Does myGame.setScreen work only on new instances of Screen?

Here's the code I tried to use to return to the old screen :

public class TroopPlacingScreen implements Screen {
private final Game game;
OrthographicCamera camera;
private final GameScreen gameScreen;
private final int XSIZE=1000, YSIZE=500;
private Stage stage;
private long lastClick;
private ImageButton saveAndContinue;

public TroopPlacingScreen(Game game, GameScreen gameScreen){
    this.game=game;
    camera= new OrthographicCamera();
    camera.setToOrtho(false, XSIZE, YSIZE);
    stage= new Stage(new ScreenViewport(), game.batch);
    lastClick= TimeUtils.millis();
    Sprite sprite= new Sprite(new 
         Texture(Gdx.files.internal("saveImage.png")));
    SpriteDrawable spriteDrawable= new SpriteDrawable(sprite);
    saveAndContinue= new ImageButton(spriteDrawable);
    saveAndContinue.setSize(100,100);        
    saveAndContinue.setPosition(Gdx.graphics.getWidth()-250, 
        Gdx.graphics.getHeight()-100);
    stage.addActor(saveAndContinue);
}


@Override
public void show() {

}

@Override
public void render(float delta) {
    ScreenUtils.clear(0, 0, 0, 1);
    camera.update();
    game.batch.setProjectionMatrix(camera.combined);
    game.batch.begin();
    game.batch.end();
    stage.addActor(saveAndContinue);
    if(saveAndContinue.isPressed()){
        game.setFirstTurn(false);
        game.setScreen(gameScreen);
        }
    }
    stage.act();
    stage.draw();
}

@Override
public void resize(int width, int height) {
    stage.getViewport().update(width, height, true);
}

@Override
public void pause() {

}

@Override
public void resume() {

}

@Override
public void hide() {

}

@Override
public void dispose() {

}
}

As I said it was very basic, and to make it work I tried to also call this.dispose(), gameScreen.show(), gameScreen.render(), and all possible permutations of these functions when the saveAndContinue button was pressed, but nothing worked.

Upvotes: 2

Views: 528

Answers (1)

gloccck18
gloccck18

Reputation: 116

According to your code you are passing the gameScreen to constructor but not initializing the class variable. Therefore when calling game.setScreen(gameScreen); you are passing null instead of the actual screen instance.

To make your code work just initialize your class variable in constructor.

this.gameScreen = gameScreen;

In addition, it is better to hold your screen instances in the Game class and have a method there, e.g. setScreen() which will accept enumeration of screens instead of leaking screen instances to each other.

public class MyGame extends Game {

    // Make sure to initialize your screens
    private ScreenA screenA;
    private ScreenB screenB;

    /** ... **/

    public void setScreen(ScreenKey screenKey) {
        switch(screenKey) {
            case ScreenKey.A:
                setScreen(screenA);
                break;
            case ScreenKey.B:
                setScreen(screenB);
                break;
        }
    }

    public enum ScreenKey {A, B}
}

Then in ScreenA you can use the following statement to switch to ScreenB:

game.setScreen(ScreenKey.B)

Instead of switch statement you could also have a map Map<ScreenKey, Screen>.

public class MyGame extends Game {

    // Make sure to initialize your screens
    private Map<ScreenKey, Screen> screens;

    /** ... **/

    public void setScreen(ScreenKey screenKey) {
        setScreen(screens.get(screenKey));
    }

    public enum ScreenKey {A, B}
}

Upvotes: 3

Related Questions