Anuncios Google

Curso aplicado de GRRLIB - 5º Entrega

Tutoriales Avanzados Homebrewes

Tal y como en los periodicos semanales o revistas donde aparecen unos pequeños catalogos con cursos, casi de la misma manera, pero no tan completos. nos llega la 5ª entrega de los cursos aplicados de GRRLIB, esta vez profundizando mucho más. Apuesto a que las ansias te ganan, bueno pues entonces dale click y continúa leyendo para aprender aún más.

TEXTURAS Y MANEJO DE LOS WIIMOTES

Hola de nuevo amigos. Como podréis ver en esta entrega, poco a poco vamos entrando en materia y empezamos a hacer aplicaciones con cierto nivel de utilidad.

En la entrega anterior estuvimos viendo las instrucciones de dibujo en 2D, pero nos faltó ver la parte que nos permite hacer aplicaciones con un aspecto más profesional.

Estamos hablando del manejo de las texturas.

En esta entrega veremos cómo se uilizan las texturas en GRRLIB, como se cargan desde la SD y como se enlazan en el archivo .dol para que no sea necesario más que un sólo archivo.

También en esta entrega aprenderemos el uso de los wiimotes. Realmente los wiimotes se controlan con la biblioteca WPAD que no tiene nada que ver con GRRLIB, pero mi intención es que llegamos a saber integrar nuestros efectos graficos en un programa completo, y para ello necesitamos conocer otras bibliotecas como WPAD.

Al final de esta entrega habremos desarrollado un "Button tester" gráfico, que aprovechará las texturas para conseguir un programa realmente aparente.

No es que a estas alturas un button tester sea algo muy original, pero si que es la excusa perfecta para aprender a utilizar los wiimotes.

Al final y añadiendole un poco de humor a la miriada de buttontester que pueblan nuestras web, me he permitido bautizar este button tester con el nombre YABT, acronimo de (YET ANOTHER BUTTON TESTER).

Dejando de lado la palabrería vamos a pasar ya al grano y comenzamos con las texturas.

ALTERNATIVAS EN EL MANEJO DE LAS TEXTURAS

Existen dos posibilidades a la hora de manejar texturas

  1. Enlazar la imagen en nuestro programa en tiempo de compilación, para que quede incluida dentro de nuestro .dol y manejemos un sólo archivo.
  2. Leer el archivo de imagen desde la SD en tiempo de ejecución.

Cada una de las dos posibilidades tiene sus ventajas y sus inconvenientes.

Enlazar la imagen en nuestro programa tiene la ventaja de que manejamos un sólo archivo ejecutable y por tanto nuestro programa no necesitará de archivos auxiliares, sin embargo tiene la desventaja de que tenemos que elegir las imagenes en tiempo de compilación (por ejemplo esto no sería posible en un visualizador de fotos), y además engordamos nuestro archivo .dol.

Leer los archivos desde la SD tiene la ventaja de la flexibilidad, pudiendo cambiar la imagen sin tocar el programa, pero sin embargo deja una carpeta más desordenada, con infinidad de archivos. Además cuando estamos depurando el programa deberemos copiar cada nuevo archivo de imagen a la SD, ya que estos no se copian automáticamente con wiiload.

No hay una solución mejor que la otra, y deberemos pensar cual es la que mejor se adapta a nuestra aplicacion a la hora de planificarla.

Por un tema de comodidad y orden a la hora de preparar el programa, para nuestro YABT usaremos la primera de las dos opciones, ya que no es necesario sustituir ninguna imagen durante la ejecución y además estas son usadas durante todo el tiempo.

Si usaramos un programa que cambie de imágenes en tiempo de ejecución sería preferible usar la función que te permite cargar la imagen directamente desde un archivo, pero tened en cuenta que esta función debéis usarla fuera del bucle principal para no penalizar el tiempo de ejecución.

En cualquiera de los dos casos debemos tener en cuenta algo que si no lo sabemos nos puede dar muchos quebraderos de cabeza. Los archivos ".png" tienen que tener resoluciones múltiplos de 4, en caso contrario simplemente no aparecerá nada. Esto es algo que a mí me trajo de calle hasta que lo leí en un foro.

1.- Como enlazar una imagen en el programa:

Para enlazar una imagen en el programa debéis copiar dicha imagen en una subcarpeta llamada DATA y vuestro archivo makefile debe estar preparado para incluirlo. El archivo makefile que incluyo en el zip está preparado para enlazar todos los archivos de imagen más comunes.

Una vez tenemos nuestro archivo en la carpeta data, cuando compilemos el programa nos generará automáticamente un archivo .h con una variable que contendrá el contenido de dicho archivo de imagen. Si el nombre de la imagen era "imagen.png" el nombre del archivo será "imagen_png.h" y el nombre de la variable que contendrá será "imagen". Además nos añadirá una variable llamada "imagen_size" que indicará el tamaño total.

Una vez hecho esto utilizaremos la función GRRLIB_LoadTexture, de la siguiente forma:

GRRLIB_texImg * mitextura = GRRLIB_LoadTexture (imagen_png);

Dicha función lee la imagen que tenemos en memoria y devuelve una variable texImg* que es el formato que utiliza GRRLIB para manejar texturas.

2.- Como cargar la imagen desde la SD

Como había dicho al principio, en lugar de lo anterior, podemos usar la función GRRLIB_LoadTextureFromFile pasandole el nombre del archivo para leer directamente la imagen desde la SD.

En nuestro ejemplo sería:

GRRLIB_texImg * mitextura = GRRLIB_LoadTextureFromFile ("imagen.png");

Mostrando la imagen que tenemos en memoria.

Independientemente de que hayamos utilizado cualquiera de los dos métodos para crear nuestra variable de textura y ya dentro del bucle while deberemos llamar a la función GRRLIB_DrawImg que tiene la siguiente sintáxis:

GRRLIB_DrawImg (const f32 xpos, const f3  ypos, const GRRLIB_texImg * tex, const f32 degrees, const f32 scaleX, const f32 scaleY, const u32 color) 
 
xpos, ypos: Posición en pantalla de la imagen
tex: variable de textura a visualizar.
degrees: Angulo de rotación de la textura a mostrar en grados.
scalex, scaley: Escala x e y de visualización de la textura.
color: Con este parámetro podemos cambiar la tonalidad de la textura e incluso darle transparencia. 

Como véis tenemos parametros para poder girar la imagen, escalarla o incluso darle tonalidad con el parámetro color.

El parámetro color usa formato RGBA al igual que en las funciones 2D que vimos en la entrega anterior. Si queremos que la imagen se muestre sin modificar utilizaremos el color blanco sin transparencias, es decir 0xFFFFFFFF.

Si queremos darle tonalidad modificaremos los componentes RGB, por ejemplo para darle tonalidad roja intensa el color utilizado sería 0xFF0000FF.

Para darle cierto grado de transparencia utilizaremos el canal alfa, es decir, los dos últimos dígitos. Cuanto más bajo sea el valor más transparente. Ejemplo: 0x00FFFF70 le daría una tonalidad cyan semitransparente.

Pero en nuestro ejemplo queremos una imagen opaca, por lo que la llamaremos de la siguientes forma:

GRRLIB_DrawImg (0,0, mitextura,0,1,1,0xFFFFFFFF)      

Al final del programa, debemos liberar la memoria de la variable de textura con la función GRRLIB_FreeTexture.

GRRLIB_FreeTexture(mitextura);

Resumiendo, el código básico de ambas alternativas sería el que sigue:

Opción 1: Enlazado de las imagenes en el .dol.

#include <grrlib.h>
#include <stdlib.h>
#include <wiiuse/wpad.h>
#include "imagen_png.h"
 
int main(int argc, char **argv) {
	// Inicializar gráficos
	GRRLIB_Init();
 
	GRRLIB_texImg* mitextura = GRRLIB_LoadTexture(imagen_png);
 
	while(1){
		if (WPAD_ButtonsDown(0) & WPAD_BUTTON_HOME)  break;
		GRRLIB_DrawImg(0,0,mitextura,0,1,1, 0xFFFFFFFF);
		GRRLIB_Render();  // Refrescamos la pantalla		
	}
	GRRLIB_FreeTexture(mitextura);
    GRRLIB_Exit(); // Liberamos memoria
 
    exit(0);  // Usar exit para salir del program (no usar return desde el main)
}

Opción 2: Lectura de las imagenes desde la SD.

#include <grrlib.h>
#include <stdlib.h>
#include <wiiuse/wpad.h>
 
int main(int argc, char **argv) {
	// Inicializar gráficos
	GRRLIB_Init();
 
	GRRLIB_texImg* mitextura = GRRLIB_LoadTextureFromFile("imagen.png");
 
	while(1){
		if (WPAD_ButtonsDown(0) & WPAD_BUTTON_HOME)  break;
		GRRLIB_DrawImg(0,0,mitextura,0,1,1, 0xFFFFFFFF);
		GRRLIB_Render();  // Refrescamos la pantalla		
	}
	GRRLIB_FreeTexture(mitextura);
    GRRLIB_Exit(); // Liberamos memoria
 
    exit(0);  // Usar exit para salir del program (no usar return desde el main)
}

En el caso de querer mostrar únicamente un trozo de la textura que tenemos en memoria deberíamos utilizar la función GRRLIB_DrawPart.

void GRRLIB_DrawPart (const f32 xpos, const f32 ypos, const f32 partx, const f32 party, const f32 partw, const f32 parth, const GRRLIB_texImg *tex, const f32 degrees, const f32 scaleX, const f32 scaleY, const u32 color)

La función GRRLIB_DrawPart tiene los mismos parámetros que GRRLIB_DrawImage y además cuatro parámetros que nos permitirán especificar la porción de imagen que queremos mostrar:

  • partx, party: coordenadas x,y de la esquina superior izquierda de la porción a mostrar.
  • partw, parth: Anchura y altura de la porción a mostrar.

Manejo de los Wiimotes

Todo esto está muy bien, pero para que nuestro programa programa tenga utilidad debe ser capaz de interaccionar con el usuario y para ello debemos saber como controlar los wiimotes.

Aunque ahora ya tienen muchos imitadores, cuando se lanzó la consola Wii los wiimotes fueron un concepto revolucionario y junto con el caracter multijugador de sus juegos, la clave del éxito de la misma.

Si nuestra intención es hacer juegos con auténtico espíritu Wii, debemos explotar los wiimotes al máximo y pensar siempre en el caracter multijugador de nuestros juegos.

Si lo que pretendemos es hacer gráficos impresionantes en 3D que se manejan con dos botones, nos hemos equivocado de consola.

Nuestra consola Wii permite conectar al mismo tiempo hasta un máximo de 4 wiimotes.
Además de botones, un wiimote tiene un acelerómetro y una cámara infrarroja que permite a nuestra consola saber en todo momento su posición y velocidad de movimiento.

Adicionalmente se le pueden añadir accesorios como el nunchuk que añade dos botones adicionales, otro acelerómetro y un joystick analógico. También hay otros muchos accesorios que se pueden añadir en lugar del Nunchuk.

Nosotros nos vamos a centrar en el control del wiimote y el nunchuk, aunque el manejo de, por ejemplo, un mando clásico es identico a lo que aquí se explica.

¿Que información podemos leer de un wiimote?

Un wiimote tiene un total de 11 botones en su parte frontal y un botón adicional en la parte trasera.

También posee un acelerómetro de tres ejes, representados en el gráfico, que permite leer aceleraciones de hasta aproximadamente 3g.

Debido a que este acelerómetro mide la aceleración absoluta, cuando lo tenemos en reposo la lectura de la aceleración en el eje Z es aproximadamente igual a la fuerza de gravedad. Es por eso que nos devolverá valores diferentes de cero cuando lo tengamos en reposo.

                                                     

Además el wiimote tiene una cámara infrarroja que utiliza en conjunción con una barra de sensores infrarrojos que situamos junto al televisor. Estos sensores nos permiten saber en todo momento a que posición de la pantalla del televisor estamos apuntando y utilizar el wiimote como apuntador.

Con toda la información anterior el wiimote nos puede informar en todo momento sobre el angulo que posee respecto a los ejes X, Y y Z.

En el caso del Nunchuk tenemos el acelerómetro funciona de una manera similar y su joystick consiste en dos potenciometros que combinados nos devuelven la posición del joystick en magnitud y ángulo.

Y ¿Como llega toda esa información a nuestra consola?, pues la comunicación de un wiimote con la consola es inalámbrica y se realiza mediante el protocolo Bluetooth, aunque esto realmente no es importante para nosotros ya que lo realizan de manera transparente las bibliotecas.

Pero no os asustéis con la explicación, ya que todo esto es mucho más sencillo de lo que parece.

