Anuncios Google

Profundizando en los mandos de la Wii - Parte 4

Tutoriales Avanzados Homebrewes

Si me habéis seguido hasta aquí y seguís queriendo más después del árido tercer tutorial, es que de verdad disfrutáis con esto de la programación. Y es que es realmente gratificante ver como esa idea que ha partido de nuestra mente, se ejecuta en nuestra querida consola. Después de tres tutoriales hay un periférico que todavía no hemos tocado, y que es realmente interesante e innovador. Este es la Wii Balance Board. En este tutorial te enseñare como usar esta fantástica plataforma.

¿Que es la balance board?, Esa curiosa plataforma que es capaz de detectar nuestro centro de gravedad y nos ayuda a hacer ejercicios o a esquiar en nuestro juego favorito.

Y seguro que muchos de vosotros os habéis preguntado en qué consiste la Balance Board. Pues es más simple de lo que podíamos imaginar. Se trata simple y llanamente de una báscula con una célula de carga en cada una de sus esquinas. Y lo realmente novedoso del tema es que Nintendo ha convertido una simple báscula en un mando de juegos. Pero ¿Cómo se puede utilizar una báscula de esa manera? Pues la clave está en el cálculo del centro de gravedad. Cuando nos subimos a nuestra querida tabla, nuestro peso se reparte por toda ella y cada una las células de carga que posee soporta un peso que sumado da el total de lo que pesamos.

Si fuéramos capaces de equilibrar nuestro peso de tal manera que nuestro centro de gravedad quedara exactamente en el centro de la tabla, las cuatro celdas detectarían el mismo peso, pero si desplazamos nuestro peso hacia alguno de los lados, el peso soportado por cada célula variará. Esto último es lo que nos va a permitir calcular la posición del centro de gravedad triangulando la información del peso. Al saber la posición de ese centro de gravedad tendremos la información de hacia donde tenemos desplazado el cuerpo, y por tanto podremos intuir hacia donde estamos dirigiendo nuestros esquíes en el juego, o nuestra correcta posición en el ejercicio de Yoga.

 

En la foto anterior podéis ver donde van situadas las células de carga que coinciden exactamente con la posición de las cuatro patas de la tabla.

A lo largo del presente tutorial voy a intentar explicaros paso a paso el desarrollo de una aplicación que haga uso de la Balance board. Y qué mejor aplicación para aprender que realizar una báscula electrónica que además muestre nuestro centro de gravedad.

Y para hacerlo un poquito más estético, utilizaré el tutorial como excusa para explicar un poco más en detalle las librerías de sonido y explicar alguna cosa más de las GX, con lo que al final nos quedará una bonita báscula parlante que leerá nuestro peso en voz alta.

Pues nada, no perdamos más tiempo y vamos al tajo…..


Herramientas que necesitaremos para el curso



Empezamos con la estructura de los datos

 

A modo de referencia y sin pretender asustaros, ya que no lo vamos a necesitar para realizar nuestro programa, voy a daros unos breves datos de cómo almacena internamente la información la BalanceBoard.

El formato de datos usado por la Balanceboard consiste en dos partes:

  •  16 bits de datos por cada una de las células representando el peso soportado por cada una. En total 8 bytes.
  • 24 bytes de datos de calibración

DATOS DE PESO (Gracias a Wiibrew por la información):

DATOS DE CALIBRACION

El peso en cada sensor se calcula interpolando el valor devuelto por dicho sensor con las dos medidas entre las que cae dicho valor.



Utilizando la BalanceBoard en nuestro programa

Para homogeneizar el uso de los mandos y poder usar las mismas funciones que con el wiimote, en la librería WPAD se ha considerado la Balanceboard como si fuera una extensión de un wiimote adicional imaginario conectado a nuestra Wii, de tal forma que la información de la misma viene en el campo “exp” de la estructura de datos de un WPAD.

_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;	 //  Aquí 
} WPADData;

Cuando buscamos los wiimotes disponibles con la función WPAD_Probe(), la manera de saber si se trata de una BalanceBoard es comprobar que el tipo de extensión devuelto por dicha función es “WPAD_EXP_WIIBOARD”.

Podríamos utilizar por tanto las siguientes líneas de código para buscar la Balanceboard:

			ret = WPAD_Probe(i,&devtype);
			if ((ret==WPAD_ERR_NONE) && (devtype==WPAD_EXP_WIIBOARD))
				printf(‘Balanceboard encontrada’);

Una vez hemos comprobado que tenemos conectada la balanceboard debemos leer los datos que nos devuelve la misma.

La estructura de datos que utilizaremos refleja aproximadamente la que mostrábamos en la sección anterior, pero aquí además tendremos tanto los valores de peso en “bruto” como los valores interpolados, además de los valores de calibración y el centro de gravedad ya calculado:

