Cómo hacer una pantalla de inicio o splash screen en LibGDX

Un aspecto importante cuando desarrollemos videojuegos será la pantalla de inicio o splash screen.

¿Qué es la «splash screen»?

Es una pantalla que se muestra al usuario justo al abrir la aplicación. Normalmente se utiliza para mostrar alguna información mientras la aplicación carga en segundo plano los recursos y hace los preparativos necesarios para funcionar. Podemos ver el uso de splash screens, por ejemplo, al arrancar Eclipse o GIMP.

¿Por qué es importante?

La cuestión más importante es que indica al usuario que la aplicación está funcionando. Si la aplicación desarrollada necesita muchos recursos (cosa habitual en un videojuego), es probable que tarde unos segundos en cargarlos todos. Si no hacemos nada, durante esos segundos nuestra aplicación parecerá estar «congelada» y en el mejor de los casos sólo mostrará una pantalla completamente negra. Usando una splash screen el usuario sabrá que nuestra aplicación ya está abierta y funcionando.

Además, podemos aprovechar la pantalla de inicio para mostrar nuestra imagen de marca, algún mensaje, etc., de forma que podamos sacar provecho de esta necesidad.

Cómo hacerlo en LibGDX

Para este ejemplo, voy a utilizar la clase com.badlogic.gdx.Game como clase principal del juego y cada escena del juego implementaría la interfaz com.badlogic.gdx.Screen, ya que es la forma en la que trabajo habitualmente (ver Gestión de escenas en LibGDX). Pasamos a ver la implementación de cada clase:

SplashScreen

El código de esta clase será tal que así:

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();
    }
}
 Aspectos clave:

Muy importante destacar que esta clase no debe depender de ningún componente que no haya sido cargado. Es por eso que aunque usáramos Stages y Actores en nuestro proyecto, lo más recomendable para la splash screen es dibujar directamente mediante un objeto SpriteBatch.

Supongamos que tuviéramos una clase en nuestro proyecto, ImageManager, responsable de cargar y gestionar los recursos gráficos de nuestra aplicación. Muy probablemente la clase ImageManager debería ser cargada al iniciar la aplicación, de forma que los recursos que gestiona estén disponibles para el resto del juego. Pues bien, nuestra SplashScreen no podría hacer uso de esta clase. Por dos motivos:

  • La splash screen debe ser lo más ligera posible. Recordemos que se mostrará al usuario nada más arrancar la aplicación y será visible sólo durante unos pocos segundos.
  • Si intentamos usar un recurso que todavía no está cargado, la splash screen no podrá mostrarse al usuario, con lo que nuestra aplicación seguirá pareciendo «congelada».

 

 Clase principal del juego

Para la clase principal del juego, GdxSplashScreenGame, voy a suponer que existe una segunda clase con el menú principal del juego, llamada MainMenuScreen (ver Gestión de escenas en LibGDX). El menú principal se mostrará automáticamente tras la splash screen.

Añadiremos también una condición para mostrar la pantalla de inicio, y es que estará visible al menos durante dos segundos. ¿Por qué hacemos esto? Pues porque si ocultamos la pantalla de inicio directamente justo después de cargar los recursos, el tiempo que esté visible dependerá en gran medida del dispositivo donde se ejecute la aplicación. Incluso si el dispositivo fuera lo suficientemente rápido cargando los recursos, nuestra pantalla de inicio podría no llegar a mostrarse. Al definir un tiempo mínimo de visualización, conseguimos mitigar las diferencias entre los distintos dispositivos donde nuestro juego se ejecuta.

El código de la clase principal GdxSplashScreenGame podría ser de la siguiente forma:

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();
    }
}
 Aspectos clave:
  • La carga de recursos no puede hacerse en el hilo principal, ya que entonces la aplicación no mostraría nada hasta que terminase toda la carga de recursos. Es por eso que la hacemos en un nuevo Thread.
  • Si al terminar la carga de recursos, ha pasado menos del tiempo definido en SPLASH_MINIMUM_MILLIS, tenemos que esperar el tiempo restante y luego mostrar la pantalla, esto lo conseguimos pasando un objeto Timer.Task al método Timer.schedule().

 

Código fuente

Puedes descargar el código de fuente de un proyecto simple que hace uso de splash screen desde mi repositorio de GitHub.

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>

*