Existe una biblioteca llamada WPAD que nos facilita enormemente las cosas y hace todos los cálculos necesarios por nosotros, por lo que al final únicamente debemos preocuparnos por los valores de posición ángulo y aceleración.

Para hacer uso de las funciones de WPAD, debemos seguir el siguiente esquema:

#include <stdlib.h>
#include <wiiuse/wpad.h>
 
int main(int argc, char **argv) {
	// Inicializar gráficos
	WPAD_Init();
 
	// ajusta el modo de operación de los PADS activando acelerometros y el IR
	WPAD_SetDataFormat(WPAD_CHAN_ALL, WPAD_FMT_BTNS_ACC_IR);
	// Asigna la resolucion que nos devuelve el IR
	WPAD_SetVRes(WPAD_CHAN_ALL, 640, 520);
 
 
	while(1){
 
		// leemos el tipo de expansión conectada y comprobamos si sigue conectado
		if (WPAD_Probe(pad, &expansion_type) < 0)
			.....mando desconectado......
 
		WPAD_ScanPads();
 
		wmote_data=WPAD_Data(pad);
		if (WPAD_ButtonsDown(0) & WPAD_BUTTON_HOME)  break;
 
		.........
		.........
	}
 
    exit(0);  // Usar exit para salir del program (no usar return desde el main)
}

Como podéis ver en este esquema, lo primero que hacemos es inicializar la biblioteca antes de entrar el el bucle con WPAD_Init().

Después configuraremos el modo de operación de los wiimotes con la función WPAD_SetDataFormat que nos permite seleccionar que partes activamos o no del wiimote.

s32 WPAD_SetDataFormat(s32 chan, s32 fmt);
 
Parámetros.
chan: 
	wiimote a configurar (es un valor de -1 a 4)
	WPAD_CHAN_ALL = -1     : Con este valor configuramos todos los wiimotes
	WPAD_CHAN_0   = 0      : wiimote 1
	WPAD_CHAN_1   = 1      : wiimote 2
	WPAD_CHAN_2   = 2      : wiimote 3
	WPAD_CHAN_3   = 3      : wiimote 4
 
fmt:
	WPAD_FMT_BTNS = 0      : Se activan solo los botones 
	WPAD_FMT_BTNS_ACC = 1  : Se activan botones y acelerometro
	WPAD_FMT_BTNS_ACC_IR=2 : Se activa también el IR

Seguidamente y siguiendo fuera del bucle principal, configuraremos la resolución que utilizará el puntero infrarrojos y que deberemos hacer coincidir con la resolución de pantalla que estemos utilizando.

Para ello utilizaremos la función WPAD_SetVRes que tiene el siguiente formato:

 
s32 WPAD_SetVRes(s32 chan,u32 xres,u32 yres);
Parámetros.
chan: 
	wiimote a configurar (es un valor de -1 a 4)
	WPAD_CHAN_ALL = -1     : Con este valor configuramos todos los wiimotes
	WPAD_CHAN_0   = 0      : wiimote 1
	WPAD_CHAN_1   = 1      : wiimote 2
	WPAD_CHAN_2   = 2      : wiimote 3
	WPAD_CHAN_3   = 3      : wiimote 4
xres: máxima resolución horizontal (habitualmente 640)
yres: máxima resolución vertical (dependiendo del modo de vídeo 480 ó 520)

Una vez dentro del bucle principal utilizaremos tres funciones que recuperarán la información de los wiimotes para poder usarla en nuestro programa. Dichas funciones son WPAD_Probe, WPAD_ScanPads y WPAD_Data.

La función WPAD_Probe tiene un doble propósito. Por un lado nos permite comprobar si un wiimote está conectado, y por el otro nos dice que tipo de expansión tenemos conectada a dicho wiimote.

Su sintáxis es la siguiente:

s32 WPAD_Probe(s32 chan,u32 *type);
chan: wiimote a chequear
type: Tipo de expansión conectada.
		Puede ser uno de los siguientes valores.
		WPAD_EXP_NONE = 0,
		WPAD_EXP_NUNCHUK = 1
		WPAD_EXP_CLASSIC = 2
		WPAD_EXP_GUITARHERO3 = 3
		WPAD_EXP_WIIBOARD = 4
		WPAD_EXP_UNKNOWN = 255
 
Devuelve el estado del wiimote:
		WPAD_ERR_NONE = 0
		WPAD_ERR_NO_CONTROLLER = -1
		WPAD_ERR_NOT_READY = -2
		WPAD_ERR_TRANSFER = -3
		WPAD_ERR_NONEREGISTERED = -4
		WPAD_ERR_UNKNOWN = -5
		WPAD_ERR_BAD_CHANNEL = -6
		WPAD_ERR_QUEUE_EMPTY = -7
		WPAD_ERR_BADVALUE = -8
		WPAD_ERR_BADCONF = -9

Aunque devuelve un estado detallado del error, es suficiente que comprobemos que el valor que devuelve WPAD_Probe es >= 0 para saber si está conectado y preparado.

WPAD_ScanPads() simplemente deberemos llamarla para permitir a WPAD realizar internamente las operaciones necesarias de comunicación vía bluetooth con el wiimote permitir que lea toda su información de estado. De esta manera se actualizará la información que luego nos devolverán el resto de las funciones. Si no llamaramos a esta función los datos devueltos por el resto de las funciones serían siempre los mismos y no corresponderían con el estado del wiimote.

Para recuperar los datos del wiimote utilizaremos la función WPAD_Data. A dicha función le pasaremos como parámetro el wiimote a consultar y nos devolverá un puntero a todos los datos de estado del wiimote.

La estructura de datos devuelta por WPAD_Data es la que sigue:

typedef struct _wpad_data
{
	s16 err;
 
	u32 data_present;        true si contiene datos válidos
	u8 battery_level;          Nivel de carga de la batería
 
	u32 btns_h;                 // Estado de los botones. Utilizaremos preferiblemente
	u32 btns_l;                  // las funciones WPAD_ButtonsDown y WPAD_ButtonsHeld
	u32 btns_d;                 // en su lugar
	u32 btns_u;
 
	struct ir_t ir;                 // Datos de posición y ángulo del IR
	struct vec3w_t accel;     // vector de aceleración (x,y,z)
	struct orient_t orient;    // orientación del wiimote
	struct gforce_t gforce;   // vector de la fuerza de la gravedad
	struct expansion_t exp;// datos de la expansión conectada
} WPADData;

Veremos en detalle la utilización de cada uno de estos campos más adelante.

Por último comentar que utilizaremos las funciones WPAD_ButtonsHeld, y WPAD_ButtonsDown la utilización de ambas es la misma debiendo pasar como parámetro el wiimote que queremos consultar, devolviendo los botones pulsados.

WPAD_ButtonsHeld devolverá el valor true desde el momento que el botón está pulsado y hasta que es soltado, mientras que WPAD_ButtonsDown devolverá true cuando se pulse, pero sólo una vez devolviendo false a partir de ese momento y hasta que lo soltemos y lo volvamos a pulsar.

Utilizaremos WPAD_ButtonsHeld sobre todo en juegos, mientras que WPAD_ButtonsDown nos será útil en la selección de las opciones de un menú para no pulsar varias veces una opción accidentalmente.

Existe aún otra función que nos permite saber cuando soltamos un botón. Esta es la función WPAD_ButtonsUp cuya utilización es de nuevo idéntica a WPAD_ButtonsHeldWPAD_ButtonsDown. Podemos ver a WPAD_ButtonsUp  como la operación contraria de WPAD_ButtonsDown.

Existen una serie de funciones auxiliares que podemos utilizar en lugar de consultar los campos de la variable que devuelve WPAD_Data. Realmente son funciones redundantes, pero pueden resultar algo más claras dependiendo de que situación.

Pasaré a dar un listado de dichas funciones junto con su descripción:

 

u8 WPAD_BatteryLevel(int chan);   // Devuelve el estado de la bateria
 
 
void WPAD_IR(int chan, struct ir_t *ir); 
   Devuelve la posición y el ángulo del IR
   Aunque la estructura ir_t tiene muchos campos únicamente utilizaremos los
   campos x e y que nos devuelve la posición a la que apunta el wiimote.
 
 
void WPAD_Orientation(int chan, struct orient_t *orient);
   Devuelve el angulo de giro respecto de cada eje
   De orien_t nos interesan los campos roll y pitch
   roll representa el ángulo de giro respecto del eje Y
   pitch representa el ángulo de giro respecto del eje X
   Ambos valores los devuelve en grados y son de tipo float
 
void WPAD_GForce(int chan, struct gforce_t *gforce);
   El valor devuelto en gforce es el vector fuerza de gravedad
   La estructura de gforce_t es como sigue
   typedef struct gforce_t {
      float x, y, z;
   } gforce_t;
 
void WPAD_Accel(int chan, struct vec3w_t *accel);
   El valor devuelto en accel es el vector de aceleración del wiimote
   typedef struct vec3w_t {
      uword x, y, z;
   } vec3w_t;
 
 
void WPAD_Expansion(int chan, struct expansion_t *exp);
   devuelve los valores específicos de expansión conectada en una variable tipo expansion_t
   typedef struct expansion_t {
     int type;	/* Tipo de expansión conectada */
       union {
         struct nunchuk_t nunchuk;
         struct classic_ctrl_t classic;
         struct guitar_hero_3_t gh3;
         struct wii_board_t wb;
         struct motion_plus_t mp;
       };
   } expansion_t;

Vamos a detenernos un poco en la estructura expansion_t.

La estructura expansión_t tiene dos campos, el primero es el tipo de expansión conectada y el segundo es del tipo union que en C permite tener un tipo de datos variable. Como ejemplo, si tenemos conectado el NunChuk nos devolverá la estructura nunchuk del tipo nunchuk_t que tiene el siguiente formato:

typedef struct nunchuk_t {
	struct accel_t accel_calib;		/**< nunchuk accelerometer calibration		*/
	struct joystick_t js;			/**< joystick calibration				*/
 
	int* flags;					/**< options flag (points to wiimote_t.flags) */
 
	ubyte btns;				/**< what buttons have just been pressed	*/
	ubyte btns_last;				/**< what buttons have just been pressed	*/
	ubyte btns_held;				/**< what buttons are being held down		*/
	ubyte btns_released;			/**< what buttons were just released this	*/
 
	struct vec3w_t accel;			/**< current raw acceleration data			*/
	struct orient_t orient;			/**< current orientation on each axis		*/
	struct gforce_t gforce;			/**< current gravity forces on each axis	*/
} nunchuk_t;

El campo js de dicha estructura es del tipo joystick_t. Los únicos campos que nos interesan son el campo mag y el campo ang. El campo mag contiene el ángulo del joystick y el campo mag (magnitud) indica lo separado que se encuentra el joystick de su centro 

typedef struct joystick_t {
	struct vec2b_t max;		/**< maximum joystick values	*/
	struct vec2b_t min;		/**< minimum joystick values	*/
	struct vec2b_t center;		/**< center joystick values		*/
	struct vec2b_t pos;		/**< raw position values        */
 
	float ang;				/**< ángulo del joystick		*/
	float mag;				/**< magnitud del joystick (rango 0-1)	*/
} joystick_t;

Al igual que _wpad_data La estructura nunchuck_t tiene dos campos que nos interesan, llamados accel, orient y gforce y cuyo contenido indica la aceleración, la orientación y la fuerza de la gravedad.

Veremos en nuestro programa de ejemplo como utilizar orient para el caso del wiimote, aunque para el nunchuk la utilización es idéntica.

Como deciamos antes la estructura expansion_t tiene un campo de tipo union. Las uniones son un tipo especial de estructuras que permiten almacenar elementos de diferentes tipos en las mismas posiciones de memoria, aunque evidentemente no simultáneamente. 

Para que lo entendáis, en nuestro caso la estructura expansion_t siempre contendrá un campo type, pero dependiendo del valor de type la información que le sigue podrá ser la del nunchuk (nunchuk_t nunchuck), la del mando clásico (classic_ctrl_t classic), la de la guitarra del guitar hero (guitar_hero_3_t gh3), la del balanceboard (wiiboard_t wb) o la del motion plus (motion_plus_t mp).

Por ejemplo, en el caso de que utilicemos en nunchuk la estructura de expansion_t sería equivalente a lo siguiente:

expansion_t
   typedef struct expansion_t {
     int type;	/* Tipo de expansión conectada */
     struct nunchuk_t nunchuk;
   } expansion_t;

Osea que si hubieramos llamado a la función WPAD_Expansion de la siguiente forma:

WPAD_Expansion(0, exp);

Podríamos acceder a la información del joystick del nunchuck como exp->nunchuck.js.

Funciones para comprobar posición