typedef struct wii_board_t {
	/* valores interpolados */
	float tl;  // arriba a la izquierda
	float tr; // arriba a la derecha
	float bl; // abajo a la izquierda
	float br;  // abajo a la derecha
 
	/* valores en bruto*/
	short rtl;  // arriba a la izquierda
 
	short rtr; // arriba a la derecha
	short rbl; // abajo a la izquierda
	short rbr;  // abajo a la derecha
 
´	/* valores de calibración */
	short ctl[3]; 
	short ctr[3];
	short cbl[3];
	short cbr[3];
 
	/* centro de gravedad */
	float x;
	float y;
} wii_board_t;

Nosotros realmente solo necesitaremos los datos de peso interpolados y las coordenadas del centro de gravedad.

Para leer dicha información lo podemos hacer como si de un wiimote cualquiera se tratara con la función WPAD_Expansion:

WPAD_Expansion(wbb, &exp);

Y una vez leída la información, podemos fácilmente calcular el peso total sumando los valores de las cuatro esquinas, mientras que el centro de gravedad lo podemos usar directamente:

x=exp.wb.x;
y=exp.wb.y;
weight=exp.wb.tl+exp.wb.tr+exp.wb.bl+exp.wb.br; // Peso en Kg


Una aplicación práctica: creación de una báscula electrónica parlante

Para la creación de la aplicación empezaré describiendo paso a paso la secuencia de desarrollo que deberíamos seguir:

  • Creación de los gráficos.
  • Captura de los sonidos y modificación de los mismos.
  • Traducción de los sonidos a C.
  • Desarrollo del código del programa en C.

Creación de los gráficos

Para editar todos los gráficos que utilizaremos en nuestro programa utilizaremos Paint.Net (recomendado al principio) o el que desees.

Para simplificar el proceso de programación, todos los gráficos que utilizaremos los juntaremos en un solo archivo “.PNG” del cual extraeremos la textura para cada objeto según nos interese.

  • A saber, necesitaremos lo siguiente:
  • Una imagen de fondo.
  • Los dígitos del 0 al 9.
  • Una mano que nos sirva de cursor.
  • Una bola para representar el centro de gravedad.
  • Un botón para pedirle a la balanceboard que lea nuestro peso.

El gráfico resultante quedaría como sigue:

Para enlazar dicho archivo en nuestro código utilizaremos en mismo método que en el tutorial anterior. Es decir, las librerías TPL.

Como dijimos en el  tutorial anterior, necesitaremos un archivo llamados “textures.scf” en el que indicaremos la forma de carga del gráfico. El contenido de dicho archivo quedaría como sigue:

<filepath="wbb.png" id="texturas" colfmt=6 />

Aquí le indicamos que el archivo a enlazar se llama wbb.png y que debe crear una variable llamada texturas, además indica que utilizamos el formato 6 que nos permite la utilización del canal Alfa.

Copiaremos todo lo anterior en la subcarpeta Textures con lo que ya tendremos todo el trabajo de gráficos terminado.


Preparando los sonidos

Para la creación de los sonidos utilizaremos el programa Audacity, que nos permite realizar una grabación de nuestra voz, modificarla fácilmente, y conseguir un efecto muy parecido a la clásica voz que Nintendo usa para la Balance Board en el programa WiiFit.

Como en el caso del Paint.Net os he dejado un enlace a la página web del programa al principio del tutorial.


Preparando el programa:

Lo primero que debéis saber es que el formato que utilizaremos en el programa es RAW de 8 bits con signo ya que es el tipo de sonidos soportado por las librerías ASND y para que el tamaño del ejecutable final no sea más grande de lo necesario, utilizaremos una frecuencia de muestreo de 8000Hz,.

Para configurar estos parámetros seguiremos los siguientes pasos dentro del programa.

Seleccionaremos “Editar/Preferencias”.

Y en la pestaña formato de archivo seleccionaremos como formato de
exportación “Otro…”

Tras lo cual nos aparecerá una ventana que nos
permitirá seleccionar una serie de formatos adicionales. Nosotros
seleccionaremos “RAW Signed 8 bits PCM”.

Además de esto seleccionaremos en la pestaña calidad la frecuencia de muestro predeterminada con 8000Hz para hacerla coincidir con el formato que utilizaremos después en la exportación.

Grabando y modificando los sonidos:

Una vez configurado el programa, deberemos grabar todas las combinaciones de sonidos necesarias para poder leer el peso.

