How to manage screens in LibGDX

When making games, it is common that our application has multiple screens or scenes. Below I will show a way to manage the different scenes in libgdx.

For this example, I will supose the game has three screens: the main menu, the seleccion level screen and the game itself. In order to not do this article so large, I will not use auxiliar classes for constants, utilities, etc. The classes we use are shown in below diagram:

LibGDX - Screen Management

Main class of the game

At project creation, the main class is called MyGdxGame by default, and it extends from AplicationListener. LibGDX has a subclass of AplicationListener, the class Game, prepared to show  an implementation of the interface Screen at each time. That we do is to use the class Game as parent of our main class, and each of the screens will be an implementation of Screen.

By this, our main game class will be like this:

54
55
56
public class MyGdxGame extends Game {
...
}

We will go back to this class later.

Game Screens

To work with class Game, each screen of our game has to implement the interface Screen. Furthermore, I work normaly with class Stage. To combine this two elements I use an abstract class, AbstractScreen, that extends Stage class and implements Screen interface. This own class will be the parent class of our screens.

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public abstract class AbstractScreen extends Stage implements Screen {
 
    protected AbstractScreen() {
        super( new StretchViewport(320.0f, 240.0f, new OrthographicCamera()) );
    }
 
    // Subclasses must load actors in this method
    public abstract void buildStage();
 
    @Override
    public void render(float delta) {
        // Clear screen
        Gdx.gl.glClearColor(1, 0, 0, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
 
        // Calling to Stage methods
        super.act(delta);
        super.draw();
    }
 
    @Override
    public void show() {
        Gdx.input.setInputProcessor(this);
    }
 
    @Override
    public void resize(int width, int height) {
        getViewport().update(width, height, true);
    }
 
    @Override public void hide() {}
    @Override public void pause() {}
    @Override public void resume() {}
}

Key issues

  • It uses a Viewport of 320 for width and 240 for height.
  • It declares an abstract method, buildStage(), that will must be implemented by every screen of our game. This method is used to add actors to the scene (LibGDX Scene2d).

We have said that our game will consist of three screens. These will have the following constructors:

  • First screen: Main Menu
    public MainMenuScreen() {...}
  • Second screen: Level Select
    public LevelSelectScreen() {...}
  • Third screen: Game
    Commonly we use the same class for several (or all) levels of our game. To know which is the current level, we have a parameter in the class constructor indicating the level:

    public GameScreen(Integer level) {...}

I will not show the implementation of these classes in order to not do this article so long with code that is not related with the main target of this post. In any case, at the end of this article you can see the link to download the source code used in this example.

 

ScreenEnum: list of available screens

In order to know the available scenes, we create an Enum java type, called ScreenEnum, with the list of possible screens. This enum defines an abstract method getScreen() that allow us to get an screen instance of each enum type.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public enum ScreenEnum {
 
    MAIN_MENU {
        public AbstractScreen getScreen(Object... params) {
            return new MainMenuScreen();
        }
    },
    LEVEL_SELECT {
        public AbstractScreen getScreen(Object... params) {
            return new LevelSelectScreen();
        }
    },
    GAME {
        public AbstractScreen getScreen(Object... params) {
            return new GameScreen((Integer) params[0]);
        }
    };
 
    publicabstract AbstractScreen getScreen(Object... params);
}

Key issues

  • The enum defines an abstract method (getScreen()) for get an instance of each screen from its enum type. This method supports one variable argument (Object... params); this allow to pass params to the screen constructors when it is needed.
  • Constructor of classes MainMenuScreen and LevelSelectScreen don’t need parameters.
  • GameScreen, in change, need an argument of type Integer. So, for instantiate this screen we make casting to Integer from the first element of the array Object... params.

Usage

If we want to obtain, for example, the screen of main menu we can do this:

AbstractScreen mainMenuScreen = ScreenEnum.MAIN_MENU.getScreen();

 

Scenes manager

The class ScreenManager is the responsible of screens management. This class, in combination with ScreenEnum, will allow us to change the visible screen in a really easy way:

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public class ScreenManager {
 
    // Singleton: unique instance
    private static ScreenManager instance;
 
    // Reference to game
    private Game game;
 
    // Singleton: private constructor
    private ScreenManager() {
        super();
    }
 
    // Singleton: retrieve instance
    public static ScreenManager getInstance() {
        if (instance == null) {
            instance = new ScreenManager();
        }
        return instance;
    }
 
    // Initialization with the game class
    public void initialize(Game game) {
        this.game = game;
    }
 
    // Show in the game the screen which enum type is received
    public void showScreen(ScreenEnum screenEnum, Object... params) {
 
        // Get current screen to dispose it
        Screen currentScreen = game.getScreen();
 
        // Show new screen
        AbstractScreen newScreen = screenEnum.getScreen(params);
        newScreen.buildStage();
        game.setScreen(newScreen);
 
        // Dispose previous screen
        if (currentScreen != null) {
            currentScreen.dispose();
        }
    }
}

Key issues

  • It is used the software pattern Singleton. By this we will only have an instance of this class for the whole app. Furthermore, this instance will be accesible from any point of our program. The way to get the instance is:
    ScreenManager.getInstance()
  • To work correctly, the class needs a reference to main class of the game, (subclass of Game). We pass this reference in the method initialize():
    ScreenManager.getInstance().initialize(gameInstance);
  • The method showScreen() allow us to show any screen of the of the game by passing its enum type. We also can pass other params needed in the screen constructor. For example:
    ScreenManager.getInstance().showScreen( ScreenEnum.LEVEL_SELECT );
    ScreenManager.getInstance().showScreen( ScreenEnum.GAME, level);

 

Return to main class of the game

Once exposed classes ScreenEnum and ScreenManager, it’s shown the implementation of the main class of the game:

7
8
9
10
11
12
13
public class MyGdxGame extends Game {
    @Override
    publicvoid create () {
        ScreenManager.getInstance().initialize(this);
        ScreenManager.getInstance().showScreen( ScreenEnum.MAIN_MENU );
    }
}

Here, we simply initialize the ScreenManager and we show the main menu screen.

 

Change Screen

To change between screens we only need to call method showScreen() of the class ScreenManager. For example, if we want to go from main menu screen to select level screen, we can use below listener in a button:

btnPlay.addListener(
    new InputListener() {
        @Override
        public boolean touchDown(InputEvent event,
                                 float x, float y, int pointer, int button) {
            ScreenManager.getInstance().showScreen( ScreenEnum.LEVEL_SELECT );
            return false;
        }
    });

 

Source code

You can download the source code from my GitHub repository. By executing the program, we can surf through the three screens of the game:

Main Menu

I hope this article is helpful for you. Good luck for your projects and regards.

7 Replies to “How to manage screens in LibGDX”

  1. It is an overkill system at least for my purpose. N
    ew screen I create:
    game.getScreen(new MenuScreen(game))

    then in MenuScreen when I want to create new screen:
    game.getScreen(new GameScreen(game))

    and I overwrite method in the screens:
    @Override
    public void hide(){
    this.dispose()
    }

    Reference to game is passed to screens.
    Old screens are disposed.
    SpriteBatch ,should be instantiated in a game.

    • Hi Marcin,

      As usual, there are different ways to do the same task. Thanks a lot for commenting and sharing your approach.

      Kind regards,

  2. Hi! Thanks for the example. I’m a little unsure how what the MainMenu screen would look like. It would extend Abstract class, but would I need to create a stage for each screen? What would I have in the show method?
    Basically my question is, could you provide and example MenuScreen that uses this architecture?

    • Hi NicMi1c,

      As you say, there is a stage for each screen of the game. In this example, the only thing I do in the show() method is to set the current screen as the input receiver by calling to Gdx.input.setInputProcessor(). This allow to children buttons to receive input events.

      You can see the complete example on GitHub. Maybe it’s interesting for your question to see the classes AbstractScreen and MainMenuScreen, both on the package com.pixnbgames.scene_management.screen of the core project.

      Thanks for comment and kind regards,

  3. Hi,
    Thanks a lot for the tutorial, it was really useful!
    I had a question concerning the AssetManager. I declare it in the Game class and used to pass it in the constructor to the different screens. Since we are passing by an enumeration in this example, I am not sure how to proceed to pass my AssetManager from my Game class to my screens.
    Maybe there is a better solution than creating the AssetManager in the Game Class and I am missing it.

    Thanks a lot!

    • Hi Eric,

      There are many ways you can do it. For example, if you have follow the structure of this post, you have a reference to the game on ScreenManager. You can expose it and retrieve from you need. Something like this:

      public class MyGdxGame extends Game {
          private AssetManager assets;
          ...
          public AssetManager getAssets() {
              return assets;
          }
          ...
      }

      And then:

      public class ScreenManager {
          ...
          public AssetsManager getMyAssets() {
              return ((MyGdxGame)game).getAssets();
          }
      }
      

      Sou you can do ScreenManager.getInstance().getMyAssets();

      Another approach is to have the AssetManager in a static variable of your game class and access it from anywhere you need, but be careful with this in order to load / unload it correctly:

      public class MyGdxGame extends Game {
          public static AssetManager myAssets;
      }
      

      Thanks for comment and kind regards!

  4. Hey thanks for writing this, it really made my code cleaner. However screens should only be instantiated when starting the game and disposed when you quit the game. Also you should pass the same spritebatch to each of the stage’s constructors, otherwise each stage will create it’s own spritebatch which will waste a lot of memory.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*