Existen tres funciones en GRRLIB que nos permitirán comprobar la coincidencia en la posición entre dos objetos. La utilidad más evidente de estas funciones en un programa como el de nuestro ejemplo es la de comprobar cuando el puntero del wiimote pasa por un determinado punto, aunque son muy utiles en otros casos como la detección de colisiones en juegos.

La función GRRLIB_PtInRect nos permite detectar cuando un punto está situado dentro de un rectángulo, para lo cual le hemos de pasar las coordenadas del rectángulo y del punto respectívamente.

bool GRRLIB_PtInRect	(	const int 	hotx,
const int 	hoty,
const int 	hotw,
const int 	hoth,
const int 	wpadx,
const int 	wpady 
)		
 
Parametros:
hotx	coordenada x de la esquina superior izquierda del rectángulo.
hoty	coordenada y de la esquina superior izquierda del rectángulo
hotw	anchura del rectángulo
hoth	Altura del rectángulo
wpadx	coordenada x del punto
wpady	coordenada y del punto
Devuelve:
Si el punto especificado cae dentro del rectángulo devuelve true, en caso contrario false.

La función GRRLIB_RectInRect especifica cuando un rectangulo está totalmente dentro de otro.

bool GRRLIB_RectInRect (
const int rect1x, 
const int rect1y, 
const int rect1w,
const int rect1h,
const int rect2x,
const int rect2y,
const int rect2w,
const int rect2h 
)		
 
Parametros:
rect1x	coordenada x de la esquina superior izquierda del primer rectángulo.
rect1y	coordenada y de la esquina superior izquierda del primer rectángulo
rect1w	anchura del primer rectángulo
rect1h	Altura del primer rectángulo
rect2x	coordenada x de la esquina superior izquierda del primer rectángulo.
rect2y	coordenada y de la esquina superior izquierda del primer rectángulo
rect2w	anchura del primer rectángulo
rect2h	Altura del primer rectángulo
Devuelve:
Si el rectangulo cae dentro del otro rectángulo devuelve true, en caso contrario false.
La función GRRLIB_RectOnRect especifica cuando un rectangulo está total o parcialmente dentro de otro.
bool GRRLIB_RectOnRect (
const int rect1x, 
const int rect1y, 
const int rect1w,
const int rect1h,
const int rect2x,
const int rect2y,
const int rect2w,
const int rect2h 
)		
 
Parametros:
rect1x	coordenada x de la esquina superior izquierda del primer rectángulo.
rect1y	coordenada y de la esquina superior izquierda del primer rectángulo
rect1w	anchura del primer rectángulo
rect1h	Altura del primer rectángulo
rect2x	coordenada x de la esquina superior izquierda del primer rectángulo.
rect2y	coordenada y de la esquina superior izquierda del primer rectángulo
rect2w	anchura del primer rectángulo
rect2h	Altura del primer rectángulo
Devuelve:
Si el rectangulo cae parcial o totalmente dentro del otro rectángulo devuelve true, en caso contrario false.

Veamos nuestro programa en detalle

Para la creación de nuestro YABT, necesitaremos de algunas texturas auxiliares que os he preparado en el zip adjunto y que deberemos copiar en la carpeta data.

He elegido el formato png porque nos permite definir zonas transparentes lo cual es muy útil a la hora de hacer sprites. Recordad que todos los gráficos tienen resoluciones x e y múltiplos de 4.

Como vimos al principio de la entrega, al incluir esos archivos en la carpeta data, nuestro compilador nos creará sendos archivos .h que deberemos incluir en nuestro programa para poder utilizarlos.

#include "botona_png.h"
#include "botonb_png.h"
#include "botonc_png.h"
#include "botonz_png.h"
#include "botonhome_png.h"
#include "botonuno_png.h"
#include "botondos_png.h"
#include "botonmas_png.h"
#include "botonmenos_png.h"
#include "botonarriba_png.h"
#include "botonabajo_png.h"
#include "botonizq_png.h"
#include "botonder_png.h"
#include "joy_png.h"
#include "nunchuk_png.h"
#include "nunchukback_png.h"
#include "wiimote_png.h"
#include "wiimoteside_png.h"
#include "wiimotefront_png.h"
#include "wiimotedown_png.h"
#include "wiimoteback_png.h"
#include "pointer_png.h"
#include "ladrillos_jpg.h"

Definimos algunas variables globales que utilizaremos.

GRRLIB_ttfFont *myFont;    // variable que contendrá la fuente truetype
bool padstatus[4];             // array destinado a contener los wiimotes conectados
u32 pad;                          // wiimote que estamos gestionando

Una vez en el main definiremos agunas variables auxiliares que nos harán falta a lo largo del programa:

	u32 expansion_type;          // tipo de expansión conectada
	WPADData * wmote_data;   // información del wiimote
	ir_t ir;                               // información del sensor IR
 
	int resx = 640; int resy=520; // resolución en modo PAL

Seguidamente pasamos a inicilizar las GRRLIB, WPAD y los wiimotes tal y como hemos aprendido:

	// Inicializar gráficos
	GRRLIB_Init();
 
	// Inicializar wiimotes
	WPAD_Init();
	WPAD_SetDataFormat(WPAD_CHAN_ALL, WPAD_FMT_BTNS_ACC_IR);
	WPAD_SetVRes(WPAD_CHAN_ALL, resx, resy);

Inicializamos la fuente truetype que utilizaremos y calculamos la posición en la que debemos situar el título para que quede centrado.

	myFont = GRRLIB_LoadTTF(verdana_ttf, verdana_ttf_size); // lo convertimos al formato usado por GRRLIB
 
	int centro = (640-GRRLIB_WidthTTF(myFont, _TITLE, 20))/2; // calculamos la posición de partida del título para que quede centrado en pantalla

Creamos todas las variables de textura a partir de los archivos de imagen.

	GRRLIB_texImg* tex_botona = GRRLIB_LoadTexture(botona_png);
	GRRLIB_texImg* tex_botonb = GRRLIB_LoadTexture(botonb_png);
	GRRLIB_texImg* tex_botonc = GRRLIB_LoadTexture(botonc_png);
	GRRLIB_texImg* tex_botonz = GRRLIB_LoadTexture(botonz_png);
	GRRLIB_texImg* tex_botonhome = GRRLIB_LoadTexture(botonhome_png);
	GRRLIB_texImg* tex_botonuno = GRRLIB_LoadTexture(botonuno_png);
	GRRLIB_texImg* tex_botondos = GRRLIB_LoadTexture(botondos_png);
	GRRLIB_texImg* tex_botonmas = GRRLIB_LoadTexture(botonmas_png);
	GRRLIB_texImg* tex_botonmenos = GRRLIB_LoadTexture(botonmenos_png);
	GRRLIB_texImg* tex_botonarriba = GRRLIB_LoadTexture(botonarriba_png);
	GRRLIB_texImg* tex_botonabajo = GRRLIB_LoadTexture(botonabajo_png);
	GRRLIB_texImg* tex_botonizq = GRRLIB_LoadTexture(botonizq_png);
	GRRLIB_texImg* tex_botonder = GRRLIB_LoadTexture(botonder_png);
	GRRLIB_texImg* tex_wiimote = GRRLIB_LoadTexture(wiimote_png);
	GRRLIB_texImg* tex_wiimotedown = GRRLIB_LoadTexture(wiimotedown_png);
	GRRLIB_texImg* tex_wiimoteside = GRRLIB_LoadTexture(wiimoteside_png);
	GRRLIB_texImg* tex_wiimotefront = GRRLIB_LoadTexture(wiimotefront_png);
	GRRLIB_texImg* tex_wiimoteback = GRRLIB_LoadTexture(wiimoteback_png);
	GRRLIB_texImg* tex_nunchuk = GRRLIB_LoadTexture(nunchuk_png);
	GRRLIB_texImg* tex_nunchukback = GRRLIB_LoadTexture(nunchukback_png);
	GRRLIB_texImg* tex_joy = GRRLIB_LoadTexture(joy_png);
	GRRLIB_texImg* tex_pointer = GRRLIB_LoadTexture(pointer_png);
	GRRLIB_texImg* tex_ladrillos = GRRLIB_LoadTexture(ladrillos_jpg);

 

La variable pad la utilizamos para memorizar el wiimote que estamos gestionando. Empezamos seleccionando el wiimote 0

	pad = 0;
 

Ya dentro del bucle rellenamos los valores del array padstatus con el valor de estado de cada uno de los wiimotes.

Para ello utilizamos la función WPAD_Probe, llamándola una vez más al salir del bucle para memorizar la expansión conectada al mando activo.

		// Comprobamos el estado de los wiimotes
		int i = 0;
		for(i=0;i<4;i++) 
			padstatus[i]=(WPAD_Probe(i, &expansion_type)>=0);
 
		// leemos el tipo de expansión conectada
		WPAD_Probe(pad, &expansion_type);

Llamamos a ScanPads para que la se actualice la información de los wiimotes y leemos dicha información con WPAD_Data y WPAD_IR.

		WPAD_ScanPads();  // Leer mandos
 		// recoge los datos extra del wiimote
		wmote_data=WPAD_Data(pad);
		WPAD_IR(pad, &ir);

Comprobamos el botón home como viene siendo habitual

        // Si pulsamos home salimos del bucle
		if (WPAD_ButtonsDown(pad) & WPAD_BUTTON_HOME)  break;

El siguiente código son dos bucles anidados que rellenan la pantalla con la textura ladrillos.jpg. Como podéis ver se utilizan la anchura (tex_ladrillos->w) y la altura (tex_ladrillos->h) de la textura como paso de cada bucle.

		int pasox = tex_ladrillos->w;
		int pasoy = tex_ladrillos->h;
		int x, y;
		for (x=0; x<resx; x+=pasox)
			for (y=0; y<resy; y+=pasoy){
				GRRLIB_DrawImg(x,y,tex_ladrillos,0,1,1, GRRLIB_WHITE);
			}

Si tenemos conectado un nunchuck en el wiimote activo mostramos todos los elementos y botones del nunchuck

		if (expansion_type==WPAD_EXP_NUNCHUK){
			if (WPAD_ButtonsHeld(pad) & WPAD_NUNCHUK_BUTTON_C)
				GRRLIB_DrawImg(199,130,tex_botonc,0,1,1, GRRLIB_SILVER);
			else
				GRRLIB_DrawImg(200,128,tex_botonc,0,1,1, GRRLIB_WHITE);
			if (WPAD_ButtonsHeld(pad) & WPAD_NUNCHUK_BUTTON_Z)
				GRRLIB_DrawImg(209,141,tex_botonz,0,1,1, GRRLIB_SILVER);
			else
				GRRLIB_DrawImg(211,138,tex_botonz,0,1,1, GRRLIB_WHITE);
			GRRLIB_DrawImg(70,130,tex_nunchuk,0,1,1, GRRLIB_WHITE);
			GRRLIB_DrawImg(150,130,tex_nunchukback,0,1,1, GRRLIB_WHITE);
 
 
			float t = DegToRad(wmote_data->exp.nunchuk.js.ang-90);
			float jx = cos(t)*wmote_data->exp.nunchuk.js.mag*10;
			float jy = sin(t)*wmote_data->exp.nunchuk.js.mag*10;
			GRRLIB_DrawImg(102+jx,162+jy,tex_joy,0,1.5,1.5, GRRLIB_WHITE);
		}

Como podéis ver para cada botón, para crear un efecto que simule que apretamos dicho botón, desplazamos ligeramente la textura y para acentuar el efecto la oscurecemos ligeramente utilizando el color GRRLIB_SILVER.

En el caso del Joystick debemos recurrir a las matemáticas para situar nuestro joystick en pantalla.

Partimos de la información que tenemos en la variable wmote_data.

Si consideramos nuestro joystik como una circunferencia wmote_data->exp.nunchuk.js.ang nos informa del ángulo sobre el que tenemos situado el joystick siendo 0 la posición superior.

Por otro lado tenemos que wmote_data->exp.nunchuk.js.mag nos devuelve lo separado que está el joystick del centro.

                                                     

Echando mano de la ecuación de la circunferencia en coordenadas polares:

                                     

Podremos calcular la posición que le corresponde en pantalla.

Pero antes tendremos que tener en cuenta dos cosas:

  1. La ecuación considera como angulo 0 el eje positivo de las x por lo que deberemos restar 90º al ángulo devuelto por el wiimote
  2. Las funciones sin y cos de C necesitan el ángulo en radianes y no en grados por lo que utilizaremos la función DegToRad que nos hace la conversión requerida.