Si ponemos el límite de peso en 299 Kg necesitaremos los siguientes sonidos:

  • Los números del 0 al 15 necesitarán un sonido específico.
  • Los números del 16 al 19 los formaremos combinando el sonido “diez” con el sonido “y” y los sonidos de los números del seis al nueve que ya teníamos grabados.
  • El sonido “veinte” (para el 20) .
  • Con el sonido “veinti” y los sonidos “uno” al “nueve” formaremos los números 21 al 29.
  • Los sonidos “treinta”, “cuarenta”….”noventa” que con los sonidos del “uno” al “nueve” formaremos todos los sonidos que nos faltan hasta el 99.
  • Para el número 100 necesitaremos un sonido específico “cien”.

A partir de ahí los números son iguales a los números 1 a 99 pero ante-poniendo el sonido “ciento”.

Y por último necesitaremos el sonido “doscientos”.

Necesitaremos por tanto grabar cada uno de los sonidos anteriores

Y después realizar las siguientes modificaciones:

  • Cambiar el tono aumentándolo un 46%
  • Cambiar la velocidad aumentándola en un 8%.

Ambas opciones son accesibles en el menú “Efecto”.

Una vez tengamos grabado y modificado nuestro sonido deberemos exportarlo a formato RAW. Para ello seleccionaremos “Exportar RAW” en el menú de archivo. Repetiremos el proceso para todos los sonidos necesarios.


Traducción de los sonidos a C

Ahora que ya tenemos los sonidos en formato RAW se nos plantea el problema de cómo utilizarlos en nuestro programa.

