En la primera parte vimos como leer, además de los botones, el IR, la inclinación y giro del wiimote, las diferentes extensiones del wiimote incluyendo la lectura de los joysticks analógicos. En esta segunda parte vamos a explorar el uso de los acelerómetros en el wiimote y en el nunchuk y cómo utilizarlos para conseguir emular una batería electrónica.
Para simular el golpeo he utilizado la librería ASNDLib que permite reproducir un sonido PCM. Con objeto de poder utilizar la librería ASNDLib en nuestro programa, deberemos decirle al compilador que ha de enlazar dicha librería.
Dicha información la debemos incluir en la sección correspondiente del makefile mediante la siguiente línea:
LIBS := -lasnd -lwiiuse -lbte -logc –lm
En dicha línea añadimos “-lasnd” que indica al enlazador que debe incluir la librería asnd. Hay que tener en cuenta que aquí es muy importante el orden, de tal manera que se empezará enlazando las librerías incluidas al final de la línea y se terminará con las primeras.
Como veíamos en el anterior tutorial, la función que nos va a permitir la lectura de los acelerómetros es la misma que utilizábamos para leer el resto de los parámetros.
Recordamos dicha función:
// recoge los datos extra del wiimote wmote_data=WPAD_Data(pad);
En la variable wmote_data recibíamos todos los datos correspondientes al wiimote.
typedef struct _wpad_data { s16 err; u32 data_present; u8 battery_level; u32 btns_h; u32 btns_l; u32 btns_d; u32 btns_u; struct ir_t ir; struct vec3w_t accel; struct orient_t orient; struct gforce_t gforce; struct expansion_t exp; } WPADData;
Concretamente los campos de dicha variable que nos van a permitir leer los acelerómetros son:
wmote_data -> accel; wmote_data -> gforce;
Para el caso del wiimote y sus equivalentes para el nunchuk:
wmote_data -> exp.nunchuk.accel; wmote_data -> exp.nunchuk.gforce;
Dichos campos nos permiten leer los componentes “x”, “y” y “z” de la aceleración y la fuerza tanto del wiimote como del nunchuk. Aunque es muy fácil intuir el significado de ambos campos no hay nada mejor que la experimentación para observar su comportamiento. Para ello podemos mostrar en pantalla los valores que se muestran y ver qué valores se nos muestran mientras movemos aleatoriamente los mandos.
La forma de mostrar dichos mandos en pantalla sería idéntica que en el tutorial anterior:
// Muestra los datos del acelerómetro del wiimote printf("\x1b[%d;%dH", 4, 40); printf("Acelerometro: "); printf("\%d ; \%d ; \%d ", wmote_data->accel.x, wmote_data->accel.y, wmote_data->accel.z); printf("\x1b[%d;%dH", 5, 40); printf("Fuerza G:"); printf("\%0.00f ; \%0.00f ; \%0.00f ", wmote_data->gforce.x, wmote_data->gforce.y, wmote_data->gforce.z); // Muestra los datos del acelerómetro del Nunchuk printf("\x1b[%d;%dH", 4, 0); printf("Acelerometro: "); printf("\%d ; \%d ; \%d ", wmote_data->exp.nunchuk.accel.x, wmote_data->exp.nunchuk.accel.y, wmote_data->exp.nunchuk.accel.z); printf("\x1b[%d;%dH", 5, 0); printf("Fuerza G:"); printf("\%0.00f ; \%0.00f ; \%0.00f ", wmote_data->exp.nunchuk.gforce.x, wmote_data->exp.nunchuk.gforce.y, wmote_data->exp.nunchuk.gforce.z);
Decíamos al principio que el objetivo final del programa era la creación de una batería utilizando ambos mandos como baquetas.
Para dicho objetivo necesitaremos dos cosas fundamentales:
Para el caso del wiimote podemos detectar cuando tenemos las baquetas levantadas utilizando el campo “orient.pitch” y experimentaremos de nuevo con los valores en pantalla.
Experimentalmente podemos observar que para un valor de “orient.pitch” inferior a -30.0 podemos considerar el wiimote levantado.
// comprobamos la orientacion vertical del wiimote if(wmote_data->orient.pitch<=-30.0) baquetamote_arriba=1;
Seguidamente debemos comprobar el movimiento rápido hacia abajo, para lo cual usaremos la componente “y” del campo “gforce” siempre y cuando previamente tuviéramos levantado el mando.
if(wmote_data->orient.pitch>=10.0f && baquetamote_arriba && wmote_data->gforce.y>=0.2f)
De nuevo de manera experimental hemos determinado que para un valor de “orient.pitch” mayor que 10.0 el mando está abajo. He puesto un valor de gforce.y de 0.2, pero cuanto más alto pongamos este valor mayor fuerza se necesitará aplicar al movimiento para que sea reconocido como tal. Os invito a que variéis el valor para probar el efecto.
Para el nunchuk el manejo es idéntico pero usando los campos correspondientes, es decir anteponiendo exp.nunchuk.
De momento hemos conseguido lo más complicado, reconocer el golpeo del mando, pero ahora deberemos hacer que nuestra querida consola reaccione al golpeo detectado. Cualquier reacción que programemos necesitará utilizar un control del tiempo transcurrido que nos permita desactivar el sonido/vibración o lo que sea.
Podemos crear la función get_ms_clock(msec) a partir de la función estándar gettick() convirtiendo de ticks a milisegundos mediante un sencillo cálculo:
#define ticks_to_msecs(ticks) ((ticks)/TB_TIMER_CLOCK) extern unsigned gettick(); unsigned get_ms_clock() // retorna los milisegundos transcurridos { return ticks_to_msecs(gettick()); }
Nosotros vamos a implementar una duración de medio segundo (500 mseg) tiempo durante el que tendremos que mantener la reacción al golpeo sea la que sea. El problema es que no podemos permitirnos estar esperando ese tiempo sin hacer nada, por lo que deberemos asignar un flag para cada mando que nos permita saber que estamos ejecutando el golpeo y ejecutar la acción correspondiente a cada vuelta del bucle principal. De esta forma podremos seguir haciendo cosas incluso cuando está sonando la baqueta. Este flag se activará en el momento de dar el golpe y se desactivara cuando termine de sonar el golpeo.
Como acción para el golpeo, lo más sencillo que podríamos hacer es mostrar un mensaje por pantalla. Por ejemplo, podríamos mostrar un PUM en la izquierda al detectar el golpeo del Nunchuk y mostrar un PUM a la derecha cuando detectemos el golpeo del wiimote:
if (wiimote_sonando) { printf("\x1b[%d;%dH", 10, 40); printf("PUM"); if ((twiimote1-twiimote0) >= ti_golpe) wiimote_sonando = 0; } else { printf("\x1b[%d;%dH", 10, 40); printf(" "); }
Esto nos permitiría probar el efecto del golpeo de la baqueta, pero quedaría algo pobre.
La idea sería simular el sonido e incrementar la sensación de haber golpeado con la baqueta activando la vibración del mando. Para activar la vibración del mando debemos usar la función WPAD_Rumble(pad, 1); que activará la vibración. Una vez pase el medio segundo que tenemos estipulado deberíamos desactivar la vibración llamando de nuevo a la función de la siguiente forma WPAD_Rumble(pad, 0);. Por otro lado, en un tutorial sobre mandos lo ideal sería hacer funcionar el sonido del mando aunque hasta el momento no he conseguido hacerlo sonar adecuadamente.
Teoricamente la secuencia debería ser la siguiente:
WPAD_ControlSpeaker(pad, 1); WPAD_SendStreamData(pad, buffer, size);
Pasando en pad el número del mando, en buffer la muestra de sonido en formato 4 bits, 6KHz. Por último hay que tener en cuenta que solo se pueden enviar 20 bytes cada WPAD_STRM_INTERVAL.
De esta forma activamos el sonido del wiimote con las funciones:
ASND_SetVoice( 1, VOICE_MONO_8BIT, Note2Freq(NOTE(NOTE_C,3), 8000, NOTE(NOTE_C,3)), 0, drum_bass_smp, size_drum_bass_smp, 255, 255, NULL); ASND_SetVoice( 2, VOICE_MONO_8BIT, Note2Freq(NOTE(NOTE_D,3), 8000, NOTE(NOTE_C,3)), 0, drum_bass_smp, size_drum_bass_smp, 255, 255, NULL);
Usando dos voces para conseguir un sonido más potente.
Y para el Nunchuk:
ASND_SetVoice( 3, VOICE_MONO_8BIT, Note2Freq(NOTE(NOTE_C,3), 8000, NOTE(NOTE_C,3)), 0, drum_floortom_smp, size_drum_floortom_smp, 255, 255, NULL);
Por otro lado la vibración la activaremos mientras cualquiera de los dos sonidos esté sonando:
// activa la vibración del wiimote si hay algún sonido activo if (wiimote_sonando | nunchuk_sonando) { WPAD_Rumble(pad, 1); } else { WPAD_Rumble(pad, 0); }
Desactivándola cuando no esté sonando ninguno de los dos golpeos. Como podéis ver para activar o desactivar la vibración es suficiente con llamar a la función WPAD_Rumble, pasándole como primer parámetro el número del pad y como segundo parámetro un 1 en caso de querer activarlo o un 0 en caso contrario.
Al final, nos queda una bonita batería electrónica para la que solo haría falta que la decorásemos gráficamente, pero para eso hemos de saber utilizar las GX y eso no es el objetivo de esta segunda parte.
Espero que os haya gustado. A mi realmente me ha resultado muy satisfactorio conseguir hacer funcionar el programa, aunque aún tengo clavada la espina de saber manejar el sonido del wiimote, por lo que insisto a ver si alguien puede echarme un cable y completamos el curso.
Para finalizar adjunto el código completo y un enlace para que os lo descarguéis:
Descargar Codigo Profundizando en los mandos de la Wii - Parte 2
En la proxima entrega la idea es practicar el uso del IR y comenzar a usar las GX en 2D. Para ello programaremos un juego de tiro en el que moveremos el objetivo con el wiimote debiendo acertar a los diferentes elementos que crucen la pantalla.
Comentarios
Muchas gracias por los
Muchas gracias por los tutoriales, he probado la programación en DS, pero aún no en Wii, me alegro de que haya gente que haga tutoriales, me gustaría ponerme a ello en cuanto tenga tiempo.
Un saludo.
Saludos! Al compilarlo me
Saludos!
Al compilarlo me sale un error especificándome algo de un archivo llamado drum.o
¿Qué hago para solucionarlo?
Prueba a seleccionar "Clean"
Prueba a seleccionar "Clean" en el menú Tools antes de compilar, para que lo recompile todo desde el principio.
Si continúas teniendo problemas me lo dices.
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
Perdona por mi torpeza, pero,
Perdona por mi torpeza, pero, ¿dónde está el menú Tools?
Saludos.
Disculpa, he dado por
Disculpa,
he dado por supuesto que estabas utilizando el programa programmer's Notepad para editar y compilar, ya que el devkitpro lo instala automáticamente.
Haz doble clic sobre el archivo BalanceBoard.pnproj y te abrirá con el programmer's Notepad. Después haz un clean pulsando Alt+1 o seleccionando Clean en el menú Tools.
Después compila normalmente con Alt+2 o seleccionando Make en el menú tools.
No debería de darte problemas así.
Ya me cuentas.
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