Tutorial videojuegos: Carga de recursos en un videojuego

tutorial programacion videojuegos carga recursos

Capítulo 2 del curso de programación de videojuegos.

Cuando estamos programando un videojuego una de las cosas que necesitamos es la carga de recursos (imágenes, sonidos, archivos de texto, etc). Para cargar recursos hay que tener algunas cosas importantes a la hora de hacerlo:

No cargar recursos en tiempo de ejecución:

En adelante cuando hable de disco hay que entender que me refiero a disco si es un pc y a memoria sólida si es un móvil. Los recursos gráficos y sonidos deben de cargarse de disco, esto consume tiempo de proceso. Durante el juego debemos evitar cargar nada de disco ya que si lo hacemos nos ocurrirá que el juego sufrirá un pequeño parón e irá a saltos ya que los FPS se reducirán durante el tiempo que se tarde la lectura. Puede parecer poco, pero os aseguro que cargar una pequeña imagen en tiempo de juego se notan los tirones.

La forma correcta es cargar los recursos antes del inicio del juego, de esta forma el usuario simplemente tendrá que esperar a que cargue el juego al principio. Durante el juego, no notará ninguna redución de los FPS.

A veces ocurre que necesitamos un montón de sprites que además creemos que tenemos que cargarlos en tiempo de ejecución. Por ejemplo, tenemos una nave que va matando marcianitos, los marcianitos van saliendo según pasa el tiempo. En este caso y casos parecidos lo normal es no crear marcianos en tiempo de ejecución, sino crear un número al principio del juego (10 por ejemplo) y según van muriendo irlos reutilizando. Esto se hace de forma sencilla con los pool de sprites. Más adelante en este curso hablaremos de los pool de sprites. De momento lo menciono para que los vayáis conociendo y os vaya sonando.

Usar archivos gráficos con formato conveniente

Si vamos a cargar imágenes de sprites deberemos usar imágenes en formato PNG para que tengan transparencias. Esta norma es raro romperla ya que casi siempre los sprites no son totalmente cuadrados o rectangulares, normalmente tienen formas y necesitan transparencias. Los PNG ocupan más que los JPG pero son necesarios para los sprites

Si vamos a cargar imágenes de fondos es recomendable usar imágenes en formato JPG. En este caso al ser fondos (tienen forma rectangular) no nos hará falta transparencia, así que podemos aprovechar para ahorrar en cuanto al espacio ocupado por nuestra app. Al usar JPG en un fondo podemos pasar fácilmente de una imagen PNG de 800kb a una de 80kb-100kb sin apenas pérdida de calidad.

Usar archivos de sonido con formato conveniente

Los archivos recomendables a la hora de reproducir sonidos en nuestro juego son los archivos .ogg, el formato mp3 es propietario y no es recomendable usarlo. Si tienes archivos MP3 podrás transformarlos fácilmente con multitud de software que hay disponible.

Usar archivos de texto con formato conveniente

Para los mapas de nuestro juego probablemente necesitemos almacenarlos de alguna forma. La forma habitual y sencilla es guardarlos en archivos de texto (xml, json o texto). Dependiendo de la complejidad del mapeado puede que simplemente necesitemos uno de texto plano. En la mayoría de las ocasiones es suficiente. En los juegos que he hecho los mapas los suelo hacer con códigos alfanuméricos. Por ejemplo:

// Cada 3 grupos de caracteres corresponde un sprite. Con esta leyenda:
// El primer caracter es la textura (1=roca.png, 2=cesped.png, etc)
// El segundo caracter corresponde con el modificador (0=no mover, 1=mover de izda a decha, etc)
// El tercer caracter corresponde lo que se quiera.

000 000 000 100 100 100 000 000 000
000 000 000 200 000 200 000 000 000
000 000 000 200 000 200 000 000 000
000 000 000 200 000 200 000 000 000
000 000 000 200 000 200 000 000 000

En mi ejemplo he cogido esa nomenclatura, podés coger la que queráis. Incluso podéis hacer un mapa más sencillo sin modificadores, solo con texturas:

0 0 0 0 0 0 
0 0 1 0 0 0 
0 0 2 0 0 0
0 0 2 0 0 0
0 3 3 3 3 3

Tenéis que tener en cuenta que yo he puesto números, pero pueden ser letras. Luego en nuestro programa haremos un fichero con traducciones que indicarán la textura que tiene cada caracter: 1="flecha.png", etc

Para leer los archivos de los mapas lo normal es hacerlo en una clase parecida a la que pongo abajo. Si os fijais al final relleno un array con lo que tiene cada celda y otro con el modificador (en mi caso el modificador es para definir que ese trozo del mapa se movera de arriba a abajo o de derecha a izquierda) de cada celda. Esto luego lo recogeremos en nuestra clase del mapa para ir pintando los sprites con sus modificadores, para ello usaremos los 2 arrays que hemos cargado. Es decir, primero cargamos los datos del mapa con la clase de abajo y luego recorremos los arrays para cargar las imagenes del mapa y le añadimos los modificadores:

public void loadScreen(AssetManager am,String fase){		
        String readLine = null;
        this.screen = new ArrayList<String[]>();
        this.modificadores = new ArrayList<String[]>();
        
        try {	        
        	InputStream fichero = am.open("screens/"+fase);	        	
        	BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(fichero));
        	// Leemos primera linea
            while ((readLine = bufferedReader.readLine()) != null) {
            	
            	String linea = readLine.toString().trim();
            	String [] tmp=linea.split("=");
            	
                if (!linea.substring(0, 1).equals("#")){                	
                	if (tmp[0].equals("name")){
                	   name=tmp[0];
                	}else{
                		String [] filaPistas = linea.split(" ");
                		String [] filaPistasFinal = new String[filaPistas.length];
                		String [] filaModificadores = new String[filaPistas.length];
                		for (int i=0;i<filaPistas.length;i++){
                			filaPistasFinal[i] = filaPistas[i].substring(0, 2);
                			filaModificadores[i] = filaPistas[i].substring(2, 3);
                		}
                		this.screen.add(filaPistasFinal);
                		this.modificadores.add(filaModificadores);
                			
                	}
                }
            }        
         
            // Close the InputStream and BufferedReader
            fichero.close();
            bufferedReader.close();

        } catch (Exception e) {Log.d("","Error al cargar la fase: "+fase+" "+e.getMessage());}  
	
		
	}

Juegos con mapas hechos con Tiles. Para estos juegos puede ser útil usar el formato TMX (Tile map XML). Con un editor como el MapEditor podremos hacer mapas en XML que luego leeremos en nuestro código. La librería Andengine usada para hacer videojuegos tiene clases que leen directamente los mapas generados por el mapEditor.

¿Dónde guardar los archivos de recursos?

Normalmente se guardan en la carpeta "assets" de nuestro proyecto. Yo suelo hacer 3 carpetas: 

assets/grf: con los recursos gráficos
assets/screens: con los recursos de texto (pantallas del juego)
assets/sounds: con los recursos de sonidos

Os propongo que probéis un juego que he desarrollado con muchas de las cosas propuestas en estos tutoriales, el juego es el Arkandroid. La foto que ilustra este artículo es una captura del juego. En este juego usé la carga de recursos que hoy he explicado en el tutorial, las fases son números que indican el tipo de ladrillo y el movimiento que tiene si lo tuviera.

Votos totales: 45