Para ello utilizaremos una utilidad que viene con el devkitpro que se llama raw2c.exe (situada en “\devkitpro\devkitppc\bin”.

Esta utilidad convierte un fichero en formato RAW a un fichero “.c” con todos los bytes del archivo asignados a un array con el mismo nombre que el archivo origen. De esta manera, podremos disponer de nuestro sonido accediendo directamente a dicho array. El formato de utilización es muy sencillo, solo deberemos pasarle el nombre del archivo a traducir y él generará dos archivos, uno con extensión “.c” y otro con extensión “.h” para que podamos incluirlo en nuestro programa.

Ejemplo:

Raw2c uno.raw



Desarrollo del código del programa en C

Bueno, pues ya lo tenemos todo preparado para empezar con el programa.

La estructura general del programa es similar a la del tutorial anterior, introduciendo algunas particularidades.

  •  Inicializar el sistema de vídeo, las GX etc.
  • Cargar texturas
  • Inicializar sonido
  • Inicializar mandos y Balance board
  • Repetir mientras no se pulse Home
  • Dibujar fondo
  • Extraer información de la Balance Board y calcular peso
  • Mostrar peso
  • Dibujar posición del centro de gravedad
  • Dibujar Botón de lectura del peso y gestionarlo
  • Dibujar cursor
  • Si hemos pulsado el botón de lectura leer el peso en voz alta

El primer problema que nos vamos a encontrar para implementar este proceso es la gestión de sonidos ya que cuando mandamos un sonido nuevo a la librería de sonidos, cualquier sonido anterior que estuviera sonando deja de sonar para comenzar a sonar el nuevo sonido. Por otro lado, no podemos parar la ejecución del programa para esperar a que termine de sonar el sonido en curso, por lo que necesitamos una solución que permita esperarnos y continuar con la ejecución del programa en paralelo. 

La solución del problema anterior pasa por implementar una cola LIFO (es decir Last Input-First output) en la que iremos introduciendo los sonidos que queramos para que vayan sonando por orden de entrada.

La gestión de la cola LIFO la realizaremos sobre un array de 10 elementos:

#define MAXSONIDO 10
unsigned char * Buffer_de_Sonidos[MAXSONIDO];
unsigned int Buffer_de_TSonidos[MAXSONIDO];

Utilizando las siguientes tres funciones:

// Gestión de la cola LIFO de sonidos
int cola = 0, cabeza = 0;
bool InsertarSonido(void* pointer, unsigned int size){
	int temp = cola;
	cola++;
	if (cola==MAXSONIDO) cola=0;
	if (cola == cabeza){
		cola = temp;
		return false;
	} else {
		Buffer_de_Sonidos[cola]=pointer;
		Buffer_de_TSonidos[cola]=size;
		return true;
	}
}
 
bool ColaSonidosVacia(void){
	return cola==cabeza;
}
 
void* SacarSonido(unsigned int * size){
	if (cola == cabeza) {
		return false;
	} else {
		cabeza++;
		if (cabeza==MAXSONIDO) cabeza=0;
		*size = Buffer_de_TSonidos[cabeza];
		return Buffer_de_Sonidos[cabeza];
	}
 
}

  •  InsertarSonido nos permitirá añadir un nuevo sonido a la cola, debiendo pasar como parámetros la dirección de la variable donde tenemos guardado el sonido y su tamaño.
  • SacarSonido nos devuelve el siguiente sonido pendiente de sonar y lo elimina de la cola.
  • ColaSonidosVacia nos permite comprobar si quedan elementos en la cola.

Equipados ya con nuestras funciones de gestión de colas comenzamos ya de lleno en el código del main. Para la inicialización de vídeo he utilizado exactamente lo mismo que en tutorial anterior agrupando toda esta tarea en la función setup_video();.

Al igual que en tutorial anterior, seguidamente inicializamos las librerías de sonido, cargamos las texturas e inicializamos los mandos.

	cargar_texturas();
	ASND_Init();						
	ASND_Pause(0);	
	// Esta función inicializa los PADs conectados
	WPAD_Init();
	// Asigna la resolucion que nos devuelve el IR
	WPAD_SetVRes(WPAD_CHAN_0, 640, 480);	
	// ajusta el modo de operación de los PADS activando acelerometros y el IR
	WPAD_SetDataFormat(WPAD_CHAN_0, WPAD_FMT_BTNS_ACC_IR);
 
	cargar_texturas();
	ASND_Init();						
	ASND_Pause(0);	
	// Esta función inicializa los PADs conectados
	WPAD_Init();
	// Asigna la resolucion que nos devuelve el IR
	WPAD_SetVRes(WPAD_CHAN_0, 640, 480);	
	// ajusta el modo de operación de los PADS activando acelerometros y el IR
	WPAD_SetDataFormat(WPAD_CHAN_0, WPAD_FMT_BTNS_ACC_IR);

Una vez hemos hecho todo esto pediremos al usuario que encienda la Balance board, para lo cual insertaremos el sonido correspondiente en la cola de sonidos.

InsertarSonido(&enciendeme, enciendeme_size);

Ya dentro del bucle principal nos encontramos con la llamada a la función Sonidos() que se encarga de gestionar los sonidos que hay en la cola de sonidos. Dentro de dicha función podemos ver lo siguiente:

unsigned char * pointer=0;
unsigned int size;
if (ASND_StatusVoice(1)==SND_WAITING||ASND_StatusVoice(1)==SND_UNUSED) {
	pointer = SacarSonido(&size);
	if (pointer) {
		cont++;
		ASND_SetVoice( 1, VOICE_MONO_8BIT, 8000, 0, pointer, size, 255, 255, NULL);
	}
}
 

Como se puede ver la función comprueba si no está sonando otro sonido en el canal 1 y sólo en ese caso recupera un nuevo elemento de la cola de sonidos y lo hace sonar con la función ASND_SetVoice.

El formato de la función ASND_SetVoice es el siguiente:

s32 ASND_SetVoice (s32 voice, s32 format, s32 pitch, s32 delay, void * snd, s32 
size_snd, s32 volume_l, s32 volume_r, ASNDVoiceCallback callback)	

  • voice es el número de canal usado. Se pueden usar hasta MAX_SND_VOICES, pero nosotros solo utilizaremos una.
  • Format. Es el formato de sonido que en nuestro caso es “VOICE_MONO_8BIT”.
  • Pitch. Es la frecuencia de grabación del sonido.
  • Delay. Sirve para añadir una espera antes de hacer sonar la voz.
  • Volumen_l y volumen_r, son el volumen del altavoz izquierdo y del derecho.
  • ASNDVoiceCallback. Es un parámetro opcional que sirve para asignar una función "callback" que será llamada cuando se termine de reproducir el buffer actual. Esto suele utilizarse para implementar un doble buffer, aunque nosotros utilizaremos en su lugar nuestra gestión de colas LIFO.
Volviendo al bucle principal del main nos encontramos con algunas funciones de gestión de texturas y descriptores de vértices que ya explicamos en el tutorial anterior.
		/************* Limpia la memoria *************/
		// Asigna el viewport
		GX_SetViewport(0,0,rmode->fbWidth,rmode->efbHeight,0,1);
		// limpiar la cache de vertices
		GX_InvVtxCache();
		// limpiar la memoria de texturas
		GX_InvalidateTexAll();
 
		// cargamos textura correcta
		GX_LoadTexObj(&texObj, GX_TEXMAP0);
 
		// limpia todos los atributos de vertice
		GX_ClearVtxDesc();
		// Vuelve a asinar los atributos de vertice
		GX_SetVtxDesc(GX_VA_POS, GX_DIRECT);
		GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT);
 
 
		// Comienza cargando la matriz identidad en GXmodeView2D
		guMtxIdentity(GXmodelView2D);
 
		// Movemos el modelo 5.0f unidades hacia atras sobre el eje Z
		guMtxTransApply (GXmodelView2D, GXmodelView2D, 0.0F, 0.0F, -5.0F);
		GX_LoadPosMtxImm(GXmodelView2D,GX_PNMTX0);
