martes, 24 de septiembre de 2013

Assets Manager, añadiendo música, imágenes y sonido.


Assets

Saludos otra vez, éste artículo lo dedicaré a los assets, un ejemplo de assets son las imágenes, el sonido y la música entre otros, que son los que a continuación voy a explicar.

Imágenes

Existen 2 tipos de imágenes planas estáticas en libgdx, la Texture y la TextureRegion. 

La Texture es una imagen jpg o png que debemos cargar en memoria y luego dibujarla en el render con el objeto Spritebatch.  Para cargarla en memoria antes tenemos que guardarla en nuestro proyecto de android en la carpeta assets, es recomendable separar los assets en carpetas por tipos, así que yo crearé mis carpetas Music, Sounds and Images.

Vamos a preparar nuestra imagen de fondo para el juego, he pensado hacer un juego de un pequeño pez en el oceano que tenga que recojer plancton para alimentarse, un ejemplo muy chorra pero nos servirá para ir desarrollando poco a poco.

La imagen debe ser POT, es decir, potencia de 2, no podemos hacer una imagen de 800x480 y colocarla y ya está, debemos alojarla en otra imagen con unas dimensiones de 512,1024,16,64, etc.

Así que cojo el Photoshop o el GIMP me creo mi fondo de 800x480.

 Y después lo añado a una imagen de 1024x1024.
 Y la guardo en la carpeta Assets/Images.

Ahora antes de instanciar la imagen ajustaré la resolución de la camara.

Para ello borraré todos los datos creados por el proyecto de prueba dejando únicamente los métodos y eliminando los atributos de la clase de mi juego. Os muestro mi clase para que observeís como colocar la imagen de fondo, guiaros por los comentarios.

package com.Firedark.libgdxspain;

import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;

public class LibgdxSpain implements ApplicationListener {
   
    //Creamos los 4 Objetos que usaremos para éste Tutorial, Camara, SpriteBatch,Textura y Region
    private OrthographicCamera camera;
    private SpriteBatch batch;
    private Texture texture;
    private TextureRegion region;

    @Override
    public void create() {       
        // Estas variables las usaremos para ajustar la resolución a 800x480
        float w = 800;
        float h = 480;
        //Instanciamos Camara y le ajustamos con el metodo SetToOrtho la resolución anterior.
        camera = new OrthographicCamera();
        camera.setToOrtho(false,w,h);
        //Instanciamos Spritebatch
        batch = new SpriteBatch();   
        //Instanciamos la Textura, para ello tenemos que darle la localización dentro de la carpeta ASSETS
        texture = new Texture(Gdx.files.internal("data/Images/oceanbackground.jpg"));
        //Usaremos la region para determinar la zona que queremos cojer de la imagen de 1024 x 1024 como empieza por la
        //esquina superior izquierda escojemos 0,0 de coordenadas X e Y y 800 de ancho y 480 de alto.
        region = new TextureRegion(texture,0,0,800,480);
       
    }

    @Override
    public void dispose() {
        // NO olvidaros vaciar la memoria en el metodo dispose de los objetos que vamos subiendo a memoria.
        batch.dispose();
        texture.dispose();
       
    }

    @Override
    public void render() {       
        //Esto limpiaria lo que es la pantalla en negro, al colocarle la imagen de fondo encima no lo apreciaremos
        Gdx.gl.glClearColor(1, 1, 1, 1);
        Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
        // Ajustamos la camara con el SpriteBatch
        batch.setProjectionMatrix(camera.combined);
        //Empezamos a dibujar
        batch.begin();
        //usamos el metodo del spritebatch draw para dibujar la region,(OJO! no la textura, podriamos dibujarla también
        //pero deberiamos cuadrarla en la pantalla con las coordenadas (0,-544).
        batch.draw(region,0,0);
        //Fin de dibujar.
        batch.end();
    }

    @Override
    public void resize(int width, int height) {
    }

    @Override
    public void pause() {
    }

    @Override
    public void resume() {
    }
}
Bien, ahora que tenemos el fondo voy a explicar como instanciar la música y el sonido, es más sencillo aún que colocar una imagen.

Sonido. 

Debe ser un archivo .wav, .mp3 o OGG. Es recomendable que useís algún programa para transformarlos todos a mp3 ya que ocupan menos, yo utilizo el AVS Audio Converter y la verdad es que me va genial.

Debemos crear un objeto Sound.
private Sound sound;

Metodo Create:
sound = Gdx.audio.newSound(Gdx.files.internal("data/mysound.mp3"));
 
Hay varios metodos para usar el sonido, es cuestión de experimentar un poco, los más 
comunes son sound.play(), sound.play(float Volumen).

Aquí teneís el link del objeto sound:
 
http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/audio/Sound.html


Musica

Voy a colocar una música de fondo a mi juego. Me la he descargado de la página de freesounds.

http://www.freesound.org/people/KaiLietzke/sounds/185063/ 

Una vez descargada la renombro a musica.wav y la meto en la carpeta assets/data/Music.

Creo el objeto Music de libgdx en los atributos de mi clase, y en el metodo create añado ésto.

        //Instancia la música.
        musica = Gdx.audio.newMusic(Gdx.files.internal("data/Music/musica.wav"));
        //La pone en bucle continuo
        musica.setLooping(true);

        //La pone en play.
        musica.play(); 
 
 Problemas y Consejos
-  No metaís en memoria assets en métodos cíclicos o sobrecargareís la memoria.
 - No añadais un sónido o una música en el metodo render sin condición alguna, al ser cíclico lógicamente lo pondreís en play cada ciclo y sonará mal. ( Existe un método isLooping que te devuelve un boolean si la música esta en loop)