Para el caso de los botones del wiimote utilizaremos el escalado de las texturas para acentuar el efecto de presionado, pero por lo demás utilizaremos exactamente la misma técnica que en el caso del Nunchuk.

		GRRLIB_DrawImg(350,80,tex_wiimote,0,1,1, GRRLIB_WHITE);
		if (WPAD_ButtonsHeld(pad) & WPAD_BUTTON_UP)
			GRRLIB_DrawImg(380,110,tex_botonarriba,0,0.95,0.95, GRRLIB_SILVER);
		else
			GRRLIB_DrawImg(380,110,tex_botonarriba,0,1,1, GRRLIB_WHITE);
		if (WPAD_ButtonsHeld(pad) & WPAD_BUTTON_DOWN)
			GRRLIB_DrawImg(380,134,tex_botonabajo,0,0.95,0.95, GRRLIB_SILVER);
		else
			GRRLIB_DrawImg(380,134,tex_botonabajo,0,1,1, GRRLIB_WHITE);
		if (WPAD_ButtonsHeld(pad) & WPAD_BUTTON_LEFT)
			GRRLIB_DrawImg(368,122,tex_botonizq,0,0.95,0.95, GRRLIB_SILVER);
		else
			GRRLIB_DrawImg(368,122,tex_botonizq,0,1,1, GRRLIB_WHITE);
		if (WPAD_ButtonsHeld(pad) & WPAD_BUTTON_RIGHT)
			GRRLIB_DrawImg(393,122,tex_botonder,0,0.95,0.95, GRRLIB_SILVER);
		else
			GRRLIB_DrawImg(393,122,tex_botonder,0,1,1, GRRLIB_WHITE);
		if (WPAD_ButtonsHeld(pad) & WPAD_BUTTON_A)
			GRRLIB_DrawImg(374,161,tex_botona,0,0.95,0.95, GRRLIB_SILVER);
		else
			GRRLIB_DrawImg(374,161,tex_botona,0,1,1, GRRLIB_WHITE);
		if (WPAD_ButtonsHeld(pad) & WPAD_BUTTON_PLUS)
			GRRLIB_DrawImg(404,217,tex_botonmas,0,0.95,0.95, GRRLIB_SILVER);
		else
			GRRLIB_DrawImg(404,217,tex_botonmas,0,1,1, GRRLIB_WHITE);
		if (WPAD_ButtonsHeld(pad) & WPAD_BUTTON_MINUS)
			GRRLIB_DrawImg(359,217,tex_botonmenos,0,0.95,0.95, GRRLIB_SILVER);
		else
			GRRLIB_DrawImg(359,217,tex_botonmenos,0,1,1, GRRLIB_WHITE);
		if (WPAD_ButtonsHeld(pad) & WPAD_BUTTON_HOME)
			GRRLIB_DrawImg(380,216,tex_botonhome,0,0.95,0.95, GRRLIB_SILVER);
		else
			GRRLIB_DrawImg(380,216,tex_botonhome,0,1,1, GRRLIB_WHITE);
		if (WPAD_ButtonsHeld(pad) & WPAD_BUTTON_1)
			GRRLIB_DrawImg(378,293,tex_botonuno,0,0.95,0.95, GRRLIB_SILVER);
		else
			GRRLIB_DrawImg(378,293,tex_botonuno,0,1,1, GRRLIB_WHITE);
		if (WPAD_ButtonsHeld(pad) & WPAD_BUTTON_2)
			GRRLIB_DrawImg(378,320,tex_botondos,0,0.95,0.95, GRRLIB_SILVER);
		else
			GRRLIB_DrawImg(378,320,tex_botondos,0,1,1, GRRLIB_WHITE);
		GRRLIB_DrawImg(480,80,tex_wiimoteback,0,1,1, GRRLIB_WHITE);
		if (WPAD_ButtonsHeld(pad) & WPAD_BUTTON_B)
			GRRLIB_DrawImg(501,129,tex_botonb,0,1,0.95, GRRLIB_SILVER);
		else
			GRRLIB_DrawImg(501,129,tex_botonb,0,1,1, GRRLIB_WHITE);

Para representar el ángulo sobre los ejes X e Y utilizaremos la información guardada en wmote_data->orient.pitch y wmote_data->orient.roll. 

Para que el giro se haga sobre el centro de la textura utilizaremos la función GRRLIB_SetMidHandle ya que en caso contrario el centro de rotación sería la esquina superior izquierda.

		GRRLIB_SetMidHandle(tex_wiimoteside, true);
		GRRLIB_SetMidHandle(tex_wiimotedown, true);
		GRRLIB_DrawImg(385, 450, tex_wiimoteside, -wmote_data->orient.pitch, 1, 1, GRRLIB_WHITE);
		GRRLIB_DrawImg(515, 450, tex_wiimotedown, wmote_data->orient.roll, 1, 1, GRRLIB_WHITE);

El siguiente bucle representa todos los wiimotes conectados y preparados, representándolos con una función que hemos creado al efecto llamada Draw_PadStatus. Dicha función colorea el recuadro de blanco en el caso de que se trate del wiimote activo y de azul en caso contrario.

		for (i = 0; i<4; i++) {
			Draw_PadStatus(30+i*30, 450, i);
			if (padstatus[i] && (WPAD_ButtonsHeld(pad) & WPAD_BUTTON_A))
				if (GRRLIB_RectInRect(ir.x,ir.y,5,5, 30+i*30-5, 450, 20, 25))
					pad = i;
		}

void Draw_PadStatus(int x, int y, int v){
	char s[5];
	sprintf(s, "%d", v+1);
	if (padstatus[v]){
		if (v==pad){
			GRRLIB_Rectangle(x-5, y, 20, 25, GRRLIB_WHITE, true);
			GRRLIB_Rectangle(x-5, y, 20, 25, GRRLIB_NAVY, false);
			GRRLIB_PrintfTTF(x, y, myFont, s, 20, GRRLIB_NAVY);
		} else {
			GRRLIB_Rectangle(x-5, y, 20, 25, GRRLIB_NAVY, true);
			GRRLIB_Rectangle(x-5, y, 20, 25, GRRLIB_WHITE, false);
			GRRLIB_PrintfTTF(x, y, myFont, s, 20, GRRLIB_WHITE);
		}
	}
}

Dentro del mismo bucle usamos la función GRRLIB_RectInRect para comprobar si tenemos situado el puntero sobre el cuadro correspondiente a uno de los wiimotes. En ese caso y si pulsamos A cambiaremos el pad activo.

Para representar el pad activo sobre la imagen frontal de nuestro wiimote dibujaremos un pequeño cuadrado azul a la altura de los leds.

		// Dibuja el led correspondiente al pad activo
		GRRLIB_Rectangle(350+16+13*pad,80+268, 5, 5, GRRLIB_LBLUE, true);

Finalmente escribimos el título de nuestro programa sobre un marco de color púrpura.

Finalmente liberamos la memoria ocupada por las texturas y por la propia GRRLIB para acabar saliendo del programa.

	GRRLIB_FreeTexture(tex_botona);
	GRRLIB_FreeTexture(tex_botonb);
	GRRLIB_FreeTexture(tex_botonc);
	GRRLIB_FreeTexture(tex_botonz);
	GRRLIB_FreeTexture(tex_botonhome);
 	GRRLIB_FreeTexture(tex_botonarriba);
	GRRLIB_FreeTexture(tex_botonabajo);
	GRRLIB_FreeTexture(tex_botonder);
	GRRLIB_FreeTexture(tex_botonizq);
	GRRLIB_FreeTexture(tex_botonuno);
	GRRLIB_FreeTexture(tex_botondos);
	GRRLIB_FreeTexture(tex_botonmas);
	GRRLIB_FreeTexture(tex_botonmenos);
	GRRLIB_FreeTexture(tex_joy);
	GRRLIB_FreeTexture(tex_ladrillos);
	GRRLIB_FreeTexture(tex_pointer);
	GRRLIB_FreeTexture(tex_nunchuk);
	GRRLIB_FreeTexture(tex_nunchukback);
	GRRLIB_FreeTexture(tex_wiimote);
	GRRLIB_FreeTexture(tex_wiimoteside);
	GRRLIB_FreeTexture(tex_wiimotedown);
	GRRLIB_FreeTexture(tex_wiimotefront);
	GRRLIB_FreeTexture(tex_wiimoteback);
 
    GRRLIB_Exit(); // Liberamos memoria
 
    exit(0);  // Usar exit para salir del program (no usar return desde el main)

El resultado final será un button tester que nos permitirá seleccionar el número de wiimote a testear, permitiendo además testear los ángulos de giro del wiimote y los botones y joystick del nunchuk.

El código completo del programa quedaría como sigue:

#include <grrlib.h>
#include <stdlib.h>
#include <wiiuse/wpad.h>
#include "verdana_ttf.h"
#include "botona_png.h"
#include "botonb_png.h"
#include "botonc_png.h"
#include "botonz_png.h"
#include "botonhome_png.h"
#include "botonuno_png.h"
#include "botondos_png.h"
#include "botonmas_png.h"
#include "botonmenos_png.h"
#include "botonarriba_png.h"
#include "botonabajo_png.h"
#include "botonizq_png.h"
#include "botonder_png.h"
#include "joy_png.h"
#include "nunchuk_png.h"
#include "nunchukback_png.h"
#include "wiimote_png.h"
#include "wiimoteside_png.h"
#include "wiimotefront_png.h"
#include "wiimotedown_png.h"
#include "wiimoteback_png.h"
#include "pointer_png.h"
#include "ladrillos_jpg.h"
 
 
// Colores RGBA
#define GRRLIB_BLACK   0x000000FF
#define GRRLIB_MAROON  0x800000FF
#define GRRLIB_GREEN   0x008000FF
#define GRRLIB_OLIVE   0x808000FF
#define GRRLIB_NAVY    0x000080FF
#define GRRLIB_PURPLE  0x800080FF
#define GRRLIB_TEAL    0x008080FF
#define GRRLIB_GRAY    0x808080FF
#define GRRLIB_SILVER  0xC0C0C0FF
#define GRRLIB_RED     0xFF0000FF
#define GRRLIB_LIME    0x00FF00FF
#define GRRLIB_YELLOW  0xFFFF00FF
#define GRRLIB_BLUE    0x0000FFFF
#define GRRLIB_FUCHSIA 0xFF00FFFF
#define GRRLIB_AQUA    0x00FFFFFF
#define GRRLIB_WHITE   0xFFFFFFFF
#define GRRLIB_LBLUE   0x5050FFFF
 
#define _TITLE "YABT - YET ANOTHER BUTTON TESTER"
 
GRRLIB_ttfFont *myFont;
bool padstatus[4];
u32 pad;
 
 
void Draw_PadStatus(int x, int y, int v){
	char s[5];
	sprintf(s, "%d", v+1);
	if (padstatus[v]){
		if (v==pad){
			GRRLIB_Rectangle(x-5, y, 20, 25, GRRLIB_WHITE, true);
			GRRLIB_Rectangle(x-5, y, 20, 25, GRRLIB_NAVY, false);
			GRRLIB_PrintfTTF(x, y, myFont, s, 20, GRRLIB_NAVY);
		} else {
			GRRLIB_Rectangle(x-5, y, 20, 25, GRRLIB_NAVY, true);
			GRRLIB_Rectangle(x-5, y, 20, 25, GRRLIB_WHITE, false);
			GRRLIB_PrintfTTF(x, y, myFont, s, 20, GRRLIB_WHITE);
		}
	}
}
 
 
 