Seguidamente leemos el valor del IR para saber donde tenemos que dibujar la mano que representará el cursor.
WPAD_IR(pad, &ir);
Inmediatamente después vemos las llamadas a las funciones que dibujan el fondo y el botón de lectura del peso:
dibujar_fondo();
dibujar_Boton();
Entrando un poco más en detalle en dichas funciones podemos ver lo siguiente:
void dibujar_fondo(void){
	GX_Begin(GX_QUADS, GX_VTXFMT0, 4);			
		GX_Position2f32(0, 0);										
		GX_TexCoord2f32(0.0,0.0);
		GX_Position2f32(639, 0);			
		GX_TexCoord2f32(1.0,0.0);
		GX_Position2f32(639,479);
		GX_TexCoord2f32(1.0,0.79);
		GX_Position2f32(0,479);		
		GX_TexCoord2f32(0.0,0.79);
	GX_End();		 
}
La función dibujar_fondo consiste simple y llanamente en dibujar un QUAD utilizando como textura la parte correspondiente a la foto de la Wii que tenemos en el .PNG de las texturas.
Seleccionamos dicha parte de la imagen indicando las coordenadas de textura correspondientes en cada llamada a GXCoord2f32 y teniendo en cuenta que las coordenadas de textura van de 0 a 1.  En este caso las sección de la textura que estamos utilizando será el cuadrado delimitado por los vértices: (0.0, 0.0) – (0.0, 0.79).
Para el caso del botón hacemos exactamente lo mismo, pero en este caso utilizamos las coordenadas de textura: (0.099, 0.90) – (0.418, 0.98) Volvemos otra vez al bucle principal del main, en el que escaneamos los mandos y pasamos a la búsqueda de la Balance board a través de la función WPAD_Probe tal y como hemos visto anteriormente:
// Esto lee el estado de los mandos a cada ciclo del bucle
WPAD_ScanPads();
int ret = -1;
for (i=0;i<WPAD_MAX_WIIMOTES;i++) //always check that's its there
{
	u32 devtype;
	ret = WPAD_Probe(i,&devtype);
	if ((ret==WPAD_ERR_NONE) && (devtype==WPAD_EXP_WIIBOARD))
	{
		wbb=i;
		check=true;
		break;
	}
}
En dicho bucle hacemos un barrido por todos los mandos para comprobar si alguno de ellos tiene una extensión del tipo WPAD_EXP_WIIBOARD. Seguidamente, y solo en el caso de que hayamos conseguido encontrar la Balanceboard ya encendida pasamos a la lectura de los datos y al cálculo del peso.
if (check){
		if (!agradecido) {
			if (ASND_TestVoiceBufferReady(1)) {
				// agradecer el encendido de la tabla
				InsertarSonido(&gracias, gracias_size);
				// pedir al usuario que se suba al la tabla
				InsertarSonido(&PSM, PSM_size);
				agradecido = true;
			}
		}
		// Lectura de los datos de la tabla y cálculo del peso
		WPAD_Expansion(wbb, &exp);
		x=exp.wb.x;
		y=exp.wb.y;
		weight=exp.wb.tl+exp.wb.tr+exp.wb.bl+exp.wb.br; // Peso en Kg
 
		//desglose del peso en centenas, decenas y unidades
		centena = weight/100;
		decena = fmod(weight,100)/10;
		unidades = fmod(weight,10);
		// Mostrarlos valores desglosados en cada uno de los dígitos
		dibujar_centena(centena);
		dibujar_decena(decena);
		dibujar_unidades(unidades);
	} else 	{ x=0; y=0; weight = 0; agradecido = false;}
 
	if (check){
		if (!agradecido) {
			if (ASND_TestVoiceBufferReady(1)) {
				// agradecer el encendido de la tabla
				InsertarSonido(&gracias, gracias_size);
				// pedir al usuario que se suba al la tabla
				InsertarSonido(&PSM, PSM_size);
				agradecido = true;
			}
		}
		// Lectura de los datos de la tabla y cálculo del peso
		WPAD_Expansion(wbb, &exp);
		x=exp.wb.x;
		y=exp.wb.y;
		weight=exp.wb.tl+exp.wb.tr+exp.wb.bl+exp.wb.br; // Peso en Kg
 
		//desglose del peso en centenas, decenas y unidades
		centena = weight/100;
		decena = fmod(weight,100)/10;
		unidades = fmod(weight,10);
		// Mostrarlos valores desglosados en cada uno de los dígitos
		dibujar_centena(centena);
		dibujar_decena(decena);
		dibujar_unidades(unidades);
	} else 	{ x=0; y=0; weight = 0; agradecido = false;}