-  Acordaós de usar el método dispose() de Músicas y Sonidos.
- Cuidado con los Path de los archivos de los assets, en desktop no te detectará mayúsculas, pero en android si, y os podeís liar.

Gestor de Assets

Es conveniente intentar separar los datos de la lógica del juego para tener mayor control de la carga de assets y acceder fácilmente a ellos desde cualquier punto del programa, ahora con 1 classe principal creada no es muy necesario pero con el tiempo y con el juego mas avanzado resultará realmente útil. Para ello vamos a crear una classe llamada AssetsManager en el proyecto núcleo de nuestro juego.

Aqui crearemos nuestros objetos de texturas y nuestros 2 métodos de carga y liberación de memoria de nuestras imágenes, música y sonido.

Éste es un ejemplo de la clase del tutorial anterior:

package com.Firedark.libgdxspain;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.TextureRegion;


public class AssetsManager {
   
    public Texture Tbackground;
    public TextureRegion background;
    public Music musica;
   
    public void cargarAssets(){
        Tbackground = new Texture(Gdx.files.internal("data/Images/oceanbackground.jpg"));
        background = new TextureRegion(Tbackground,0,0,800,480);
        musica = Gdx.audio.newMusic(Gdx.files.internal("data/Music/musica.wav"));       
    }
   
    public void disposeAssets(){
        Tbackground.dispose();
        musica.dispose();
    }
   
}





Finalmente deberemos ir a la classe principal de nuestro juego y acceder a los datos a través de la instancia de esta classe AssetsManager.

package com.Firedark.libgdxspain;

import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;


public class LibgdxSpain implements ApplicationListener {
   
    //Creamos los 4 Objetos que usaremos para éste Tutorial, Camara, SpriteBatch,Textura y Region
    private OrthographicCamera camera;
    private SpriteBatch batch;
    private AssetsManager assets;

    @Override
    public void create() {    

        // Creamos el AssetManager
         assets = new AssetsManager();
        //Si nos olvidamos de cargar los assets en memoria nos dará NullPointerException porque no los encontrará.
        assets.cargarAssets();
       
        float w = 800;
        float h = 480;
        camera = new OrthographicCamera();
        camera.setToOrtho(false,w,h);

        batch = new SpriteBatch();   
    //accedemos a assets.musica, el atributo de musica de la clase assets.
        assets.musica.setLooping(true);
        assets.musica.play();
    }

    @Override
    public void dispose() {
   
        batch.dispose();
        //Llamamos al metodo para liberar Assets.
        assets.disposeAssets();
       
    }

    @Override
    public void render() {       

        Gdx.gl.glClearColor(1, 1, 1, 1);
        Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);

        batch.setProjectionMatrix(camera.combined);

        batch.begin();
        //Aqui accedemos al atributo TextureRegion background de la clase assets.
        batch.draw(assets.background,0,0);
        batch.end();
    }

    @Override
    public void resize(int width, int height) {
    }

    @Override
    public void pause() {
    }

    @Override
    public void resume() {
    }
}
 




 

Gracias, para el siguiente artículo explicaré un poco de entradas y empezaremos a mover rectángulos y hacer que actúen. A programar! 

11 comentarios:

  1. La verdad que muy útil todo. Muchas gracias!

    ResponderEliminar
  2. Hola unas preguntas de novato por si puedes ayudarme:
    -si yo le doy a run as android aplication en el proyecto-android me deberia cargar la imagen y la musica de fondo no? es que solo me sale el movil
    -en el metodo create no deberia ser music en vez de musica, con musica me da error
    -no hace falta poner en la ruta de sound y music /assets?(la carpeta assets es la que esta en el -android me imagino)
    -

    ResponderEliminar
    Respuestas
    1. Ok cambiando a otro dispositivo con un soft mas nuevos ya me va la imagen y el sonido de fondo a ver si consigo ponerlo en horizontal :) gracias por el tuto hay muy pocos en español

      Eliminar
  3. Podrias decirme cuando te refieres "en el proyecto núcleo de nuestro juego." es una classe en el mismo "nivel" de la classe principal o es una classe "dentro de" es que me despista que tengas los imports encima de las dos classes, si pudieras explicarme un poco esto te lo agradeceria porque es que ya no se que hacer, de la unica manera que no me salen errores con tu codigo es escribir la clase dentro de public class LibgdxSpain implements ApplicationListener. gracias

    ResponderEliminar
    Respuestas
    1. Tambien he estado pensando si fuera problema del emulador ya que me he bajado otros proyectos y me da el mismo error, de dice que se ha parado la aplicacion me recomiendas alguna configuracion o mejor lo pruebo en el movil? Muchas gracias de nuevo

      Eliminar
    2. Vale, antes de todo asegurate tener los tres proyectos, el normal, el android y el desktop, partiendo de ahi, no hace falta k lo pruebes siempre en android puedes testearlo rapido en desktop y probarlo alguna vez en android para arreglar resoluciones, etc

      Eliminar
  4. Tengo problemas para mostrar las imagenes, siempre me sale la pantalla en negro.

    ResponderEliminar
  5. Hola José, he puesto el enlace al foro, aún esta bastante verde ya que es recién creado, pero servirá para exponer las dudas que tienes, ve al apartado de dudas y especifica un poco tu problema, pega el código etc, así me resultará mas fácil ayudarte.

    ResponderEliminar
  6. Hola esta muy bueno bolg quería preguntarte si el tamaño de imagen se adapta a las distintas pantallas y densidades de forma automática ó cual seria (el ó los) tamaños de imágenes (en pixeles) recomendadas, para mayor performance en cuanto al tamaño de la .apk.
    Así al final tener un juego que no pese mucho por sus recursos gráficos y se vea bien en un celular ó tablet.

    Gracias saludos... :)

    ResponderEliminar