{"id":97,"date":"2015-02-26T21:55:54","date_gmt":"2015-02-26T20:55:54","guid":{"rendered":"http:\/\/www.pixnbgames.com\/blog\/?p=97"},"modified":"2015-04-11T22:59:34","modified_gmt":"2015-04-11T21:59:34","slug":"como-hacer-una-pantalla-de-inicio-o-splash-screen-en-libgdx","status":"publish","type":"post","link":"https:\/\/www.pixnbgames.com\/blog\/libgdx\/como-hacer-una-pantalla-de-inicio-o-splash-screen-en-libgdx\/","title":{"rendered":"C\u00f3mo hacer una pantalla de inicio o splash screen en LibGDX"},"content":{"rendered":"<p style=\"text-align: justify;\">Un aspecto importante cuando desarrollemos videojuegos ser\u00e1 la pantalla de inicio o splash screen.<\/p>\n<h4>\u00bfQu\u00e9 es la \u00absplash screen\u00bb?<\/h4>\n<p style=\"text-align: justify;\">Es una pantalla que se muestra al usuario justo al abrir la aplicaci\u00f3n. Normalmente se utiliza para mostrar alguna informaci\u00f3n mientras la aplicaci\u00f3n carga en segundo plano los recursos y hace los preparativos necesarios para funcionar. Podemos ver el uso de splash screens, por ejemplo, al arrancar <a title=\"Sitio oficial de Eclipse\" href=\"http:\/\/www.eclipse.org\/\" target=\"_blank\">Eclipse<\/a> o <a title=\"Sitio oficial de GIMP\" href=\"http:\/\/www.gimp.org\/\" target=\"_blank\">GIMP<\/a>.<\/p>\n<h4>\u00bfPor qu\u00e9 es importante?<\/h4>\n<p style=\"text-align: justify;\"><strong>La cuesti\u00f3n m\u00e1s importante es que indica al usuario que la aplicaci\u00f3n est\u00e1 funcionando.<\/strong> Si la aplicaci\u00f3n 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\u00f3n parecer\u00e1 estar \u00abcongelada\u00bb y en el mejor de los casos s\u00f3lo mostrar\u00e1 una pantalla completamente negra. Usando una splash screen el usuario sabr\u00e1 que nuestra aplicaci\u00f3n ya est\u00e1 abierta y funcionando.<\/p>\n<p style=\"text-align: justify;\">Adem\u00e1s, podemos aprovechar la pantalla de inicio para mostrar nuestra imagen de marca, alg\u00fan mensaje, etc., de forma que podamos sacar provecho\u00a0de esta necesidad.<\/p>\n<h3>C\u00f3mo hacerlo en LibGDX<\/h3>\n<p style=\"text-align: justify;\">Para este ejemplo, voy a utilizar la clase <code>com.badlogic.gdx.Game<\/code> como clase principal del juego y cada escena del juego implementar\u00eda la interfaz <code>com.badlogic.gdx.Screen<\/code>, ya que es la forma en la que trabajo habitualmente (ver\u00a0<a title=\"C\u00f3mo gestionar varias pantallas en LibGDX\" href=\"http:\/\/www.pixnbgames.com\/blog\/libgdx\/como-gestionar-varias-pantallas-en-libgdx\/\">Gesti\u00f3n de escenas en LibGDX<\/a>). Pasamos a ver la implementaci\u00f3n de cada clase:<\/p>\n<h4>SplashScreen<\/h4>\n<p>El c\u00f3digo de esta clase ser\u00e1 tal que as\u00ed:<\/p>\n<pre lang=\"Java\" line=\"1\">package com.pixnbgames.splashscreen;\r\n\r\nimport com.badlogic.gdx.Gdx;\r\nimport com.badlogic.gdx.Screen;\r\nimport com.badlogic.gdx.graphics.GL20;\r\nimport com.badlogic.gdx.graphics.Texture;\r\nimport com.badlogic.gdx.graphics.g2d.SpriteBatch;\r\n\r\npublic class SplashScreen implements Screen {\r\n    private SpriteBatch batch;\r\n    private Texture ttrSplash;\r\n \r\n    public SplashScreen() {\r\n        super();\r\n        batch = new SpriteBatch();\r\n        ttrSplash = new Texture(\"splash-screen.png\");\r\n    }\r\n \r\n    @Override\r\n    public void render(float delta) {\r\n        Gdx.gl.glClearColor(0, 0, 0, 1);\r\n        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);\r\n \r\n        batch.begin();\r\n        batch.draw(ttrSplash, 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());\r\n        batch.end();\r\n    }\r\n \r\n    @Override\r\n    public void hide() { }\r\n \r\n    @Override\r\n    public void pause() { }\r\n \r\n    @Override\r\n    public void resume() { }\r\n\r\n    @Override\r\n    public void show() { }\r\n\r\n    @Override\r\n    public void resize(int width, int height) { }\r\n \r\n    @Override\r\n    public void dispose() {\r\n        ttrSplash.dispose();\r\n        batch.dispose();\r\n    }\r\n}<\/pre>\n<h5>\u00a0Aspectos clave:<\/h5>\n<p style=\"text-align: justify;\"><span style=\"text-decoration: underline;\">Muy importante destacar que esta clase no debe depender de ning\u00fan componente que no haya sido cargado<\/span>. Es por eso que aunque us\u00e1ramos Stages y Actores en nuestro proyecto, lo m\u00e1s recomendable para la splash screen es dibujar directamente mediante un objeto <code>SpriteBatch<\/code>.<\/p>\n<p style=\"text-align: justify;\">Supongamos que tuvi\u00e9ramos\u00a0una clase en nuestro proyecto, <code>ImageManager<\/code>, responsable de cargar y gestionar los recursos gr\u00e1ficos de nuestra aplicaci\u00f3n.\u00a0Muy probablemente la clase <code>ImageManager<\/code> deber\u00eda ser cargada\u00a0al iniciar la aplicaci\u00f3n, de forma que los recursos que gestiona est\u00e9n disponibles para el resto del juego. Pues bien, nuestra <code>SplashScreen<\/code> no podr\u00eda\u00a0hacer uso de esta clase. Por dos motivos:<\/p>\n<ul>\n<li style=\"text-align: justify;\">La splash screen debe ser lo m\u00e1s ligera\u00a0posible. Recordemos que se mostrar\u00e1 al usuario nada m\u00e1s arrancar la aplicaci\u00f3n y ser\u00e1 visible s\u00f3lo durante unos pocos segundos.<\/li>\n<li style=\"text-align: justify;\">Si intentamos usar un recurso que todav\u00eda no est\u00e1 cargado, la splash screen no\u00a0podr\u00e1 mostrarse al usuario, con lo que nuestra aplicaci\u00f3n seguir\u00e1 pareciendo \u00abcongelada\u00bb.<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<h4>\u00a0Clase principal del juego<\/h4>\n<p style=\"text-align: justify;\">Para la clase principal del juego, <code>GdxSplashScreenGame<\/code>, voy a suponer que existe una segunda clase\u00a0con el men\u00fa principal del juego, llamada <code>MainMenuScreen<\/code> (ver\u00a0<a title=\"C\u00f3mo gestionar varias pantallas en LibGDX\" href=\"http:\/\/www.pixnbgames.com\/blog\/libgdx\/como-gestionar-varias-pantallas-en-libgdx\/\">Gesti\u00f3n de escenas en LibGDX<\/a>). El men\u00fa principal se mostrar\u00e1 autom\u00e1ticamente tras la splash screen.<\/p>\n<p style=\"text-align: justify;\">A\u00f1adiremos tambi\u00e9n una condici\u00f3n para mostrar la pantalla de inicio, y es que estar\u00e1 visible al menos durante dos segundos. \u00bfPor qu\u00e9 hacemos esto? Pues porque si ocultamos la pantalla de inicio directamente justo despu\u00e9s de cargar los recursos, el tiempo que est\u00e9 visible depender\u00e1 en gran medida del dispositivo donde se ejecute la aplicaci\u00f3n. Incluso si el dispositivo fuera lo suficientemente\u00a0r\u00e1pido cargando los recursos, nuestra pantalla de inicio podr\u00eda no llegar a mostrarse. Al definir\u00a0un tiempo m\u00ednimo de visualizaci\u00f3n, conseguimos mitigar las diferencias entre los distintos dispositivos donde nuestro juego se ejecuta.<\/p>\n<p style=\"text-align: justify;\">El c\u00f3digo de la clase principal <code>GdxSplashScreenGame<\/code> podr\u00eda ser de la siguiente forma:<\/p>\n<pre lang=\"Java\" line=\"1\">package com.pixnbgames.splashscreen;\r\n\r\nimport com.badlogic.gdx.Game;\r\nimport com.badlogic.gdx.Gdx;\r\nimport com.badlogic.gdx.utils.Timer;\r\n\r\npublic class GdxSplashScreenGame extends Game {\r\n \r\n    private static long SPLASH_MINIMUM_MILLIS = 2000L;\r\n \r\n    public GdxSplashScreenGame() { super(); }\r\n \r\n    @Override\r\n    public void create () {\r\n        setScreen(new SplashScreen());\r\n \r\n        final long splash_start_time = System.currentTimeMillis();\r\n        new Thread(new Runnable() {\r\n               @Override\r\n               public void run() {\r\n \r\n                   Gdx.app.postRunnable(new Runnable() {\r\n                       @Override\r\n                       public void run() {\r\n                           \/\/ ... carga de datos\r\n                           \/\/ ... carga de fuentes tipograficas\r\n                           \/\/ ... carga de sonidos\r\n                           \/\/ ... carga de imagenes\r\n                           \/\/ ... carga de recursos de internacionalizacion\r\n                           \/\/ ... otros\r\n \r\n                           \/\/ Se muestra el menu principal tras la SpashScreen\r\n                           long splash_elapsed_time = System.currentTimeMillis() - splash_start_time;\r\n                           if (splash_elapsed_time &lt; GdxSplashScreenGame.SPLASH_MINIMUM_MILLIS) {\r\n                               Timer.schedule(\r\n                                       new Timer.Task() {\r\n                                           @Override\r\n                                           public void run() {\r\n                                               GdxSplashScreenGame.this.setScreen(new MainMenuScreen());\r\n                                           }\r\n                                       }, (float)(GdxSplashScreenGame.SPLASH_MINIMUM_MILLIS - splash_elapsed_time) \/ 1000f);\r\n                           } else {\r\n                               GdxSplashScreenGame.this.setScreen(new MainMenuScreen());\r\n                           }\r\n                       }\r\n                   });\r\n               }\r\n            }).start();\r\n    }\r\n \r\n    @Override\r\n    public void dispose() {\r\n        \/\/ DISPOSE ALL RESOURCES\r\n        getScreen().dispose();\r\n        Gdx.app.exit();\r\n    }\r\n}\r\n<\/pre>\n<h5>\u00a0Aspectos clave:<\/h5>\n<ul>\n<li style=\"text-align: justify;\">La carga de recursos no puede hacerse en el hilo principal, ya que entonces la aplicaci\u00f3n no mostrar\u00eda nada hasta que terminase toda la carga de recursos. Es por eso que la hacemos en un nuevo <code>Thread<\/code>.<\/li>\n<li style=\"text-align: justify;\">Si al terminar la carga de recursos, ha pasado menos del tiempo definido en <code>SPLASH_MINIMUM_MILLIS<\/code>, tenemos que esperar el tiempo restante y luego mostrar la pantalla, esto lo conseguimos pasando un objeto <code>Timer.Task<\/code> al m\u00e9todo <code>Timer.schedule()<\/code>.<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<h3>C\u00f3digo fuente<\/h3>\n<p style=\"text-align: justify;\">Puedes descargar el c\u00f3digo de fuente de un proyecto simple que hace uso de splash screen desde mi repositorio de\u00a0<a title=\"Gdx-SplashScreen-Example en GitHub\" href=\"https:\/\/github.com\/angelnavarro\/Gdx-SplashScreen-Example\" target=\"_blank\">GitHub<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Un aspecto importante cuando desarrollemos videojuegos ser\u00e1 la pantalla de inicio o splash screen. \u00bfQu\u00e9 es la \u00absplash screen\u00bb? Es una pantalla que se muestra al usuario justo al abrir la aplicaci\u00f3n. Normalmente se utiliza para mostrar alguna informaci\u00f3n mientras <a class=\"more-link\" href=\"https:\/\/www.pixnbgames.com\/blog\/libgdx\/como-hacer-una-pantalla-de-inicio-o-splash-screen-en-libgdx\/\">Seguir leyendo <span class=\"screen-reader-text\">  C\u00f3mo hacer una pantalla de inicio o splash screen en LibGDX<\/span><span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":304,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[14],"tags":[15,18],"language":[5],"_links":{"self":[{"href":"https:\/\/www.pixnbgames.com\/blog\/wp-json\/wp\/v2\/posts\/97"}],"collection":[{"href":"https:\/\/www.pixnbgames.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.pixnbgames.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.pixnbgames.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.pixnbgames.com\/blog\/wp-json\/wp\/v2\/comments?post=97"}],"version-history":[{"count":14,"href":"https:\/\/www.pixnbgames.com\/blog\/wp-json\/wp\/v2\/posts\/97\/revisions"}],"predecessor-version":[{"id":298,"href":"https:\/\/www.pixnbgames.com\/blog\/wp-json\/wp\/v2\/posts\/97\/revisions\/298"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.pixnbgames.com\/blog\/wp-json\/wp\/v2\/media\/304"}],"wp:attachment":[{"href":"https:\/\/www.pixnbgames.com\/blog\/wp-json\/wp\/v2\/media?parent=97"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.pixnbgames.com\/blog\/wp-json\/wp\/v2\/categories?post=97"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.pixnbgames.com\/blog\/wp-json\/wp\/v2\/tags?post=97"},{"taxonomy":"language","embeddable":true,"href":"https:\/\/www.pixnbgames.com\/blog\/wp-json\/wp\/v2\/language?post=97"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}