En las líneas anteriores lo primero que hacemos es comprobar si la tabla acaba de ser encendida, para agradecérselo al usuario y pedirle que se suba a ella:
if (ASND_TestVoiceBufferReady(1)) {
	// agradecer el encendido de la tabla
	InsertarSonido(&gracias, gracias_size);
	// pedir al usuario que se suba al la tabla
	InsertarSonido(&PSM, PSM_size);
	agradecido = true;
}
Seguidamente, extraemos la información de la tabla y calculamos el peso tal y como hemos visto en el apartado anterior:
// Lectura de los datos de la tabla y cálculo del peso
WPAD_Expansion(wbb, &exp);
x=exp.wb.x;
y=exp.wb.y;
weight=exp.wb.tl+exp.wb.tr+exp.wb.bl+exp.wb.br; // Peso en Kg
Una vez hemos calculado el peso, necesitamos desglosarlo en centenas, decenas y unidades para poder mostrarlo después mediante dígitos.
dibujar_centena(centena);
dibujar_decena(decena);
dibujar_unidades(unidades);
Funciones que utilizan la misma técnica que para el caso del fondo o del botón, solo que en este caso las coordenadas de textura dependen del parámetro que le pasamos:
void dibujar_digito(int x, int y, int n){
float tx = n*0.092+0.070;
float ty = 0.81;
float h = 0.075;
float w = 0.072;
float dw=43;
float dh=45;
	GX_Begin(GX_QUADS, GX_VTXFMT0, 4);			
		GX_Position2f32(x, y);
		GX_TexCoord2f32(tx,ty);
		GX_Position2f32(x+dw, y);			
		GX_TexCoord2f32(tx+w,ty);
		GX_Position2f32(x+dw,y+dh);	
		GX_TexCoord2f32(tx+w,ty+h);
		GX_Position2f32(x,y+dh);		
		GX_TexCoord2f32(tx,ty+h);
	GX_End();		
}
 
void dibujar_centena(int n){
	dibujar_digito(248, 106, n);
}
void dibujar_decena(int n){
	dibujar_digito(305, 106, n);
}
 
void dibujar_unidades(int n){
	dibujar_digito(362, 106, n);
}

Como podemos observar, las funciones dibujar_centena, dibujar_decena y dibujar_unidades, llaman a la función dibujar_digito con distintas coordenadas cada una.
En la función dibujar dígito, lo que hacemos es establecer las coordenadas de textura mediante un cálculo, que partiendo del valor pasado,  determina las coordenadas de textura del digito a utilizar.
Una vez hemos dibujado el peso, comprobamos los botones pulsados.
u32 pressed = WPAD_ButtonsDown(pad); 
Dibujamos la bolita en la posición del centro de gravedad  
dibujar_CG(x, y);
Y dibujamos la mano que nos sirve de cursor.
dibujar_mano(ir.x, ir.y, ir.angle);
En este caso, además de mostrar un Quad con una textura determinada aplicaremos un ángulo de rotación que permitirá que la mano siga la rotación del wiimote según el valor devuelto en ir.angle.
void dibujar_mano(int x, int y, float angle){
Mtx model;
	guVector Zaxis = {0,0,1};
 
	guMtxIdentity(model);
	guMtxRotAxisDeg(model, &Zaxis, angle);
	guMtxTransApply(model, model, x, y, 0);
	// load the modelview matrix into matrix memory
	GX_LoadPosMtxImm(model, GX_PNMTX0);
 
	GX_Begin(GX_QUADS, GX_VTXFMT0, 4);			
		GX_Position2f32(-20, -30);					
		GX_TexCoord2f32(0.0,0.807);
		GX_Position2f32(+20, -30);			
		GX_TexCoord2f32(0.055,0.807);
		GX_Position2f32(+20,+30);	
		GX_TexCoord2f32(0.055,0.895);
		GX_Position2f32(-20,+30);					GX_TexCoord2f32(0.0,0.895);
	GX_End();									
}
En este caso es muy importante el cuadrado tenga el origen de coordenadas en 0,0 antes de realizar la rotación, porque si no, no podremos aplicar correctamente la rotación. 
La función guMtxIdentity(model) nos permite obtener una matriz identidad para utilizar como base. Inmediatamente después rotamos el plano respecto del eje Z (o sea de un eje perpendicular a la pantalla) con la función guMtxRotAxisDeg(model, &Zaxis, angle). Y como habíamos dibujado el Quad respecto al origen de coordenadas, ahora deberemos trasladar el plano a la posición marcada en X,Y mediante la función guMtxTransApply(model, model, x, y, 0).
Una vez terminadas las transformaciones debemos cargar la matriz en memoria para que el sistema la dibuje al final del bucle actual GX_LoadPosMtxImm(model, GX_PNMTX0). Después de las funciones de gestión del buffer de gráficos, pasamos a la sección del código que comprueba si hemos pulsado el botón de lectura del peso y selecciona los sonidos que debe insertar en la cola de sonidos para leer correctamente el peso.
Básicamente el algoritmo en pseudocódigo seria como sigue:
Si pulsamos el botón A y el puntero está dentro de los límites del botón
 