int main(int argc, char **argv) {
 
	u32 expansion_type;
	WPADData * wmote_data;
	ir_t ir;
 
	int resx = 640; int resy=520;
 
	// Inicializar gráficos
	GRRLIB_Init();
 
	// Inicializar wiimotes
	WPAD_Init();
	WPAD_SetDataFormat(WPAD_CHAN_ALL, WPAD_FMT_BTNS_ACC_IR);
	WPAD_SetVRes(WPAD_CHAN_ALL, resx, resy);
 
 
	myFont = GRRLIB_LoadTTF(verdana_ttf, verdana_ttf_size); // lo convertimos al formato usado por GRRLIB
 
	int centro = (640-GRRLIB_WidthTTF(myFont, _TITLE, 20))/2; // calculamos el centro de la pantalla
 
	GRRLIB_texImg* tex_botona = GRRLIB_LoadTexture(botona_png);
	GRRLIB_texImg* tex_botonb = GRRLIB_LoadTexture(botonb_png);
	GRRLIB_texImg* tex_botonc = GRRLIB_LoadTexture(botonc_png);
	GRRLIB_texImg* tex_botonz = GRRLIB_LoadTexture(botonz_png);
	GRRLIB_texImg* tex_botonhome = GRRLIB_LoadTexture(botonhome_png);
	GRRLIB_texImg* tex_botonuno = GRRLIB_LoadTexture(botonuno_png);
	GRRLIB_texImg* tex_botondos = GRRLIB_LoadTexture(botondos_png);
	GRRLIB_texImg* tex_botonmas = GRRLIB_LoadTexture(botonmas_png);
	GRRLIB_texImg* tex_botonmenos = GRRLIB_LoadTexture(botonmenos_png);
	GRRLIB_texImg* tex_botonarriba = GRRLIB_LoadTexture(botonarriba_png);
	GRRLIB_texImg* tex_botonabajo = GRRLIB_LoadTexture(botonabajo_png);
	GRRLIB_texImg* tex_botonizq = GRRLIB_LoadTexture(botonizq_png);
	GRRLIB_texImg* tex_botonder = GRRLIB_LoadTexture(botonder_png);
	GRRLIB_texImg* tex_wiimote = GRRLIB_LoadTexture(wiimote_png);
	GRRLIB_texImg* tex_wiimotedown = GRRLIB_LoadTexture(wiimotedown_png);
	GRRLIB_texImg* tex_wiimoteside = GRRLIB_LoadTexture(wiimoteside_png);
	GRRLIB_texImg* tex_wiimotefront = GRRLIB_LoadTexture(wiimotefront_png);
	GRRLIB_texImg* tex_wiimoteback = GRRLIB_LoadTexture(wiimoteback_png);
	GRRLIB_texImg* tex_nunchuk = GRRLIB_LoadTexture(nunchuk_png);
	GRRLIB_texImg* tex_nunchukback = GRRLIB_LoadTexture(nunchukback_png);
	GRRLIB_texImg* tex_joy = GRRLIB_LoadTexture(joy_png);
	GRRLIB_texImg* tex_pointer = GRRLIB_LoadTexture(pointer_png);
	GRRLIB_texImg* tex_ladrillos = GRRLIB_LoadTexture(ladrillos_jpg);
 
	pad = 0;
 
	while(1){
 
		// Comprobamos el estado de los wiimotes
		int i = 0;
		for(i=0;i<4;i++) 
			padstatus[i]=(WPAD_Probe(i, &expansion_type)>=0);
 
		// leemos el tipo de expansión conectada
		WPAD_Probe(pad, &expansion_type);
 
		WPAD_ScanPads();  // Leer mandos
 		// recoge los datos extra del wiimote
		wmote_data=WPAD_Data(pad);
		WPAD_IR(pad, &ir);
 
        // Si pulsamos home salimos del bucle
		if (WPAD_ButtonsDown(pad) & WPAD_BUTTON_HOME)  break;
//		if (WPAD_ButtonsDown(0) & WPAD_BUTTON_1) GRRLIB_ScrShot("SCREEN.PNG");
 
		int pasox = tex_ladrillos->w;
		int pasoy = tex_ladrillos->h;
		int x, y;
		for (x=0; x<resx; x+=pasox)
			for (y=0; y<resy; y+=pasoy){
				GRRLIB_DrawImg(x,y,tex_ladrillos,0,1,1, GRRLIB_WHITE);
			}
 
		if (expansion_type==WPAD_EXP_NUNCHUK){
			if (WPAD_ButtonsHeld(pad) & WPAD_NUNCHUK_BUTTON_C)
				GRRLIB_DrawImg(199,130,tex_botonc,0,1,1, GRRLIB_SILVER);
			else
				GRRLIB_DrawImg(200,128,tex_botonc,0,1,1, GRRLIB_WHITE);
			if (WPAD_ButtonsHeld(pad) & WPAD_NUNCHUK_BUTTON_Z)
				GRRLIB_DrawImg(209,141,tex_botonz,0,1,1, GRRLIB_SILVER);
			else
				GRRLIB_DrawImg(211,138,tex_botonz,0,1,1, GRRLIB_WHITE);
			GRRLIB_DrawImg(70,130,tex_nunchuk,0,1,1, GRRLIB_WHITE);
			GRRLIB_DrawImg(150,130,tex_nunchukback,0,1,1, GRRLIB_WHITE);
 
 
			float t = DegToRad(wmote_data->exp.nunchuk.js.ang-90);
			float jx = cos(t)*wmote_data->exp.nunchuk.js.mag*10;
			float jy = sin(t)*wmote_data->exp.nunchuk.js.mag*10;
			GRRLIB_DrawImg(102+jx,162+jy,tex_joy,0,1.5,1.5, GRRLIB_WHITE);
		}
 
		GRRLIB_SetMidHandle(tex_wiimoteside, true);
		GRRLIB_SetMidHandle(tex_wiimotedown, true);
		GRRLIB_DrawImg(385, 450, tex_wiimoteside, -wmote_data->orient.pitch, 1, 1, GRRLIB_WHITE);
		GRRLIB_DrawImg(515, 450, tex_wiimotedown, wmote_data->orient.roll, 1, 1, GRRLIB_WHITE);
 
 
 
		GRRLIB_DrawImg(350,80,tex_wiimote,0,1,1, GRRLIB_WHITE);
		if (WPAD_ButtonsHeld(pad) & WPAD_BUTTON_UP)
			GRRLIB_DrawImg(380,110,tex_botonarriba,0,0.95,0.95, GRRLIB_SILVER);
		else
			GRRLIB_DrawImg(380,110,tex_botonarriba,0,1,1, GRRLIB_WHITE);
		if (WPAD_ButtonsHeld(pad) & WPAD_BUTTON_DOWN)
			GRRLIB_DrawImg(380,134,tex_botonabajo,0,0.95,0.95, GRRLIB_SILVER);
		else
			GRRLIB_DrawImg(380,134,tex_botonabajo,0,1,1, GRRLIB_WHITE);
		if (WPAD_ButtonsHeld(pad) & WPAD_BUTTON_LEFT)
			GRRLIB_DrawImg(368,122,tex_botonizq,0,0.95,0.95, GRRLIB_SILVER);
		else
			GRRLIB_DrawImg(368,122,tex_botonizq,0,1,1, GRRLIB_WHITE);
		if (WPAD_ButtonsHeld(pad) & WPAD_BUTTON_RIGHT)
			GRRLIB_DrawImg(393,122,tex_botonder,0,0.95,0.95, GRRLIB_SILVER);
		else
			GRRLIB_DrawImg(393,122,tex_botonder,0,1,1, GRRLIB_WHITE);
		if (WPAD_ButtonsHeld(pad) & WPAD_BUTTON_A)
			GRRLIB_DrawImg(374,161,tex_botona,0,0.95,0.95, GRRLIB_SILVER);
		else
			GRRLIB_DrawImg(374,161,tex_botona,0,1,1, GRRLIB_WHITE);
		if (WPAD_ButtonsHeld(pad) & WPAD_BUTTON_PLUS)
			GRRLIB_DrawImg(404,217,tex_botonmas,0,0.95,0.95, GRRLIB_SILVER);
		else
			GRRLIB_DrawImg(404,217,tex_botonmas,0,1,1, GRRLIB_WHITE);
		if (WPAD_ButtonsHeld(pad) & WPAD_BUTTON_MINUS)
			GRRLIB_DrawImg(359,217,tex_botonmenos,0,0.95,0.95, GRRLIB_SILVER);
		else
			GRRLIB_DrawImg(359,217,tex_botonmenos,0,1,1, GRRLIB_WHITE);
		if (WPAD_ButtonsHeld(pad) & WPAD_BUTTON_HOME)
			GRRLIB_DrawImg(380,216,tex_botonhome,0,0.95,0.95, GRRLIB_SILVER);
		else
			GRRLIB_DrawImg(380,216,tex_botonhome,0,1,1, GRRLIB_WHITE);
		if (WPAD_ButtonsHeld(pad) & WPAD_BUTTON_1)
			GRRLIB_DrawImg(378,293,tex_botonuno,0,0.95,0.95, GRRLIB_SILVER);
		else
			GRRLIB_DrawImg(378,293,tex_botonuno,0,1,1, GRRLIB_WHITE);
		if (WPAD_ButtonsHeld(pad) & WPAD_BUTTON_2)
			GRRLIB_DrawImg(378,320,tex_botondos,0,0.95,0.95, GRRLIB_SILVER);
		else
			GRRLIB_DrawImg(378,320,tex_botondos,0,1,1, GRRLIB_WHITE);
		GRRLIB_DrawImg(480,80,tex_wiimoteback,0,1,1, GRRLIB_WHITE);
		if (WPAD_ButtonsHeld(pad) & WPAD_BUTTON_B)
			GRRLIB_DrawImg(501,129,tex_botonb,0,1,0.95, GRRLIB_SILVER);
		else
			GRRLIB_DrawImg(501,129,tex_botonb,0,1,1, GRRLIB_WHITE);
 
		for (i = 0; i<4; i++) {
			Draw_PadStatus(30+i*30, 450, i);
			if (padstatus[i] && (WPAD_ButtonsHeld(pad) & WPAD_BUTTON_A))
				if (GRRLIB_RectInRect(ir.x,ir.y,5,5, 30+i*30-5, 450, 20, 25))
					pad = i;
		}
 
		// Dibuja el led correspondiente al pad activo
		GRRLIB_Rectangle(350+16+13*pad,80+268, 5, 5, GRRLIB_LBLUE, true);
 
 
		GRRLIB_Rectangle(centro-5, 5, GRRLIB_WidthTTF(myFont, _TITLE, 20)+10, 
			30, GRRLIB_SILVER, true);
		GRRLIB_Rectangle(centro-5, 5, GRRLIB_WidthTTF(myFont, _TITLE, 20)+10, 
			30, GRRLIB_BLACK, false);
		GRRLIB_PrintfTTF(centro, 10, myFont, _TITLE, 20, GRRLIB_PURPLE);
 
		GRRLIB_SetMidHandle(tex_pointer, true);
		GRRLIB_DrawImg(ir.x,ir.y,tex_pointer,ir.angle,1,1, GRRLIB_WHITE);
 
		GRRLIB_Render();  // Refrescamos la pantalla
    }
 
	GRRLIB_FreeTTF (myFont); // Liberamos la fuente truetype
 
	GRRLIB_FreeTexture(tex_botona);
	GRRLIB_FreeTexture(tex_botonb);
	GRRLIB_FreeTexture(tex_botonc);
	GRRLIB_FreeTexture(tex_botonz);
	GRRLIB_FreeTexture(tex_botonhome);
 	GRRLIB_FreeTexture(tex_botonarriba);
	GRRLIB_FreeTexture(tex_botonabajo);
	GRRLIB_FreeTexture(tex_botonder);
	GRRLIB_FreeTexture(tex_botonizq);
	GRRLIB_FreeTexture(tex_botonuno);
	GRRLIB_FreeTexture(tex_botondos);
	GRRLIB_FreeTexture(tex_botonmas);
	GRRLIB_FreeTexture(tex_botonmenos);
	GRRLIB_FreeTexture(tex_joy); 
	GRRLIB_FreeTexture(tex_ladrillos);
	GRRLIB_FreeTexture(tex_pointer);
	GRRLIB_FreeTexture(tex_nunchuk);
	GRRLIB_FreeTexture(tex_nunchukback);
	GRRLIB_FreeTexture(tex_wiimote);
	GRRLIB_FreeTexture(tex_wiimoteside);
	GRRLIB_FreeTexture(tex_wiimotedown);
	GRRLIB_FreeTexture(tex_wiimotefront);
	GRRLIB_FreeTexture(tex_wiimoteback);
 
    GRRLIB_Exit(); // Liberamos memoria
 
    exit(0);  // Usar exit para salir del program (no usar return desde el main)
}

Y ya hemos terminado por hoy, espero que os haya gustado y hayáis podido digerir esta entrega. Se que ha sido compleja pero si la completáis creo que puede ser muy gratificante.

En la siguiente entrega explicaremos como utilizar una sola textura para almacenar muchos gráficos. Esto es lo que llamaremos tiles y tiene como utilidad más habitual la de utilizar fuentes bitmap, es decir fuentes que se dibujan punto a punto al contrario de las fuentes true type que utilizan líneas.

También se utilizan habitualmente para realizar fondos en juegos tipo laberinto o plataforma, ya que permiten tratar las imagenes como un array de datos.

Os espero en la próxima entrega!!! 

4.387095
Tu voto: Ninguno Votos totales: 4.4 (31 votos)

Anuncios Google

Comentarios

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.
Imagen de csar.ale

=/

