A la hora de programar juegos de tablero, o a la hora de dibujar nuestros mundos, no es necesario cargar unos fondos enormes. PALib ofrece la posibilidad de poder dibujar tiles.
Los tiles son pequeñas casillas que se pueden dibujar en la pantalla tantas veces como se quiera. Son casillas de 8x8 pixeles, por lo que una pantalla de la DS que tiene 256x192 tendrá 32x24 tiles.
La siguiente imágen nos carga los tiles que vamos a usar en esta primera versión del Tetris:
Si os fijáis bien, se han creado una serie de cuadraditos de 8x8 pixeles que serán las posibles casillas a dibujar. Cómo las fichas del Tetris tienen distintos colores pues hemos hecho casillas de diferentes colores.
Ahora veamos el código poco a poco para ver cómo funciona todo:
En primer lugar:
Cargamos la imagen de los tiles en las dos pantallas mediante estas dos funciones de la API de PALib.
PA_DualLoadBgPal(BACKGROUND_TWO, (void *)tiles_Pal);
PA_DualLoadSimpleBg(BACKGROUND_TWO, tiles_Tiles, Blank, BG_256X256, 0, 1);
La primera carga la paleta de la imagen, y la segunda carga, en las dos pantallas, la imagen como si fueran tiles y lo muestra en pantalla.
¿Pero que muestra? Un array de ceros, Blank, de 32x24 en cada una de las pantallas. Como la primera casilla de la imagen (la casilla cero) de tiles es negra, mostrará una pantalla negra.
Para dibujar por la pantalla los distintos tiles se puede utilizar la función PALib:
PA_SetMapTileEx(screen, BACKGROUND_TWO, x1, y1, ficha, 0, 0, 0);
donde x1,y1 serán las coordenadas del array de 32x24 en que está dividida cada pantalla de la DS. Los tres últimos parámetros ya los veremos más adelante.
Para poder ver todo lo que se ha dicho aquí, probar el siguiente código quitando las dos líneas que cargan los fondos: PA_EasyBgLoad(SCREEN_TOP, BACKGROUND_ONE, fondo_top); y PA_EasyBgLoad(SCREEN_BOTTOM, BACKGROUND_ONE, fondo_bottom);.
Dibujar_casilla:
Esta función dibuja cada casilla del tablero y cada bloque de una ficha del tetris. Como 8x8 pixeles es muy pequeño, vamos a dibujar casillas de 16x16, es decir cuatro veces la casilla de 8x8.
PA_SetMapTileEx(screen, BACKGROUND_THREE, x1, y1, ficha, 0, 0, 0);
PA_SetMapTileEx(screen, BACKGROUND_THREE, x1, y1 + 1, ficha, 0, 1, 0);
PA_SetMapTileEx(screen, BACKGROUND_THREE, x1 + 1, y1, ficha, 1, 0, 0);
PA_SetMapTileEx(screen, BACKGROUND_THREE, x1 + 1, y1 + 1, ficha, 1, 1, 0);
Los parámetros son:
PA_SetMapTileEx(screen, background, x, y, tile, girar_horizontal, girar_vertical, paleta);
Debido a un pequeño problema que ocurre en la pantalla inferior (la posición 0,0 se baja unos 16 pixeles), hay que poner el scroll de esta pantalla a 0 (!?!?!?!?!?) :
PA_EasyBgScrollXY(SCREEN_BOTTOM, BACKGROUND_THREE, 0, 0);
Por último dibujaremos la pantalla de la aplicación. Por ahora he usado estos dos fondos (fondo_top y fondo_bottom)
El código es el siguiente:
#include <PA9.h>
#include "gfx/all_gfx.h"
#include "gfx/all_gfx.c"
#include "devnintendods.h"
#define TABLERO_ANCHO 10
#define TABLERO_ALTO 21
#define FICHA_ANCHO 4
#define FICHA_ALTO 4
#define CASILLA_VACIA 1
#define CASILLA_ROJA 2
#define CASILLA_AZUL 3
#define CASILLA_VERDE 4
#define VELOCIDAD_MINIMA 25
#define BORDE_IZQUIERDO 1
//La fila 0 es la de más arriba y la 16 la de la base. La columna 0 es la de la izquierda.
u8 tablero[TABLERO_ANCHO][TABLERO_ALTO];
typedef struct {
int x, y;
u8 radio;
u8 ficha[FICHA_ANCHO][FICHA_ALTO];
} tipo_ficha;
tipo_ficha ficha;
void inicializar_tablero();
void dibujar_tablero();
void dibujar_casilla(int x, int y, u8 ficha);
int main(int argc, char ** argv) {
PA_Init();
PA_InitVBL();
PA_InitText(SCREEN_TOP, BACKGROUND_TWO);
PA_DualLoadBgPal(BACKGROUND_THREE, (void *)tiles_Pal);
PA_DualLoadSimpleBg(BACKGROUND_THREE, tiles_Tiles, Blank, BG_256X256, 0, 1);
PA_EasyBgScrollXY(SCREEN_BOTTOM, BACKGROUND_THREE, 0, 0);
PA_EasyBgLoad(SCREEN_TOP, BACKGROUND_ONE, fondo_top);
PA_EasyBgLoad(SCREEN_BOTTOM, BACKGROUND_ONE, fondo_bottom);
inicializar_tablero();
dibujar_tablero();
while (1) {
PA_WaitForVBL();
}
}
void inicializar_tablero() {
u8 i, j;
for(i = 0; i < TABLERO_ANCHO; i++)
for(j = 0; j < TABLERO_ALTO; j++)
tablero[i][j] = CASILLA_VACIA;
}
void dibujar_tablero() {
u8 i, j;
for(i = 0; i < TABLERO_ANCHO; i++)
for(j = 0; j < TABLERO_ALTO; j++)
dibujar_casilla(i, j, tablero[i][j]);
}
void dibujar_casilla(int x, int y, u8 ficha) {
u8 x1 = x * 2;
u8 y1 = y;
u8 screen = SCREEN_TOP;
if (y1 >= 12) {
screen = SCREEN_BOTTOM;
y1 = y1 - 12;
}
y1 = y1 * 2;
x1 += BORDE_IZQUIERDO;
PA_SetMapTileEx(screen, BACKGROUND_THREE, x1, y1, ficha, 0, 0, 0);
PA_SetMapTileEx(screen, BACKGROUND_THREE, x1, y1 + 1, ficha, 0, 1, 0);
PA_SetMapTileEx(screen, BACKGROUND_THREE, x1 + 1, y1, ficha, 1, 0, 0);
PA_SetMapTileEx(screen, BACKGROUND_THREE, x1 + 1, y1 + 1, ficha, 1, 1, 0);
}
#include "gfx/all_gfx.h"
#include "gfx/all_gfx.c"
#include "devnintendods.h"
#define TABLERO_ANCHO 10
#define TABLERO_ALTO 21
#define FICHA_ANCHO 4
#define FICHA_ALTO 4
#define CASILLA_VACIA 1
#define CASILLA_ROJA 2
#define CASILLA_AZUL 3
#define CASILLA_VERDE 4
#define VELOCIDAD_MINIMA 25
#define BORDE_IZQUIERDO 1
//La fila 0 es la de más arriba y la 16 la de la base. La columna 0 es la de la izquierda.
u8 tablero[TABLERO_ANCHO][TABLERO_ALTO];
typedef struct {
int x, y;
u8 radio;
u8 ficha[FICHA_ANCHO][FICHA_ALTO];
} tipo_ficha;
tipo_ficha ficha;
void inicializar_tablero();
void dibujar_tablero();
void dibujar_casilla(int x, int y, u8 ficha);
int main(int argc, char ** argv) {
PA_Init();
PA_InitVBL();
PA_InitText(SCREEN_TOP, BACKGROUND_TWO);
PA_DualLoadBgPal(BACKGROUND_THREE, (void *)tiles_Pal);
PA_DualLoadSimpleBg(BACKGROUND_THREE, tiles_Tiles, Blank, BG_256X256, 0, 1);
PA_EasyBgScrollXY(SCREEN_BOTTOM, BACKGROUND_THREE, 0, 0);
PA_EasyBgLoad(SCREEN_TOP, BACKGROUND_ONE, fondo_top);
PA_EasyBgLoad(SCREEN_BOTTOM, BACKGROUND_ONE, fondo_bottom);
inicializar_tablero();
dibujar_tablero();
while (1) {
PA_WaitForVBL();
}
}
void inicializar_tablero() {
u8 i, j;
for(i = 0; i < TABLERO_ANCHO; i++)
for(j = 0; j < TABLERO_ALTO; j++)
tablero[i][j] = CASILLA_VACIA;
}
void dibujar_tablero() {
u8 i, j;
for(i = 0; i < TABLERO_ANCHO; i++)
for(j = 0; j < TABLERO_ALTO; j++)
dibujar_casilla(i, j, tablero[i][j]);
}
void dibujar_casilla(int x, int y, u8 ficha) {
u8 x1 = x * 2;
u8 y1 = y;
u8 screen = SCREEN_TOP;
if (y1 >= 12) {
screen = SCREEN_BOTTOM;
y1 = y1 - 12;
}
y1 = y1 * 2;
x1 += BORDE_IZQUIERDO;
PA_SetMapTileEx(screen, BACKGROUND_THREE, x1, y1, ficha, 0, 0, 0);
PA_SetMapTileEx(screen, BACKGROUND_THREE, x1, y1 + 1, ficha, 0, 1, 0);
PA_SetMapTileEx(screen, BACKGROUND_THREE, x1 + 1, y1, ficha, 1, 0, 0);
PA_SetMapTileEx(screen, BACKGROUND_THREE, x1 + 1, y1 + 1, ficha, 1, 1, 0);
}
La programación con 'tiles' nos permitirá crear el juego de plataformas. Si nos da tiempo volveremos sobre el juego de Pokemon para poder hacer mundos más grandes, sin ocupar demasiado espacio en memoria.
Saludos