{
 
	Si la centena es 1 {
 
		Si es el número 100 leemos “cien”
 
		En caso contrario leemos ciento	
 
	}
 
	Si la centena es 2 leemos “doscientos”
 
	Si la decena es 1{
 
Si las unidades están entre 1 y 5 leer “once”, “doce”..... o “quince”
 
En caso contrario leer “diez”
 
	}
 
	Si la decena es 2{
 
		Si es el número 20 leer “veinte”
 
		En caso contrario leer “veinti”
 
	}
 
	Si la decena está entre 3 y 9 leer “treinta”, “cuarenta”…..o “noventa”
 
 
 
Leer “y” salvo en los siguientes casos:
 
	El número es menor de 15 
 
	veinte que se lee “veinti”
 
	Es múltiplo de 10
 
Si el número no está entre 10 y 15 
 
	Si el número es exactamente 0 entonces leer “cero”
 
	Si las unidades están entre 1 y 9 Leer las unidades (“uno”, “dos”, “tres”…… “nueve”)
 
	Leemos “Kilogramos” 
El código correspondiente en C para el algoritmo anterior quedaría como sigue:
if ((pressed & WPAD_BUTTON_A) && 
	(ir.x >= 275) && (ir.x <= 380) &&
	(ir.y >= 450) && (ir.y <= 479)) 
{
		switch (centena) {
			case 1:
				if ((decena==0)&&(unidades==0)) { //si es el 100 leemos “cien”
					InsertarSonido(&cien, cien_size);
				} else {
					InsertarSonido(&ciento, ciento_size); //en otro caso “ciento”
				}
				break;
			case 2: 
				InsertarSonido(&doscientos, doscientos_size);
				break;
		}
		switch (decena) {
			case 1: 
				switch (unidades){
					case 1:
						InsertarSonido(&once, once_size);
						break;
					case 2:
						InsertarSonido(&doce, doce_size);
						break;
					case 3:
						InsertarSonido(&trece, trece_size);
						break;
					case 4:
						InsertarSonido(&catorce, catorce_size);
						break;
					case 5:
						InsertarSonido(&quince, quince_size);
						break;
					default:
						InsertarSonido(&diez, diez_size);
						break;
				}
					break;
			case 2:
				if (unidades==0)
					InsertarSonido(&veinte, veinte_size);
				else
					InsertarSonido(&veinti, veinti_size);		
				break;
			case 3:
				InsertarSonido(&treinta, treinta_size);
				break;
			case 4:
				InsertarSonido(&cuarenta, cuarenta_size);
				break;
			case 5:
				InsertarSonido(&cincuenta, cincuenta_size);
				break;
			case 6:
				InsertarSonido(&sesenta, sesenta_size);
				break;
			case 7:
				InsertarSonido(&setenta, setenta_size);
				break;
			case 8:
				InsertarSonido(&ochenta, ochenta_size);
				break;
			case 9:
				InsertarSonido(&noventa, noventa_size);
				break;
	}
 
	if ((decena != 2) && (unidades != 0) && (decena != 0) && 
		(!((decena==1)&&(unidades<=5)))) 
		InsertarSonido(&sonidoy, sonidoy_size);
	if ((decena != 1) || (unidades > 5)) {
		switch (unidades) {
			case 0:
				if ((decena==0)&&(centena==0))
					InsertarSonido(&cero, cero_size);
				break;
			case 1:
				InsertarSonido(&uno, uno_size);
				break;
			case 2:
				InsertarSonido(&dos, dos_size);
				break;
			case 3:
				InsertarSonido(&tres, tres_size);
				break;
			case 4:
				InsertarSonido(&cuatro, cuatro_size);
				break;
			case 5:
				InsertarSonido(&cinco, cinco_size);
				break;
			case 6:
				InsertarSonido(&seis, seis_size);
				break;
			case 7:
				InsertarSonido(&siete, siete_size);
				break;
			case 8:
				InsertarSonido(&ocho, ocho_size);
				break;
			case 9:
				InsertarSonido(&nueve, nueve_size);
				break;
		}
	}
	InsertarSonido(&Kilogramos, Kilogramos_size);
 
}
Y ya lo tenemos, una bonita báscula parlanchina. Yo no sé vosotros, pero yo según voy aprendiendo más cosas de la programación para Wii voy disfrutando cada vez más.
4.15909
Tu voto: Ninguno Votos totales: 4.2 (44 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 rayosbute

Ya quiero ver un app con tu nombre.

Tengo que verlo. Muy buenos tutoriales.

Paz!!

Imagen de wilco2009

Estoy en ello

Estoy en ello Rayosbute....

Primero espero publicar una más sencilla para ir soltando la mano, y más adelante ya tengo pensado algo con modelado en 3D, pero de momento esa esperará un poco.

Por cierto, para esa segunda aplicación me vendría de maravilla alguien que tuviera buena mano con el 3DStudio....interesados enviadme un MP.

 

 


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 Kai-Kun

Creo que

Creo que tenemos la misma idea, hacer modelos 3d de objetos y a partir de ahi generar "sprites" usables para un juego, manejo 3d max y estoy casi igual que tu, buscando gente que sepa de lo mismo para poder tirarme al agua con un juego de wii, creo que tu lo lograras antes que yo xD, saludos

Imagen de wilco2009

Te propongo que colaboremos

Te propongo que colaboremos en algún programa.

De momento estoy programando una aplicación en 3D que creo que puedo tener lista en una o dos semanas.

No creo que el tema sea el colmo de la popularidad pero yo estoy disfrutando y sobre todo aprendiendo para futuras aplicaciones.

Para los que tienen algunos años a sus espaldas, como yo, y les gustan los temas científicos, igual recuerdan una sección de la revista Scientific American que llevaba A.K. Dewdney y que se llamaba Computer Games y que proponía un tema de programación cada mes.

En esta sección se trataban temas de programación recreativa basada en conceptos científicos y de simulación.

En uno de los números de la revista, propuso la programación de una versión en 3D de un programa de simulación de automatas celulares ideado por John Conway y llamado "The Game of Life"  http://en.wikipedia.org/wiki/Conway's_Game_of_Life

Mi programa es una implementación para Wii de ese programa en 3D, con su editor de mundos y de artefactos. Además se utiliza los Mii como forma de seleccionar tu configuración.

Con este programa estoy tocando un poco de todo, manejo de los mandos, introducción de textos por pantalla, programación en 3D, acceso a ficheros en la SD y en la NAND, texturas, botones, menús.........

Cuando acabe con este programa pretendo hacer algo más comercial, pero me vendría bien algo de colaboración, por lo que si te animas, estoy dispuesto a formar equipo.

Dime algo.


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 Kai-Kun

yo me apunto

yo me apunto a trabajar contigo, pero definitivamente no puede ser ahora, tendria que ser de aqui a unos 2~3 meses si todo va como lo planeo ya que afortunadamente tengo un trabajo grande que cumplir, ademas estoy metido en varios proyectos que van desde musica hasta organización de eventos (pensamos hacer un "tetris con humanos" con musica en vivo y eso en una convencion en mi pais, pero de momento todo esta de cabeza) y si te digo que si ahora te quedaria mal y es algo que no quiero, por otro lado, lo que comentas es realmente impresionante e interesante, me encantan los temas de inteligencia artificial (y a la vez los odio porque pueden ser muy complicados), hablando con un amigo pensabamos crear un juego pero mas dinamico, te mencionaba lo del 3D porque el juego que pensamos hacer es de naves al mero estilo de los años 90, pero los modelos de las naves tendrian bases en modelos 3D y a partir de ahi se sacan los sprites colocando los modelos en distintas posiciones, hasta cierto punto es mas facil de la forma que te estoy diciendo, y la programación es similar a un juego Sidescroll, volviendo al tema, me gustaria colaborar contigo pero te repito, en este momento no puedo ya que como dicen, quien mucho abarca poco aprieta y si me pongo en otro proyecto de este tamaño todo me va a colapsar y quedare mal con todo mundo y es algo que definitivamente no quiero, un saludo

Imagen de wilco2009

Pues cuando tengas tiempo,

Pues cuando tengas tiempo, aquí estoy. No tienes más que decírmelo y buscamos un tema de programación.

Suerte con el trabajo que llevas entre manos.


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

wm+ y Blender 3D

exelentes tutos Risa

tienes pensado tratar el uso del wm+?

seria interesante poder usar esta tecnologia.

y tambien; yo sugiero el uso de Blender en lugar del 3Dstudio.

digo, si ya usaste el Audacity, por que no recomendar el Blender.

Imagen de wilco2009

He sugerido 3DStudio porque

He sugerido 3DStudio porque es el formato que conozco. He encontrado por ahí como interpretar los archivos 3DS para convertirlos en vertices en un array.

De todas formas lo único que necesito es un archivo final .3DS  o la forma de leer el formato de Blender.


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 JAVIenigma

Excelente Wilco, saludos!

Excelente Wilco, saludos!

Imagen de wilco2009

Muchas gracias Javi!!

Muchas gracias Javi!!

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.