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.
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.
Existen dos posibilidades a la hora de manejar texturas
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.
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.
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:
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.
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.
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.
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_ButtonsHeld y WPAD_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.
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.
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.
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:
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!!!
Comentarios
=/
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:
Saludos!
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
Si
Aqui esta:
http://www.megaupload.com/?d=JRVG3GGI
Gracias!
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
Correcto
Al final ha funcionado garcias wiilco, te juro que es el Tester Buttons más difícil que he hecho xD
Saludos!
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
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
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
Volvi a compilar la libreria
Volvi a compilar la libreria y va todo bien y el makefile uso el que viene
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?
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.
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);
}
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!
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
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!
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!
jejeje, mis horas me ha
jejeje, mis horas me ha costado pegarme con errores similares a ese.
Ánimo que se nota que vas lanzado!
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
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.
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.
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