How to make a splash screen in LibGDX

An important aspect at video game development is the splash screen.

What is the splash screen?

It is an screen which is shown to the user just when he opens the application. It is usually used to show some information to user while in background the app does the necessary load and preparations to run. We can see the use of splash screen, for example, on Eclipse or GIMP.

Why is it important?

The more important issue is that the splash screen shows to the user that our app is running. If the app needs many resources (common in a video game), it is probably the app spends some seconds on load all it. If we don’t do anything, our app will seem frozen along those seconds and in the better case it will only show a black screen. By using the splash screen the user will know our app is opened and running.

Furthermore, we can take advantage of the splash screen to show our trademark, any message, etc.

 

How to make it in LibGDX

For this example, I have going to use the class com.badlogic.gdx.Game as superclass of the main class of my game, and every scene of the game will be an implementation of the interface com.badlogic.gdx.Screen, because this is the way I usually work (see Scenes management in LibGDX). Let’s go to see the classes implementations:

SplashScreen

The code of this class will be like this:

1
2
3
4
5
6
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
package com.pixnbgames.splashscreen;
 
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
 
public class SplashScreen implements Screen {
    private SpriteBatch batch;
    private Texture ttrSplash;
 
    public SplashScreen() {
        super();
        batch = new SpriteBatch();
        ttrSplash = new Texture("splash-screen.png");
    }
 
    @Override
    public void render(float delta) {
        Gdx.gl.glClearColor(0, 0, 0, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
 
        batch.begin();
        batch.draw(ttrSplash, 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
        batch.end();
    }
 
    @Override
    public void hide() { }
 
    @Override
    public void pause() { }
 
    @Override
    public void resume() { }
 
    @Override
    public void show() { }
 
    @Override
    public void resize(int width, int height) { }
 
    @Override
    public void dispose() {
        ttrSplash.dispose();
        batch.dispose();
    }
}
Key Issues:

It’s very important to stand out that this class must not depend on any other component which has not been loaded yet. This is why this class draws directly an image on screen with a SpriteBatch object.

Supose you have a class in your project, ImageManager, responsible of load and management of the graphics resources of our app. Probably, ImageManager should be initialized at the aplication startup, so that the resources it manages will be available to the rest of the game. Well, our SplashScreen can not use this class. For two reasons:

  • The splash screen have to be as light as possible. Remember that it will be shown to the user as soon as possible at the aplication startup and it will be visible only for a few seconds.
  • If we try to use any resource which has not been loaded yet, the splash screen will not can be shown to the user, so our app will still seem «frozen».

 

 Main class of the Game, GdxSplashScreenGame

For the main class of the game, GdxSplashScreenGame, I will supose that there is a second class (not included in this tutorial) with the main menu of the game, named MainMenuScreen (see Scenes management in LibGDX). The main menu will be automatically shown after splash screen.

We also add a condition to splash screen, and it is that the screen will be shown at least for two seconds. Why do we do this? Because if we hide the splash screen just when all the resources are loaded, the time while the splash screen is shown is totally dependent of the device where the app is running. Even, if the device is enough fast at resource loading, our splash screen could not get displayed. By defining a minimum display time, we managed to mitigate the differences between the various devices where our game is running.

The code for the main class GdxSplashScreenGame would be like this:

1
2
3
4
5
6
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
50
51
52
53
54
55
56
57
package com.pixnbgames.splashscreen;
 
import com.badlogic.gdx.Game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.utils.Timer;
 
public class GdxSplashScreenGame extends Game {
 
    private static long SPLASH_MINIMUM_MILLIS = 2000L;
 
    public GdxSplashScreenGame() { super(); }
 
    @Override
    public void create () {
        setScreen(new SplashScreen());
 
        final long splash_start_time = System.currentTimeMillis();
        new Thread(new Runnable() {
               @Override
               public void run() {
 
                   Gdx.app.postRunnable(new Runnable() {
                       @Override
                       public void run() {
                           // ... carga de datos
                           // ... carga de fuentes tipograficas
                           // ... carga de sonidos
                           // ... carga de imagenes
                           // ... carga de recursos de internacionalizacion
                           // ... otros
 
                           // Se muestra el menu principal tras la SpashScreen
                           long splash_elapsed_time = System.currentTimeMillis() - splash_start_time;
                           if (splash_elapsed_time < GdxSplashScreenGame.SPLASH_MINIMUM_MILLIS) {
                               Timer.schedule(
                                       new Timer.Task() {
                                           @Override
                                           public void run() {
                                               GdxSplashScreenGame.this.setScreen(new MainMenuScreen());
                                           }
                                       }, (float)(GdxSplashScreenGame.SPLASH_MINIMUM_MILLIS - splash_elapsed_time) / 1000f);
                           } else {
                               GdxSplashScreenGame.this.setScreen(new MainMenuScreen());
                           }
                       }
                   });
               }
            }).start();
    }
 
    @Override
    public void dispose() {
        // DISPOSE ALL RESOURCES
        getScreen().dispose();
        Gdx.app.exit();
    }
}
Key Issues:
  • The resources loading cannot be done in the main thread, so then the application could not show anything until the loading will be completed. This is why it is done in a new Thread.
  • If after resource loading, it has been spent less time that the time defined in SPLASH_MINIMUM_MILLIS, we have to wait the missing time and then show the main menu screen. We get this by passing a Timer.Task object to the Timer.schedule() method.

 

Source code

You can download the source code of a simple project with splash screen from my GitHub repository.

8 comentarios en «How to make a splash screen in LibGDX»

  1. Thanks for the tuto.

    Just a question: do you really need to explicitly create another thread? I think it should be enough to tell gdx to post a runnable:

    Gdx.app.postRunnable(new Runnable() {
    // load stuff…
    });

    • Hi gsim,

      Thanks for comment. Surely, there are other possibilities, but the truth is I don’t know why, but the only way I got the desired behavior was as shown here.

      Have you tried your solution and checked it is ok?

      Thanks again and kind regards!

  2. I think that this implementation is wrong.. You should load stuff in the new Thread that you create not in Gdx.app.postRunnable(), this becaus stuff inside Gdx.app.postRunnable() happens on Main UI Thread!

    Proof? Just put a Thread.sleep(5000) to simulate hard loading inside Gdx.app.postRunnable() run..
    So the correct structure should be:
    new Thread(new Runnable() {
    @Override
    public void run() {
    //Load stuff… Thread.sleep
    Gdx.app.postRunnable(new Runnable() {
    @Override
    public void run() {
    //switch screen
    }
    });
    }
    }).start();

  3. @Override
    public void show() {
    stage = new Stage(new FitViewport(VIRTUAL_WIDTH, VIRTUAL_HEIGHT, new OrthographicCamera()));
    stage.getViewport().apply(true);

    stage.setDebugAll(true);

    atlas = game.getAssetManager().get(«game_textures.atlas»);
    background = atlas.findRegion(«splash1»);
    Image bck = new Image(background);
    bck.setAlign(Align.center);
    bck.addAction(Actions.alpha(0f));
    bck.addAction(Actions.sequence(
    Actions.fadeIn(2f),
    Actions.delay(1f),
    Actions.fadeOut(2f),
    Actions.run(new Runnable() {
    @Override
    public void run() {
    game.setScreen(new GameScreen(game));
    }
    }))
    );

    game.setScreen(new GameScreen(game));
    stage.addActor(bck);
    }

    Just another one implementation 🙂 , some animation(action) instead of Thread.sleep();

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>

*