No lo logro, he hecho el tutorial completo he añadido comentarios para entenderlo mejor y e escrito el código al 100% pero tengo un problema, a la hora de ejecutar el boot.dol en el wii, me sale una pantalla negra y regresa al HBC :(

Pego mi código:

#include <grrlib.h>
#include <stdlib.h>
#include <wiiuse/wpad.h>
#include "SFCollegiate_ttf.h"
#include "botona_png.h"
#include "botonb_png.h"
#include "botonc_png.h"
#include "botonz_png.h"
#include "botonhome_png.h"
#include "botonuno_png.h"
#include "botondos_png.h"
#include "botonmas_png.h"
#include "botonmenos_png.h"
#include "botonarriba_png.h"
#include "botonabajo_png.h"
#include "botonizq_png.h"
#include "botonder_png.h"
#include "joy_png.h"
#include "nunchuk_png.h"
#include "nunchukback_png.h"
#include "wiimote_png.h"
#include "wiimoteside_png.h"
#include "wiimotefront_png.h"
#include "wiimotedown_png.h"
#include "wiimoteback_png.h"
#include "pointer_png.h"
#include "ladrillos_jpg.h"
 
// Colores RGBA
#define GRRLIB_BLACK   0x000000FF
#define GRRLIB_MAROON  0x800000FF
#define GRRLIB_GREEN   0x008000FF
#define GRRLIB_OLIVE   0x808000FF
#define GRRLIB_NAVY    0x000080FF
#define GRRLIB_PURPLE  0x800080FF
#define GRRLIB_TEAL    0x008080FF
#define GRRLIB_GRAY    0x808080FF
#define GRRLIB_SILVER  0xC0C0C0FF
#define GRRLIB_RED     0xFF0000FF
#define GRRLIB_LIME    0x00FF00FF
#define GRRLIB_YELLOW  0xFFFF00FF
#define GRRLIB_BLUE    0x0000FFFF
#define GRRLIB_FUCHSIA 0xFF00FFFF
#define GRRLIB_AQUA    0x00FFFFFF
#define GRRLIB_WHITE   0xFFFFFFFF
#define GRRLIB_LBLUE   0x5050FFFF
 
#define _TITLE "YABT - YET ANOTHER BUTTON TESTER"
 
 
GRRLIB_ttfFont *myFont; //Fuente sera myFont
bool padstatus[4];
u32 pad;
 
		void Draw_PadStatus(int x, int y, int v){
	char s[5];
	sprintf(s, "%d", v+1);
	if (padstatus[v]){
		if (v==pad){
			GRRLIB_Rectangle(x-5, y, 20, 25, GRRLIB_WHITE, true);
			GRRLIB_Rectangle(x-5, y, 20, 25, GRRLIB_NAVY, false);
			GRRLIB_PrintfTTF(x, y, myFont, s, 20, GRRLIB_NAVY);
		} else {
			GRRLIB_Rectangle(x-5, y, 20, 25, GRRLIB_NAVY, true);
			GRRLIB_Rectangle(x-5, y, 20, 25, GRRLIB_WHITE, false);
			GRRLIB_PrintfTTF(x, y, myFont, s, 20, GRRLIB_WHITE);
		}
	}				
		}
 
int main(int argc, char **argv) {
 
	u32 expansion_type;          // tipo de expansión conectada
	WPADData * wmote_data;   // información del wiimote
	ir_t ir;                               // información del sensor IR
 
	int resx = 640; int resy= 480; // resolucion
 
 
// Inicializar graficos
	GRRLIB_Init();
 
	// Inicializar wiimotes
	WPAD_Init(); //Inicio wiimotes
	WPAD_SetDataFormat(WPAD_CHAN_ALL, WPAD_FMT_BTNS_ACC_IR); //informacion del wiimote en general (acelerometros, ir y botones)
	WPAD_SetVRes(WPAD_CHAN_ALL, resx, resy); //Informacion de resolucion del IR en todos los canales
 
 
	//Carga fuente y calcula el centro
	myFont = GRRLIB_LoadTTF(SFCollegiate_ttf, SFCollegiate_ttf_size); // lo convertimos al formato usado por GRRLIB
	int centro = (640-GRRLIB_WidthTTF(myFont, _TITLE, 20))/2; //Calcula el centro de la pantalla
 
 	//Variables de todas las imagenes
	GRRLIB_texImg* tex_botona = GRRLIB_LoadTexture(botona_png);//Boton a
	GRRLIB_texImg* tex_botonb = GRRLIB_LoadTexture(botonb_png);//boton B
	GRRLIB_texImg* tex_botonc = GRRLIB_LoadTexture(botonc_png); //Boton C
	GRRLIB_texImg* tex_botonz = GRRLIB_LoadTexture(botonz_png); //Boton Z
	GRRLIB_texImg* tex_botonhome = GRRLIB_LoadTexture(botonhome_png); //Boton Home
	GRRLIB_texImg* tex_botonuno = GRRLIB_LoadTexture(botonuno_png); //Boton uno
	GRRLIB_texImg* tex_botondos = GRRLIB_LoadTexture(botondos_png); //Boton Dos
	GRRLIB_texImg* tex_botonmas = GRRLIB_LoadTexture(botonmas_png); //Boton Mas
	GRRLIB_texImg* tex_botonmenos = GRRLIB_LoadTexture(botonmenos_png); //Boton Menos
	GRRLIB_texImg* tex_botonarriba = GRRLIB_LoadTexture(botonarriba_png); //Boton arriba
	GRRLIB_texImg* tex_botonabajo = GRRLIB_LoadTexture(botonabajo_png); //Boton abajo
	GRRLIB_texImg* tex_botonizq = GRRLIB_LoadTexture(botonizq_png); //Boton Izquierda
	GRRLIB_texImg* tex_botonder = GRRLIB_LoadTexture(botonder_png); //Boton Derecha
	GRRLIB_texImg* tex_wiimote = GRRLIB_LoadTexture(wiimote_png); //Imagen WiiMote
	GRRLIB_texImg* tex_wiimotedown = GRRLIB_LoadTexture(wiimotedown_png); //Imagen Wii Mote abajo
	GRRLIB_texImg* tex_wiimoteside = GRRLIB_LoadTexture(wiimoteside_png); //Imagen wiimote Aceleromotreo
	GRRLIB_texImg* tex_wiimotefront = GRRLIB_LoadTexture(wiimotefront_png); //Imagen wiimote enfrente
	GRRLIB_texImg* tex_wiimoteback = GRRLIB_LoadTexture(wiimoteback_png); //Imagen wiimote atras
	GRRLIB_texImg* tex_nunchuk = GRRLIB_LoadTexture(nunchuk_png); //Imagen Nunchuck
	GRRLIB_texImg* tex_nunchukback = GRRLIB_LoadTexture(nunchukback_png); //Imagen Nunchuck atras
	GRRLIB_texImg* tex_joy = GRRLIB_LoadTexture(joy_png); //Joy del nunchuck
	GRRLIB_texImg* tex_pointer = GRRLIB_LoadTexture(pointer_png); //Imagen cursor
	GRRLIB_texImg* tex_ladrillos = GRRLIB_LoadTexture(ladrillos_jpg); //Ladrillos
 
	pad = 0;
 
while(1){
	int i = 0; //i es igual a 0 es deicr ninguna extension conectada
		for(i=0;i<4;i++) //i es igual a 0 y puede llegar a 4, cuando i es mayor a 0 i suma
			padstatus[i]=(WPAD_Probe(i, &expansion_type)>=0); //Define que el estado es cero
			WPAD_Probe(pad, &expansion_type); // leemos el tipo de expansión conectada
 
			WPAD_ScanPads();  // Leer mandos
				// recoge los datos extra del wiimote
				wmote_data=WPAD_Data(pad); //(Datos de Acelerometros posicion)
				WPAD_IR(pad, &ir); //Estado del IR
 
		if (WPAD_ButtonsDown(pad) & WPAD_BUTTON_HOME)  break; //Si el boton home es presionado en cualquier wiimote (si es que esta conectado el bucle se rompe)
 
	int pasox = tex_ladrillos->w; //Paso X es igual al ancho del ladrillo
		int pasoy = tex_ladrillos->h; //Paso Y es igual al largo del ladrillo
		int x, y; //Inicia X e Y
		for (x=0; x<resx; x+=pasox) //X es igual a 0 y Pasox incrementara hasta volverse igual a res x que es 640
			for (y=0; y<resy; y+=pasoy){ //Y es igual a 0. Pasoy incrementara hasta volverse igual a Y que es 480
				GRRLIB_DrawImg(x,y,tex_ladrillos,0,1,1, GRRLIB_WHITE); //impresion de imagen desde x e y que son igual a cordenadas 0 y 0, no rotacion, escuala 1 y color blanco
			}
 
	if (expansion_type==WPAD_EXP_NUNCHUK){
			if (WPAD_ButtonsHeld(pad) & WPAD_NUNCHUK_BUTTON_C)
				GRRLIB_DrawImg(199,130,tex_botonc,0,1,1, GRRLIB_SILVER);
			else
				GRRLIB_DrawImg(200,128,tex_botonc,0,1,1, GRRLIB_WHITE);
			if (WPAD_ButtonsHeld(pad) & WPAD_NUNCHUK_BUTTON_Z)
				GRRLIB_DrawImg(209,141,tex_botonz,0,1,1, GRRLIB_SILVER);
			else
				GRRLIB_DrawImg(211,138,tex_botonz,0,1,1, GRRLIB_WHITE);
			GRRLIB_DrawImg(70,130,tex_nunchuk,0,1,1, GRRLIB_WHITE); //Imagen del nunchuck
			GRRLIB_DrawImg(150,130,tex_nunchukback,0,1,1, GRRLIB_WHITE); //imagen del nunchuck por atras
 
			float t = DegToRad(wmote_data->exp.nunchuk.js.ang-90); //t es igual a la conversion del angulo del nunchuck menos 90, lo que lo deja en el centro
			float jx = cos(t)*wmote_data->exp.nunchuk.js.mag*10; //jx es que tanto se mueve el joystik con respecto al angulo inicial en X
			float jy = sin(t)*wmote_data->exp.nunchuk.js.mag*10; //jy es que tanto se mueve el joystik con respecto al angulo inicial en y
			GRRLIB_DrawImg(102+jx,162+jy,tex_joy,0,1.5,1.5, GRRLIB_WHITE); //se imprime en 102 mas el movimiento en X y 162 mas el movimiento en Y, los cuales ya contienen la direccion especificada en T
		}
 
		GRRLIB_SetMidHandle(tex_wiimoteside, true); //Textura de WiiMote parado tiene rotacion en el centro
		GRRLIB_SetMidHandle(tex_wiimotedown, true); //Textura de WiiMote acostado tiene rotacion en el centro
		GRRLIB_DrawImg(385, 450, tex_wiimoteside, -wmote_data->orient.pitch, 1, 1, GRRLIB_WHITE); //impresion de imagen con rotacion que es igual a orientacion
		GRRLIB_DrawImg(515, 450, tex_wiimotedown, wmote_data->orient.roll, 1, 1, GRRLIB_WHITE); //impresion de imagen con rotacion que es igual a angulo de giro izquierda o rerecha
 
		GRRLIB_DrawImg(350,80,tex_wiimote,0,1,1, GRRLIB_WHITE);
		if (WPAD_ButtonsHeld(pad) & WPAD_BUTTON_UP)
			GRRLIB_DrawImg(380,110,tex_botonarriba,0,0.95,0.95, GRRLIB_SILVER);
		else
			GRRLIB_DrawImg(380,110,tex_botonarriba,0,1,1, GRRLIB_WHITE);
		if (WPAD_ButtonsHeld(pad) & WPAD_BUTTON_DOWN)
			GRRLIB_DrawImg(380,134,tex_botonabajo,0,0.95,0.95, GRRLIB_SILVER);
		else
			GRRLIB_DrawImg(380,134,tex_botonabajo,0,1,1, GRRLIB_WHITE);
		if (WPAD_ButtonsHeld(pad) & WPAD_BUTTON_LEFT)
			GRRLIB_DrawImg(368,122,tex_botonizq,0,0.95,0.95, GRRLIB_SILVER);
		else
			GRRLIB_DrawImg(368,122,tex_botonizq,0,1,1, GRRLIB_WHITE);
		if (WPAD_ButtonsHeld(pad) & WPAD_BUTTON_RIGHT)
			GRRLIB_DrawImg(393,122,tex_botonder,0,0.95,0.95, GRRLIB_SILVER);
		else
			GRRLIB_DrawImg(393,122,tex_botonder,0,1,1, GRRLIB_WHITE);
		if (WPAD_ButtonsHeld(pad) & WPAD_BUTTON_A)
			GRRLIB_DrawImg(374,161,tex_botona,0,0.95,0.95, GRRLIB_SILVER);
		else
			GRRLIB_DrawImg(374,161,tex_botona,0,1,1, GRRLIB_WHITE);
		if (WPAD_ButtonsHeld(pad) & WPAD_BUTTON_PLUS)
			GRRLIB_DrawImg(404,217,tex_botonmas,0,0.95,0.95, GRRLIB_SILVER);
		else
			GRRLIB_DrawImg(404,217,tex_botonmas,0,1,1, GRRLIB_WHITE);
		if (WPAD_ButtonsHeld(pad) & WPAD_BUTTON_MINUS)
			GRRLIB_DrawImg(359,217,tex_botonmenos,0,0.95,0.95, GRRLIB_SILVER);
		else
			GRRLIB_DrawImg(359,217,tex_botonmenos,0,1,1, GRRLIB_WHITE);
		if (WPAD_ButtonsHeld(pad) & WPAD_BUTTON_HOME)
			GRRLIB_DrawImg(380,216,tex_botonhome,0,0.95,0.95, GRRLIB_SILVER);
		else
			GRRLIB_DrawImg(380,216,tex_botonhome,0,1,1, GRRLIB_WHITE);
		if (WPAD_ButtonsHeld(pad) & WPAD_BUTTON_1)
			GRRLIB_DrawImg(378,293,tex_botonuno,0,0.95,0.95, GRRLIB_SILVER);
		else
			GRRLIB_DrawImg(378,293,tex_botonuno,0,1,1, GRRLIB_WHITE);
		if (WPAD_ButtonsHeld(pad) & WPAD_BUTTON_2)
			GRRLIB_DrawImg(378,320,tex_botondos,0,0.95,0.95, GRRLIB_SILVER);
		else
			GRRLIB_DrawImg(378,320,tex_botondos,0,1,1, GRRLIB_WHITE);
		GRRLIB_DrawImg(480,80,tex_wiimoteback,0,1,1, GRRLIB_WHITE);
		if (WPAD_ButtonsHeld(pad) & WPAD_BUTTON_B)
			GRRLIB_DrawImg(501,129,tex_botonb,0,1,0.95, GRRLIB_SILVER);
		else
			GRRLIB_DrawImg(501,129,tex_botonb,0,1,1, GRRLIB_WHITE);
 
 
			for (i = 0; i<4; i++) {
			Draw_PadStatus(30+i*30, 450, i);
			if (padstatus[i] && (WPAD_ButtonsHeld(pad) & WPAD_BUTTON_A))
				if (GRRLIB_RectInRect(ir.x,ir.y,5,5, 30+i*30-5, 450, 20, 25))
					pad = i;
		}
		// Dibuja el led correspondiente al pad activo
		GRRLIB_Rectangle(350+16+13*pad,80+268, 5, 5, GRRLIB_LBLUE, true);
 
 
		GRRLIB_Rectangle(centro-5, 5, GRRLIB_WidthTTF(myFont, _TITLE, 20)+10, 
			30, GRRLIB_SILVER, true);
		GRRLIB_Rectangle(centro-5, 5, GRRLIB_WidthTTF(myFont, _TITLE, 20)+10, 
			30, GRRLIB_BLACK, false);
		GRRLIB_PrintfTTF(centro, 10, myFont, _TITLE, 20, GRRLIB_PURPLE);
 
		GRRLIB_SetMidHandle(tex_pointer, true);
		GRRLIB_DrawImg(ir.x,ir.y,tex_pointer,ir.angle,1,1, GRRLIB_WHITE);
 
		GRRLIB_Render();  // Refrescamos la pantalla
    }
 
 
		//Se liberan todas las texturas y fuente
		GRRLIB_FreeTTF (myFont);
		GRRLIB_FreeTexture(tex_botona);
		GRRLIB_FreeTexture(tex_botonb);
		GRRLIB_FreeTexture(tex_botonc);
		GRRLIB_FreeTexture(tex_botonz);
		GRRLIB_FreeTexture(tex_botonhome);
		GRRLIB_FreeTexture(tex_botonarriba);
		GRRLIB_FreeTexture(tex_botonabajo);
		GRRLIB_FreeTexture(tex_botonder);
		GRRLIB_FreeTexture(tex_botonizq);
		GRRLIB_FreeTexture(tex_botonuno);
		GRRLIB_FreeTexture(tex_botondos);
		GRRLIB_FreeTexture(tex_botonmas);
		GRRLIB_FreeTexture(tex_botonmenos);
		GRRLIB_FreeTexture(tex_joy);
		GRRLIB_FreeTexture(tex_ladrillos);
		GRRLIB_FreeTexture(tex_pointer);
		GRRLIB_FreeTexture(tex_nunchuk);
		GRRLIB_FreeTexture(tex_nunchukback);
		GRRLIB_FreeTexture(tex_wiimote);
		GRRLIB_FreeTexture(tex_wiimoteside);
		GRRLIB_FreeTexture(tex_wiimotedown);
		GRRLIB_FreeTexture(tex_wiimotefront);
		GRRLIB_FreeTexture(tex_wiimoteback);
 
    GRRLIB_Exit(); // Liberamos memoria
 
    exit(0);  // Usar exit para salir del program (no usar return desde el main)
}

Saludos!

Imagen de wilco2009

Déjame que lo repase esta

Déjame que lo repase esta tarde cuando vuelva de trabajar y te digo algo.

 

EDITO: Pues acabo de probar tu código y a mí me funciona correctamente. Lo único que tengo diferente es la fuente de letras.

¿Podrías subirme a algun sitio la carpeta completa que estás utilizando para comprobar cual es el problema?

 


Curso aplicado de GRRLIB - Parte 1 - Parte 2 - Parte 3 - Parte 4 - Parte 5 - Parte 6 - Parte 7 - Parte 8 - Parte 9 - Parte 10 - Parte 11

Profundizando en los mandos de la Wii - Parte 1 - Parte 2 - Parte 3  - Parte 4 (Balanceboard) - Parte 5 (Miis) 

Homebrew - WiiTriis -  LifemiiWii

Imagen de csar.ale

Si

Imagen de wilco2009

Visto. Al final tu problema

Visto.

Al final tu problema no era el código que estaba, de hecho, exactamente igual que el del curso.

El problema lo generaba el jpg que habías incluido para los ladrillos que por el motivo que sea no le gustaba a GRRLIB.

No es la primera vez que veo que da problemas un jpg por lo que te recomiendo que uses siempre que puedas png (convierte el archivo con GIMP). Adicionalmente, aunque esto ya lo debes saber, las imágenes ya sean jpg o png deben tener una resolución múltiplo de 4.


Curso aplicado de GRRLIB - Parte 1 - Parte 2 - Parte 3 - Parte 4 - Parte 5 - Parte 6 - Parte 7 - Parte 8 - Parte 9 - Parte 10 - Parte 11

Profundizando en los mandos de la Wii - Parte 1 - Parte 2 - Parte 3  - Parte 4 (Balanceboard) - Parte 5 (Miis) 

Homebrew - WiiTriis -  LifemiiWii

Imagen de csar.ale

Correcto

Al final ha funcionado garcias wiilco, te juro que es el Tester Buttons más difícil que he hecho xD

Saludos!

Imagen de wilco2009

Sí, pero al final el problema

Sí, pero al final el problema era una causa ajena al código propiamente dicho. Creo que tiene que ver con un código de finalización que deben llevar los JPEGs y que en ocasiones no incorporan.

De todas formas, yo creo que una vez captas la forma de trabajar de la biblioteca, es muy fácil de utilizar. Te animo a que, si has llegado hasta aquí continues.

El capitulo 11 que estoy redactando ahora mismo, es un capítulo bastante práctico, que trata de aplicar algunas de las cosas aprendidas en capitulos anteriores recreando una especie de espacio intergaláctico por el que nos podemos mover. Verás que el acabado de las escenas en 3D, utilizando luces y texturas, es realmente expectacular.


Curso aplicado de GRRLIB - Parte 1 - Parte 2 - Parte 3 - Parte 4 - Parte 5 - Parte 6 - Parte 7 - Parte 8 - Parte 9 - Parte 10 - Parte 11

Profundizando en los mandos de la Wii - Parte 1 - Parte 2 - Parte 3  - Parte 4 (Balanceboard) - Parte 5 (Miis) 

Homebrew - WiiTriis -  LifemiiWii

Imagen de anxoganso

Intente escrbir de nuevo el

Intente escrbir de nuevo el codigo haber si era capaz pero me mandaba un error entonces probe con tus archivos tal y como esta y me dice esto:

bueno hay muchas lineas arriba pero el error comienza aqui:

linking ... b.elf
c:/devkitPro/libogc/lib/wii\libgrrlib.a(GRRLIB_texEdit.o): In function `GRRLIB_LoadTextureJPGEx':
GRRLIB_texEdit.c:(.text.GRRLIB_LoadTextureJPGEx+0x78): undefined reference to `jpeg_mem_src'
collect2: ld returned 1 exit status
make[1]: *** [/c/b/b.elf] Error 1
"make": *** [build] Error 2

> Process Exit Code: 2
> Time Taken: 04:38


Imagen de wilco2009

Tiene todo el aspecto de no

Tiene todo el aspecto de no haberte compilado correctamente el GRRLIB cuando lo instalaste.

Fíjate si termina bien o con un error.

También podría ser que el archivo makefile no fuera el correcto. Copia el que viene en el ejemplo.


Curso aplicado de GRRLIB - Parte 1 - Parte 2 - Parte 3 - Parte 4 - Parte 5 - Parte 6 - Parte 7 - Parte 8 - Parte 9 - Parte 10 - Parte 11

Profundizando en los mandos de la Wii - Parte 1 - Parte 2 - Parte 3  - Parte 4 (Balanceboard) - Parte 5 (Miis) 

Homebrew - WiiTriis -  LifemiiWii

Imagen de anxoganso

Volvi a compilar la libreria

Volvi a compilar la libreria y va todo bien y el makefile uso el que viene

Imagen de wilco2009

Cuando dices que compilaste

Cuando dices que compilaste la libreria y va todo bien, ¿Te refieres a que ahora ya te compila el fuente del tutorial?

Imagen de anxoganso

No que cuando compile la

No que cuando compile la libreria parecia que enlazaba todo bien y no habia ningun fallo pero al compilar el codigo fuente del tutorial no funciona voy a volver a compilar la libreria haber de todas formas


Felicitarte

Ni mas ni menos que FELICITARTE por el curro que te has pegado y por lo bien explicado que está. GENIAL. GRACIAS.

Imagen de wilco2009

Gracias a ti por seguirlos y

Gracias a ti por seguirlos y ánimo con el curso.

parpadeo

Hola de nuevo ;)

te explico mi duda:
tengo 2 imagenes iguales que se mueven de derecha a izquierda, una junto a la otra, y cuando llegan a x -640 vuelven a 640, haciendo asi un scroll infinito de cielo. (hasta aqui todo perfecto)

delante de esto tengo una imagen con transparencia que son los edificios 

pues resulta que el cielo se ve a trozos por encima de los edificios parpadeando, esto es normal?
quizas lo estoy haciendo de manera equivocada????

aqui lo puedes ver: http://www.youtube.com/watch?v=zzpxRZRc5m4

 

ya se que no es el codigo mas limpio ni mas correcto del mundo.

void menu(){

int contadorvel = 0;

int posicioncielo = 0;

int posicioncielo2 = 640;

GRRLIB_texImg* grafcielomenu = GRRLIB_LoadTexture(cielomenu_png); 

GRRLIB_texImg* grafskyline = GRRLIB_LoadTexture(skylinemenu_png); 

GRRLIB_ttfFont *myFont = GRRLIB_LoadTTF(verdana_ttf, verdana_ttf_size); 

while(1){

 

// ----------------------------------------------

// mueve el cielo

//-----------------------------------------------

if (contadorvel==0){ //solo si el ciclo es 0

posicioncielo--;

if (posicioncielo==-640)posicioncielo=640;

posicioncielo2--;

if (posicioncielo2==-640)posicioncielo2=640;

}

contadorvel++; //añade ciclos para que valla mas lento

if (contadorvel==3) contadorvel=0; //añade ciclos para que valla mas lento

GRRLIB_DrawImg(posicioncielo,0,grafcielomenu,0,1,1, 0xFFFFFFFF); //dibujamos cielo

GRRLIB_DrawImg(posicioncielo2,0,grafcielomenu,0,1,1, 0xFFFFFFFF); //dibujamos cielo

//-----------------------------------------------

GRRLIB_DrawImg(0,100,grafskyline,0,1,1, 0xFFFFFFFF); //dibujamos edificios

WPAD_ScanPads();  

if (WPAD_ButtonsDown(0) & WPAD_BUTTON_HOME) break;

GRRLIB_PrintfTTF(20,440, myFont, "HOMBREMAN THE GAME V0.1", 10, GRRLIB_WHITE); 

GRRLIB_Render(); 

}

 

    GRRLIB_FreeTTF (myFont);

GRRLIB_FreeTexture(grafcielomenu);

GRRLIB_FreeTexture(grafskyline);

 

Imagen de wilco2009

Creo que tu problema es

Creo que tu problema es debido a que estás intentando visualizar una parte importante de las texturas fuera de la pantalla.

Intenta utilizar DrawPart para visualizar sólo la parte visible.

 


Curso aplicado de GRRLIB - Parte 1 - Parte 2 - Parte 3 - Parte 4 - Parte 5 - Parte 6 - Parte 7 - Parte 8 - Parte 9 - Parte 10 - Parte 11

Profundizando en los mandos de la Wii - Parte 1 - Parte 2 - Parte 3  - Parte 4 (Balanceboard) - Parte 5 (Miis) 

Homebrew - WiiTriis -  LifemiiWii

Tienes toda la razon, lo mio

Tienes toda la razon, lo mio me ha costado adaptarlo, pero funciona sin ningun problema.

hay alguna funcion para hacer scrolls en grrlib? de manera que puedas mover a los personajes con coordenadas relativas a el, etc...

muchas gracias por tu ayuda! 

Imagen de wilco2009

No hay nada preparado para

No hay nada preparado para hacerlo automáticamente, pero puedes mantener las coordenadas relativas respecto a ese escenario y hacer el cálculo de su posición final en pantalla.

Es decir si Xe, Ye son las coordenadas del escenario respecto de la pantalla, y Xp, Yp las coordenadas del personaje respecto del escenario, las coordenadas dentro de la textura a visualizar serán (-Xe, -Ye) y las coordenadas del personaje en la pantalla serán Xp+Xe, Yp+Ye.

Por cierto tenía muy buen aspecto el video que has enviado. Espero ver el resultado de ese juego........ 


Curso aplicado de GRRLIB - Parte 1 - Parte 2 - Parte 3 - Parte 4 - Parte 5 - Parte 6 - Parte 7 - Parte 8 - Parte 9 - Parte 10 - Parte 11

Profundizando en los mandos de la Wii - Parte 1 - Parte 2 - Parte 3  - Parte 4 (Balanceboard) - Parte 5 (Miis) 

Homebrew - WiiTriis -  LifemiiWii

mmmm tendré que digerir esto

mmmm tendré que digerir esto que me explicas, yo vengo de programar en DIV games studio, donde habia una funcion para iniciar el scroll y otra funcion que hacia de camara, con lo cual solo tenias que hacer que la camara siguiera al personaje.
espero que la wii tenga suficiente potencia para cargar y mover bien un scroll muy largo, si no tendré que hacer el scroll por partes.
muchas gracias, de verdad, es un lujo tener a alguien que te aclare las dudas. y contar con un curso tan claro, si me hubieran dicho hace años que programaria para wii no me lo hubiera creido :D

Imagen de wilco2009

Si hablamos de programación

Si hablamos de programación en 3D sí que puedes ir moviendo la cámara y tener situados los objetos en posiciones fijas, pero en 2D has de trabajar calculando posiciones relativas para luego volcarlas en pantalla.

De todas formas, tal y como se ve en el capítulo 6, si buscas rendimiento usa fuentes bitmap ya que las fuentes truetype dan un rendimiento bastante bajo.

Moviendo texturas la Wii se arregla bastantante bien, ya me contarás como te va.


Curso aplicado de GRRLIB - Parte 1 - Parte 2 - Parte 3 - Parte 4 - Parte 5 - Parte 6 - Parte 7 - Parte 8 - Parte 9 - Parte 10 - Parte 11

Profundizando en los mandos de la Wii - Parte 1 - Parte 2 - Parte 3  - Parte 4 (Balanceboard) - Parte 5 (Miis) 

Homebrew - WiiTriis -  LifemiiWii

Muchisismas gracias por las 5

Muchisismas gracias por las 5 entregas. Soy programador en VB y me está costando pero me es super util. Te animo a continuar, aunque sea por el simple hecho de que a mucha gente nos ayudará a hacer juegos interesantes(algo que escasea ultimamente en homebrew)
muchas gracias y felicidades de nuevo!

Imagen de wilco2009

Se agradecen muchisimo los

Se agradecen muchisimo los ánimos. La verdad es que este tipo de articulos cuestan mucho trabajo, y aunque los hago con gran placer, son vuestros comentarios el principal motivo para continuar.

Reitero mi disponibilidad para cualquier pregunta que tengais.


Curso aplicado de GRRLIB - Parte 1 - Parte 2 - Parte 3 - Parte 4 - Parte 5 - Parte 6 - Parte 7 - Parte 8 - Parte 9 - Parte 10 - Parte 11

Profundizando en los mandos de la Wii - Parte 1 - Parte 2 - Parte 3  - Parte 4 (Balanceboard) - Parte 5 (Miis) 

Homebrew - WiiTriis -  LifemiiWii

Hola de nuevo!Me ha surgido

Hola de nuevo!Me ha surgido una duda. He estado probando ejemplos del grrlib. No me funciona al hacer un cubo3d con texturas. Sin texturas perfecto. He visto que en los ejemplos cargan las texuras muy diferentes, por ejemplo #include "pruebas_png.h" ellos ponen #include "pruebas.h" y la carga de texturas varia un poco(obviamente:
GRRLIB_texImg* pruebas= GRRLIB_LoadTexture(pruebas);
GRRLIB_texImg* pruebas= GRRLIB_LoadTexture(pruebas_png);

He visto que en el proyecto incluyen 2 archivos realitvos a la textura: un C source file y un C header file. Con el WiiBuilder obtienes facil el header, pero el otro no(de todas formas creo que simplemente es para estructurar mejor todo.

La cuestion que lo haga como lo haga, al iniciar el programa se ve todo negro. Si renderizo el cubo sin texturas se ve texto, el cubo, algun png cargado...

Sabes mas o menos como renderizar un cubo con texturas?
Gracias de nuevo

Perfecto!Efectivamente era al

Perfecto!Efectivamente era al iniciar el modo 3d. Fallos asi tendre muchos por la falta de costumbre.
Se nota que tienes mucha experiencia porque has detectado el error muy rapido.
Algunos como yo( y muchos mas seguramente) estamos ansiosos por la 6ª entrega!Animo!

Imagen de wilco2009

jejeje, mis horas me ha

jejeje, mis horas me ha costado pegarme con errores similares a ese.

Ánimo que se nota que vas lanzado!

Imagen de wilco2009

Comprueba que has llamado

Comprueba que has llamado correctamente a 3dMode poniendo a 1 el parámetro que indica si se usan o nó texturas.

void GRRLIB_3dMode (f32 minDist, f32 maxDist, f32 fov, bool texturemode, bool normalmode)

Por otro lado la función GRRLIB_DrawCube corresponde a un cubo sin texturas.

Si quieres hacer un cubo con texturas debes hacerlo manualmente con 6 QUADS.

Tienes un ejemplo de cubo con texturas entre los que van en GRRLIB.


Curso aplicado de GRRLIB - Parte 1 - Parte 2 - Parte 3 - Parte 4 - Parte 5 - Parte 6 - Parte 7 - Parte 8 - Parte 9 - Parte 10 - Parte 11

Profundizando en los mandos de la Wii - Parte 1 - Parte 2 - Parte 3  - Parte 4 (Balanceboard) - Parte 5 (Miis) 

Homebrew - WiiTriis -  LifemiiWii

La mañana de hoy estuve

La mañana de hoy estuve trasteando sobre hacer cosas en 2d. Es muy muy sencillo. He creado un miniprograma en el que sale link en un campo de futbol y puede coger el balon y rematar(con la tecla 2). Siempre dispara al lado derecho, estilo mario smash soccer. Es un ejemplo muy muy sencillito pero es para que los programadores vean que esta chupado programar para wii.
Simplemente leyendo estos tutoriales, sabiendo programacion y dedicandole tiempo cualquiera puede llegar a hacer un juego simple y divertido. Os animo a todos a intentarlo.
PD aqui dejo el link para descargar el pequeño ejemplo que hice en pocos minutos: http://depositfiles.com/files/323h4hdrc

Imagen de wilco2009

La verdad es que está

La verdad es que está fantástico, te ha quedado de maravilla.

En el siguiente capitulo veremos el concepto de tiles que puedes utilizar para simplificar las animaciones del personaje.

La verdad es que estoy impresionado.

 


Curso aplicado de GRRLIB - Parte 1 - Parte 2 - Parte 3 - Parte 4 - Parte 5 - Parte 6 - Parte 7 - Parte 8 - Parte 9 - Parte 10 - Parte 11

Profundizando en los mandos de la Wii - Parte 1 - Parte 2 - Parte 3  - Parte 4 (Balanceboard) - Parte 5 (Miis) 

Homebrew - WiiTriis -  LifemiiWii

Hola de nuevo wilco!!tengo

EDITO:Creo que ya tengo la solucion si funciona lo posteo luego
Hola de nuevo wilco!!tengo una duda que te va a parecer un poco absurda, pero es la falta de costumbre de programar en C para wii jejej.
La cuestion es la siguiente:
Imagina un juego de futbol, con un campo que mide 1024 pixels de ancho,La resolucion en wii es de 640X. Entonces el campo se va mostrando a medida que avanzas a la porteria rival o retrocedes a la tuya. Tienes que limitar el balon para que no salga despedido por detras de cualquier porteria, osea deberia chocar en la linea de fondo. Tambien ocurre que si estas en tu area y rematas a la meta rival el balon se aleja mucho, y lo que deberia ocurrir es que tu jugador no se moviera de tu area y el balon apareciera en el otro area, la camara obviamente apuntaria a donde el balon, tu jugador no seria visible pero puede caminar al area rival hasta que sea visible.

Vale el problema es que muevo la posicion del campo de futbol con relacion a la pelota:
GRRLIB_DrawPart (0, 0, bgx2-53, bgy2-5, 640, 480, tex_estadio, 0, 1.2, 1.2, GRRLIB_WHITE);

Y limito el avance de jugadores y la pelota asi:
if(Jugadores.bgy[JugadorSeleccionado] > MinY) {
if(wpadheld & WPAD_BUTTON_RIGHT) {
Jugadores.bgy[JugadorSeleccionado] -=2;
if (CapiBalon == 1) {
bgy2 -=2;

El problema es que renderiza el jugador siempre:
GRRLIB_DrawTile(Jugadores.bgx[1], Jugadores.bgy[1], tex_mm, 0, 2, 2, GRRLIB_WHITE, Jugadores.frame[1]);

Y logicamente si un jugador no tiene la pelota no puedes sacarlo de la pantalla, bgx y bgy son coordenadas de los jugadores dentro de la pantalla visible. La cuestion es que se deberia guardar la posicion del jugador pase lo que pase, osea situar sus coordenadas de forma que X e Y no sean posicion de pantalla sino posicion dentro del PNG o de un mapa.
No se como se podria hacer.¿Tienes idea de como seria el algoritmo?
Espero haberme explicado mas o menos bien jejeje.

Imagen de wilco2009

Si he entendido bien tu

Si he entendido bien tu mensaje, la solución te la estás dando tu mismo.

Tienes que guardar las coordenadas del jugador dentro del campo en sendas variables, y por otro lado las coordenadas del campo respecto de la pantalla.

A la hora de visualizar es cuando debes hacer los cálculos.

Imaginemos que "jx" y "jy" son las coordenadas del jugador y "vx" y "vy" las del campo respecto de la pantalla.

La parte a visualizar del campo sería:

0-vx, 0-vy, 640, 528

Para dibujar o no el jugador deberíamos comprobar que está dentro de la parte visible:

x=jx+vx; y=jy+vy;

if (GRRLIB_PtInRect(0,0,640,528,x,y)) GRRLIB_Drawtile(x,y,.......

 

 


Curso aplicado de GRRLIB - Parte 1 - Parte 2 - Parte 3 - Parte 4 - Parte 5 - Parte 6 - Parte 7 - Parte 8 - Parte 9 - Parte 10 - Parte 11

Profundizando en los mandos de la Wii - Parte 1 - Parte 2 - Parte 3  - Parte 4 (Balanceboard) - Parte 5 (Miis) 

Homebrew - WiiTriis -  LifemiiWii

Ostras pues es verdad, no

Ostras pues es verdad, no habia caido en la función PtInRect (aun no las conozco todas a fondo). Pues genial por darme la solución porque habia pensado una más complicada...
Muchas gracias otra vez!!¿Cómo llevas esa parte 6? Estoy ansioso ya jajaja
A ver si mas gente se anima a hacer cosas, que es super sencillo.

Imagen de wilco2009

Realmente están escritas ya

Realmente están escritas ya la 6 y la 7 y estoy ahora mismo con la 8, lo que pasa es que se van dosificando según criterio del staff.

El intervalo varía entre 4 y 8 días.


Curso aplicado de GRRLIB - Parte 1 - Parte 2 - Parte 3 - Parte 4 - Parte 5 - Parte 6 - Parte 7 - Parte 8 - Parte 9 - Parte 10 - Parte 11

Profundizando en los mandos de la Wii - Parte 1 - Parte 2 - Parte 3  - Parte 4 (Balanceboard) - Parte 5 (Miis) 

Homebrew - WiiTriis -  LifemiiWii

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.