utilizzo di wiimote e balance board come strumento per la
Transcript
utilizzo di wiimote e balance board come strumento per la
POLITECNICO DI MILANO FACOLTÀ DI INGEGNERIA CORSO DI LAUREA IN INGEGNERIA INFORMATICA UTILIZZO DI WIIMOTE E BALANCE BOARD COME STRUMENTO PER LA RIABILITAZIONE IN APPLICAZIONI REALIZZATE CON IL FRAMEWORK XNA Relatore: Prof. Alessandro CAMPI Correlatore: Ing. Paola SPOLETINI Tesi di Laurea di: Enrico BONTEMPI Matricola n. 704443 Roberto CARETTONI Matricola n. 704099 ANNO ACCADEMICO 2009-2010 1 Indice Indice .................................................................................................................................2 Capitolo 1. Introduzione.................................................................................................5 Capitolo 2. L’innovazione di Nintendo Wii ....................................................................6 Capitolo 3. Il Wiimote [4] ..............................................................................................7 3.1 Pulsanti ................................................................................................................8 3.2 Accelerometro .....................................................................................................9 3.2.1 Accelerazione statica e dinamica ...................................................................9 3.2.2 Interpretazione dei valori rilevati ................................................................10 3.2.3 Calcolo delle inclinazioni degli assi ............................................................10 3.3 Puntamento Infrarosso .......................................................................................12 3.3.1 Sensor Bar ..................................................................................................12 3.3.2 Tecnica di puntamento ................................................................................13 3.3.3 Posizione di puntamento .............................................................................13 3.3.4 Levigatura del cursore.................................................................................14 3.4 Altre funzionalità ...............................................................................................15 3.4.1 LED ............................................................................................................15 3.4.2 Rumble .......................................................................................................15 3.4.3 Speaker .......................................................................................................15 3.5 Estensioni ..........................................................................................................16 3.5.1 Nunchuk .....................................................................................................16 3.5.2 Classic Controller .......................................................................................17 3.5.3 Wii Motion Plus ..........................................................................................17 3.5.4 Wii Balance Board ......................................................................................18 Capitolo 4. 4.1 Interfacciamento e connessione dei dispositivi ...........................................19 HID [5] ..............................................................................................................19 4.1.1 L’innovazione di HID .................................................................................19 4.1.2 Il protocollo HID ........................................................................................20 4.1.3 Bluetooth HID ............................................................................................20 4.2 Bluetooth [6]......................................................................................................21 2 4.2.1 BlueSoleil [7] .............................................................................................21 4.2.2 Connessione del Wiimote ...........................................................................22 4.3 Wiimotelib .........................................................................................................24 4.3.1 Creazione del canale di comunicazione .......................................................24 4.3.2 Trasmissione dei pacchetti ..........................................................................26 Capitolo 5. Ambiente di Sviluppo .................................................................................28 5.1 Microsoft Visual Studio 2008 [12] .....................................................................28 5.2 C# [13] ..............................................................................................................28 5.3 Il Framework XNA [15].....................................................................................29 5.4 Struttura di un progetto XNA [16]......................................................................29 5.4.1 Metodi predefiniti .......................................................................................30 5.4.2 Componenti ................................................................................................30 5.4.3 Grafica 2D ..................................................................................................31 5.5 Audio .................................................................................................................32 5.5.1 XACT .........................................................................................................32 5.5.2 Classe statica Audio ....................................................................................32 5.6 Requisiti di piattaforma ......................................................................................34 Capitolo 6. 6.1 Ideazione del software ................................................................................35 Specifiche del software ......................................................................................35 6.1.1 Design della batteria ...................................................................................35 6.1.2 Criteri di movimento ...................................................................................36 6.1.3 Composizione e disegno della batteria ........................................................39 6.1.4 Determinazione e controllo della posizione del centro di massa ..................40 6.1.5 Fase di gioco ...............................................................................................41 6.1.6 Modalità Free .............................................................................................42 Capitolo 7. 7.1 Gestione del Wiimote con Wiimotelib ........................................................43 La classe Wiimote..............................................................................................43 7.1.1 Metodi ........................................................................................................44 7.1.2 Eventi .........................................................................................................44 7.1.3 WiimoteCollection ......................................................................................44 7.2 Le strutture dati..................................................................................................45 7.3 Eccezioni ...........................................................................................................47 3 7.4 Implementazione della classe WiiMote ..............................................................47 7.4.1 Capitolo 8. 8.1 Metodi della classe WiiMote.......................................................................48 Implementazione del videogame ................................................................49 La classe DrumAble ...........................................................................................50 8.1.1 Modalità di esecuzione ...............................................................................51 8.1.2 Compiti della classe DrumAble...................................................................51 8.2 I componenti della sezione menu .......................................................................52 8.2.1 La classe Menu ...........................................................................................52 8.2.2 La classe Istruzioni .....................................................................................52 8.2.3 La classe Tracklist ......................................................................................52 8.2.4 La classe Speed...........................................................................................53 8.2.5 La classe RiproduzioneSequenza ................................................................53 8.3 Le tracce predefinite ..........................................................................................53 8.3.1 La classe Traccia ........................................................................................53 8.3.2 I DataSet .....................................................................................................54 8.4 L’input della fase di gioco ..................................................................................54 8.4.1 La classe Percussione ..................................................................................54 8.4.2 Rilevamento dei gesti..................................................................................55 8.4.3 Evento PercussioneChanged .......................................................................55 8.4.4 La classe BalanceBoard ..............................................................................55 8.5 I componenti della fase di gioco .........................................................................56 8.5.1 La classe PlayScreen ...................................................................................56 8.5.2 La classe Logica .........................................................................................57 Capitolo 9. Sviluppi futuri.............................................................................................58 Elenco figure ...................................................................................................................59 Elenco Tabelle .................................................................................................................59 Bibliografia ......................................................................................................................60 4 Capitolo 1. Introduzione Nel 2006 Nintendo lancia la console Wii [1], appartenente alla settima generazione [2], la cui innovazione è insita nella nuova natura dei controller, che non sono più dei semplici telecomandi che permettono di comandare i giochi soltanto premendo dei pulsanti, ma dispositivi in grado di rilevare il movimento del corpo o di alcune sue parti rendendo così possibile un’associazione tra gesti compiuti dai giocatori e azioni di risposta all’interno dei videogame. Questo lavoro si colloca in un più ampio progetto di sviluppo di applicazioni rivolte a soggetti con disabilità motorie [3], quali individui paraplegici. Tale progetto consiste nella creazione di videogiochi con finalità terapeutiche, con l’intento cioè di intrattenere gli utenti stimolandoli a compiere determinati movimenti, introducendo così l’uso di questi software ad esempio nella riabilitazione post-trauma. Grazie alle loro caratteristiche, i controller di Wii si prestano particolarmente a questo ambito di progetto, e sono l’ideale strumento di interazione con l’utente in applicazioni di questo genere. L’obiettivo di questo lavoro è sfruttare la tecnologia del Wiimote e della Balance Board mediante la creazione di interessanti applicazioni indipendenti dai pulsanti e governabili il più possibile attraverso i movimenti di un Wiimote e il rilevamento del baricentro tramite la Balance Board. Il prodotto di questo lavoro è un software che simula una batteria musicale, utilizzabile mediante il compimento di diversi gesti con il Wiimote, stando seduti sulla Balance Board. Questo progetto permette di estendere l’ambito dei lavori svolti in passato, che si concentravano principalmente sull’equilibrio e sul movimento del busto mediante l’uso esclusivo della Balance Board, all’utilizzo degli arti superiori. 5 Capitolo 2. L’innovazione Nintendo Wii di Le innovazioni introdotte con Nintendo Wii [1] aprono varie frontiere nel videogaming in quanto l’utilizzo di movimenti come input per i giochi permette di modellare in maniera molto più naturale le interazioni con l’utente. Diventa così possibile simulare i gesti compiuti in discipline sportive, nell’uso di strumenti musicali o di utensili attraverso i telecomandi di Wii, e introdurre tutte queste attività in svariati videogame che riscuotono notevole successo. Il controller principale della console Wii è il Wiimote; è un telecomando senza fili che comunica con la console attraverso la tecnologia Bluetooth. Il Wiimote è dotato di pulsanti, di un accelerometro in grado di rilevare i movimenti impressi al telecomando, e di altri dispositivi che consentono l’interazione sia per l’input che per l’output. Al Wiimote possono essere collegati mediante un apposito connettore altri controller tra cui: Nunchuk, Classic Controller, WiiMotionPlus, chitarra e batteria di Guitar Hero e altri. Questi dispositivi vengono identificati dalla console come estensioni del controller principale, e il flusso di informazioni trasmesse relativo ad un’estensione viene inglobato nelle informazioni del Wiimote. È possibile collegare una sola estensione al Wiimote, a meno che si tratti del WiiMotionPlus, che dispone di un connettore per estensioni, agendo così in modo “trasparente” e permettendo l’inserimento di una seconda estensione. Un altro controller di Wii è la Wii Balance Board; è una pedana che comunica via Bluetooth con la console attraverso lo stesso protocollo utilizzato dal Wiimote, ma che differisce da quest’ultimo come tecnologia interna in quanto è composta da quattro bilance che rilevano lo spostamento del peso dell’utente che si posiziona sopra di essa. 6 Capitolo 3. Il Wiimote [4] Il controller di Nintendo Wii utilizza un approccio di interazione differente da quello tradizionale, nel tentativo di risultare interessante per un pubblico più vasto. Il Wiimote ha la forma di un comune telecomando da televisione e viene tenuto in una sola mano; Essendo simmetrico, appare ugualmente utilizzabile da destrorsi e mancini. Il componente principale del Wiimote è il chip Broadcom; esso è dotato di alcuni registri e di un microcontrollore, attraverso cui gestisce il flusso interno dei dati (input e output dalle periferiche interne) e le trasmissioni con la console. Il chip fa da riferimento per gli altri componenti interni al dispositivo, in quanto la struttura del Wiimote è progettata intorno ad esso. Vi sono due funzionalità di input direttamente controllate dal chip: un accelerometro a tre assi e 11 pulsanti (più il pulsante Power). In aggiunta, il telecomando, contiene un ricevitore infrarosso con un processore di monitoraggio oggetti, una porta d’espansione che permette di collegarvi fonti di input addizionali (le estensioni), uno speaker e un “rumble pack” che consente al telecomando di vibrare. Figura 1: Wiimote 7 3.1 Pulsanti Il Wiimote ha 11 pulsanti sul lato frontale e uno sul retro; tra questi, il pulsante Power è speciale ed è considerato differentemente dagli altri dal dispositivo. Tutti gli altri pulsanti sono indipendentemente accessibili attraverso un pacchetto di 2 byte che viene trasmesso per primo nella maggior parte dei report. Il bit corrispondente ad un pulsante assumerà valore 1 se il pulsante è premuto oppure 0 in caso contrario. Di norma questi pacchetti vengono inviati quando lo stato di qualche pulsante cambia, ma è anche possibile configurare il Wiimote affinché invii lo stato dei pulsanti continuamente attraverso un’alterazione del Data Reporting Mode. I pulsanti dei Wiimote sono i seguenti: A, B (retro), un Pad direzionale, +, -, Home, 1 e 2. Quando il Wiimote è spento, la pressione del pulsante Power provoca un tentativo di riattivazione della comunicazione con la Wii a cui è sincronizzato. I dettagli implementativi che portano all’accensione non sono stati resi pubblici e sono contenuti nel modulo Bluetooth di Wii. La connessione del telecomando con un diverso host (pc) non può invece avvenire automaticamente ma occorre ripetere il procedimento di connessione dal software Bluetooth dell’host. Se il Wiimote è acceso e connesso a un host, la pressione e il mantenimento del pulsante Power per qualche secondo fa sì che il telecomando richieda una disconnessione dall’host e si spenga. Vi è inoltre un ulteriore pulsante nascosto nel vano batterie: il Sync Button. Alla pressione di tale tasto il Wiimote si disconnette dall’host con il quale ha una connessione attiva e si pone in modalità di rilevazione accettando richieste di connessione o accoppiamento per esattamente 20 secondi. 8 3.2 Accelerometro Il Wiimote contiene un accelerometro lineare a tre assi posto sulla faccia superiore della base del circuito interno, leggermente a sinistra del pulsante A. Si tratta di un componente integrato semplicemente saldato al circuito: l’ADXL330 di Analog Devices. Questo dispositivo può misurare l’accelerazione di gravità statica per applicazioni che percepiscono l’inclinazione, così come l’accelerazione dinamica derivante da movimenti, scosse o vibrazioni. La misurazione avviene con valore minimo di fondo scala di ±3g e una sensibilità del 10%. 3.2.1 Accelerazione statica e dinamica Poiché il funzionamento reale dell’accelerometro consiste nella misura della forza esercitata da un insieme di piccole masse di resistenza poste al suo interno nei confronti del guscio che le contiene, esso misura un’accelerazione lineare di un punto di riferimento in caduta libera: questo significa che se il Wiimote fosse in caduta libera, riporterebbe accelerazione zero. Quand’è immobile invece, rileva un’accelerazione pari all’accelerazione di gravità g (ma nella direzione opposta, verso l’alto, +Z quando è fermo in posizione orizzontale). Questo dato può essere usato per intuire l’inclinazione del telecomando dagli output di accelerazione quando il Wiimote è ragionevolmente fermo. Figura 2: Wiimote e assi direzionali 9 3.2.2 Interpretazione dei valori rilevati La Figura 2 rappresenta il Wiimote e gli assi di riferimento dell’accelerometro: l’orientamento degli assi permette di interpretare il valore letto per ognuno di essi e dedurne l’inclinazione rispetto alla posizione piana (orizzontale) oppure la direzione del movimento dell’accelerazione rilevata. Durante la fase sperimentale di studio del Wiimote si è notato che non tutti i movimenti vengono rilevati, ma il valore relativo ad un asse varia soltanto se tale asse si muove ruotando in un piano, necessariamente ortogonale al suolo, che lo contiene. Ad esempio il movimento rotatorio del polso, mantenendo il telecomando in posizione orizzontale, può essere modellizzato come la rotazione del piano XZ intorno all’asse Y che funge da perno; tale movimento può essere rilevato dalle variazioni dei valori dei tre assi, riconoscendo una variazione positiva o negativa dei valori di X e Z (a seconda che la rotazione sia avvenuta in senso orario o antiorario) e una conservazione del valore precedente di Y. Al contrario, un movimento rotatorio del telecomando appoggiato su un piano (rotazione del piano XY con perno l’asse Z) non può essere rilevato in quanto l’asse Z funziona da perno e quindi non subisce scostamenti, e nonostante gli assi X e Y stiano effettivamente ruotando, non ne viene riscontrata una variazione dei valori in quanto il piano da essi costituito è parallelo al suolo e non ortogonale, quindi anche ripetendo o velocizzando il movimento l’accelerometro non rileverebbe variazioni: come se il telecomando fosse fermo. 3.2.3 Calcolo delle inclinazioni degli assi Come conclusione allo studio del funzionamento dell’accelerometro nell’ambito dell’accelerazione statica, si è cercata una formula che permettesse di tradurre i valori letti dal dispositivo nelle rispettive inclinazioni degli assi corrispondenti, interpretate come sfasamenti da una posizione base, e cioè un angolo di 0° equivalente a una posizione orizzontale, parallela al suolo, dell’asse. A seconda dell’inclinazione dell’asse, il valore letto dal telecomando assume valori compresi tra +1 e -1. Definito l’orientamento degli assi come mostrato in Figura 2, si è 10 messo in relazione il valore letto con la posizione dell’asse, raggiungendo le conclusioni seguenti: • Se l’asse (X, Y, Z) si trova in posizione orizzontale, e cioè ortogonale alla direzione della forza di gravità, il valore rilevato è 0 • Se l’asse si trova nella stessa direzione della forza di gravità e con verso concorde (verso il basso), il valore rilevato è -1 • Se l’asse si trova nella stessa direzione della forza di gravità ma con verso discorde (verso l’alto), il valore rilevato è +1 Ponendo a questo punto gli angoli corrispondenti alle posizioni limite (aventi la direzione della forza di gravità con verso concorde o discorde) rispettivamente -90° e +90°, si può scrivere la seguente equazione che mette in relazione angoli e valori (fissati da un’ipotesi teorica) di due posizioni limite: (Y90° - Yα) : (Y90° - Y0°) = (90° - α) : (90° - 0°) È un’interpolazione lineare dove: • Y90° indica il valore di Y letto quando l’asse Y si trova a +90° (Y90° = -1) • Yα indica il valore di Y letto quando l’asse Y si trova all’angolo α • Y0° indica il valore di Y letto quando l’asse Y si trova a 0° (Y90° = 0) • α è l’angolo corrispondente al valore dell’asse Y letto (Yα) Da questa interpolazione si può ricavare la formula finale: α = -90° · Yα Che permette effettivamente di identificare in modo univoco l’angolo (di sfasamento) corrispondente al valore dell’asse letto. In Figura 2 sono indicati anche tre movimenti che in realtà non sono rilevabili dal Wiimote ma possono essere individuati se si dispone del WiiMotionPlus, che verrà successivamente trattato nella sezione estensioni. 11 3.3 Puntamento Infrarosso Il Wiimote contiene un ricevitore monocromo 128x96 con un elaboratore d’immagine integrato. Il ricevitore si presenta come un filtro infrarosso nella custodia di plastica del telecomando. L’elaboratore d’immagine è capace di puntare fino a quattro oggetti in movimento, e questi sono gli unici dati che trasmette all’host; i dati relativi ai pixel grezzi “visti” dalla telecamera non sono raggiungibili dall’host, pertanto il ricevitore non può essere usato per catturare immagini. Il processore integrato effettua un’analisi sub pixel 8x per fornire una risoluzione 1024x768 dei punti tracciati. 3.3.1 Sensor Bar La Wii dispone di una Sensor Bar contenente due gruppi di LED IR (infrarossi), che vengono tracciati dal Wiimote per fornire informazioni sul puntamento. La distanza tra i centri dei gruppi di LED è 20cm. La Sensor Bar non svolge nessun compito se non quello di supporto e alimentazione (tramite un cavetto particolare che la collega alla console) ai LED IR: funge in pratica soltanto da emettitore infrarosso. I LED IR costituiscono i punti di riferimento per il ricevitore infrarosso del Wiimote: questa correlazione permette di sfruttare un tecnica di puntamento nelle applicazioni; i valori letti vengono spesso elaborati e convertiti ad esempio per l’uso di un cursore governato dal movimento del telecomando. Figura 3: Sensor Bar 12 3.3.2 Tecnica di puntamento La prospettiva derivante dalla combinazione degli angoli (verticale e orizzontale) tra il ricevitore e la Sensor Bar, può far apparire quest’ultima in una posizione in cui non si trova realmente, ma attraverso semplici relazioni trigonometriche è possibile individuare lo sfasamento degli angoli tra gli emettitori e il ricevitore. Il primo passo dell’algoritmo di puntamento è la localizzazione della Sensor Bar. Poiché potrebbero essere presenti fonti IR spurie, si rivela indispensabile individuare con precisione i due punti che più probabilmente corrispondono alla Sensor Bar. Per far questo si cercano due punti orizzontalmente allineati distanziati da uno spazio minimo predefinito (per rimuovere ogni possibile riferimento duplicato se il Wiimote rilevasse più punti raggruppati intorno ad un emettitore IR), usando l’inclinazione calcolata dall’accelerometro per determinare qual è il piano orizzontale cui riferirsi. Le coppie contraddistinte da un margine di sfasamento dal piano orizzontale superiore ai 10° vengono scartate. Tra le rimanenti coppie, vengono scelte le due che più si avvicinano al piano orizzontale; una coppia di punti con un terzo punto molto vicino alla linea immaginaria tra di essi viene scartata, in quanto non è possibile che vi sia un emettitore IR tra gli estremi, pertanto quella coppia non può essere la Sensor Bar. Se il Wiimote smarrisce il puntamento di una delle estremità, che può scomparire dalla vista una volta avvicinatosi ai bordi dell’area di puntamento o quando ne esce, il telecomando tenta di proseguire usando il solo punto rimanente cercando di intuire la posizione del punto scomparso, ad esempio usando i valori della distanza (fissa) tra i due punti e i valori dell’accelerometro per calcolare l’angolo. 3.3.3 Posizione di puntamento Noti i due punti della Sensor Bar, viene ruotato il campo del sensore per farli apparire in allineamento orizzontale (usando i valori dell’accelerometro per assicurare di essere nell’esatto quadrante, ad esempio se il Wiimote fosse sottosopra). Si può probabilmente applicare almeno un filtro di base di movimento medio per ridurre gli scatti. Una volta mappata la Sensor Bar in un sistema di coordinate orizzontali, si può semplicemente calcolare la posizione intermedia tra i due punti e usarla per calcolare la posizione del 13 puntatore definendo un quadro per mappare lo schermo su di esso. La posizione di questo quadro può variare a seconda del luogo di posizionamento della Sensor Bar (sopra o sotto lo schermo). Il quadro dovrebbe essere proporzionatamente dimensionato in modo da accomodare più angoli senza aree morte. Una posizione di puntamento approssimata può essere calcolata mediante l’uso delle seguenti formule: Rotation = Math.Atan2(Accelerometer.Z, Accelerometer.X) - (float)(Math.PI / 2.0); Position = (1 - Midpoint.x, Midpoint.y); Position.Subtract(0.5,0.5); Position.Rotate(Rotation); Position.Add(0.5,0.5) Se il punto intermedio non fosse disponibile si può usare il punto rimanente e comparare la sua posizione corrente con la sua posizione quando entrambi i punti erano visibili. 3.3.4 Levigatura del cursore La conversione dei dati rilevati dal ricevitore IR in informazioni per il posizionamento di un cursore nello schermo consente a diverse applicazioni di sfruttare la tecnica di puntamento nel loro funzionamento. Questa tecnica risulta particolarmente vantaggiosa nei menu e nelle GUI; per queste applicazioni sarebbe auspicabile un filtraggio della posizione del cursore. Una strategia per questo scopo è l’implementazione di uno schema circolare trascinabile; Il software disegna un cerchio immaginario attorno alla nuova posizione puntata; se il cursore si sposta al di fuori del cerchio, viene immediatamente trascinato al suo interno. In ogni caso, se il cursore si trova già all’interno del cerchio, si muoverà in direzione del centro ad una velocità proporzionale alla distanza dal centro. Questa tecnica “leviga” il movimento del cursore e fa si che alcune piccole vibrazioni fisiche non muovano drasticamente il cursore, consentendo comunque piccole correzioni. Un’altra opzione è un algoritmo che corregge più attentamente la posizione quando il Wiimote si muove lentamente e dà maggiore tolleranza in corrispondenza di movimenti veloci. L’aspetto complesso di questo metodo sta nella difficoltà di apporto di piccole correzioni quando il telecomando viene mosso di pochi pixel. 14 3.4 Altre funzionalità 3.4.1 LED Sul lato frontale del Wiimote sono presenti quattro LED azzurri. Durante la modalità di rilevazione e prima dell’inizializzazione, questi LED lampeggiano assieme. Il numero dei LED che lampeggiano è proporzionale alla tensione sulla batteria, e indica la carica delle pile (tutti e quattro indicano batterie completamente cariche, e un led soltanto indica che le batterie stanno per esaurirsi e andrebbero sostituite). Il Wiimote è alimentato da due pile di tipo AA. Quando il Wiimote è sincronizzato alla console, uno dei LED è acceso e indica il numero giocatore assegnato dalla console al telecomando (fino a quattro giocatori). I LED sono comunque indipendentemente controllabili dall’host, e possono essere accesi o spenti a piacimento dal software. I LED possono anche essere modulati ad una comunque moderata alta frequenza, abilitando un controllo di luminosità occupando però parecchia banda Bluetooth. I LED sono montati sulla parte superiore del circuito, alimentati a 2.66 V DC. 3.4.2 Rumble Il Wiimote include una funzionalità di vibrazione, la cui implementazione consiste in un piccolo motore unito a un peso decentrato (Rumble Pack). Il motore può essere attivato o fermato attraverso un Output Report. Non tutti i Wiimote montano lo stesso motore; uno di questi è il SEM 8728DA, alimentato a 3.3 V DC e a 35 mA. 3.4.3 Speaker Il telecomando contiene un piccolo altoparlante di 21 mm piezo-elettrico di bassa qualità, usato per brevi effetti sonori durante il gioco. I suoni provengono direttamente dall’host e lo speaker ha qualche parametro regolabile. L’altoparlante è controllato tramite tre Output Report assieme a una sezione del registro indirizzi del Wiimote. 15 3.5 Estensioni Il Wiimote dispone di un connettore d’espansione a 6 pin che consente di connettervi periferiche esterne. La comunicazione è bi-direzionale seriale e sincrona (il protocollo è sconosciuto); le estensioni forniscono un blocco virtuale di registro mappato in una porzione dello spazio indirizzi del Wiimote; la comunicazione è crittografata. I dispositivi qui elencati sono tutte estensioni del Wiimote ad esso connesse tramite il connettore di cui sopra, fatta eccezione per la Balance Board che comunica direttamente con l’host via Bluetooth. 3.5.1 Nunchuk È un telecomando di forma ovoidale leggermente più piccolo del Wiimote, dotato di un accelerometro a tre assi simile a quello del Wiimote, di un joystick analogico, due pulsanti dorsali (C e Z) e un microcontroller. La posizione centrale del joystick viene calibrata al collegamento del Nunchuk al Wiimote, con un meccanismo finora sconosciuto. I due potenziometri (30KΩ) che controllano gli assi del joystick sono collegati in parallelo. Il chip di controllo dell’accelerometro è il LIS3L02 di STMicroelectronics. Figura 4: Nunchuk collegato al Wiimote 16 3.5.2 Classic Controller È un controller tradizionale, utilizzabile come seconda scelta in giochi che lo supportano; è provvisto di 15 pulsanti, due dei quali sono trigger analogici e forniscono sia lo stato di “click” una misura della pressione ad essi impressa, e due joystick analogici. Sul lato frontale del controller sono posizionati i joystick e 11 dei pulsanti standard: A, B, , Home, +, X, Y, Up, Down, Left, Right. Sul lato superiore si trovano i trigger e gli altri due pulsanti: Z e L; sono posizionati in modo da essere premibili con gli indici. I trigger (destro e sinistro) sono sensibili a forze; alla pressione di un trigger, un meccanismo fa scorrere un potenziometro lineare da 30KΩ. Il meccanismo utilizza solo un quarto della distanza massima percorribile dal potenziometro. Al termine di uno spostamento derivante da una pressione viene chiuso uno switch; il trigger è considerato premuto appieno quando viene chiuso anche lo switch in fondo al percorso del potenziometro. Tutti i sei potenziometri nel dispositivo (due relativi a ogni trigger e due per ognuno dei joystick) sono collegati in parallelo. 3.5.3 Wii Motion Plus È un accessorio che migliora le prestazioni del Wiimote rendendolo molto più preciso e realistico. Esso permette di compiere movimenti con il telecomando che saranno mappati 1:1 dalla console; in pratica vengono recepiti tutti i movimenti 3D compiuti nello spazio, rilevati con altissima precisione. Il dispositivo ha una propria porta d’espansione che consente di collegarvi ad esempio un Nunchuk, permettendo così l’uso di entrambe le estensioni. Il Wii Motion Plus contiene due giro sensori: un giroscopio a due assi (IDG-600 di InvenSense) per il rilevamento di Pitch e Roll, e un giroscopio monoasse (X3500W di EPSON TOYOCOM) per il rilevamento di Yaw. L’uso combinato dei due giroscopi abilita il dispositivo alla lettura della velocità angolare in tutti e tre gli assi, consentendo così un orientamento completo. In Figura 2 sono rappresentati i movimenti Pitch, Roll e Yaw rilevabili dal Wii Motion Plus. 17 3.5.4 Wii Balance Board La Wii Balance Board è una pedana che comunica via Bluetooth direttamente con la console. È composta da quattro bilance che rilevano lo spostamento del peso dell’utente che si posiziona sopra di essa, permette quindi di usare gli spostamenti del corpo per controllare le azioni di gioco. La Balance Board è effettivamente un’estensione nonostante non la si possa collegare fisicamente al connettore del Wiimote, tuttavia è utilizzabile anche in assenza di un Wiimote in quanto appare alla console come un Wiimote con un “Balance Board extension controller” permanentemente connesso, e trasmette i propri dati alla console in maniera del tutto simile ad un’estensione connessa a un Wiimote. I dispositivi di misurazione della Balance Board sono quattro estensimetri, incorporati in ciascuno dei piedini su cui la pedana poggia al suolo. Il principio di funzionamento di questi sensori è la misura della resistenza elettrica di un sottile filo di metallo posto al loro interno, che aumenta all’allungamento del filo; l’estensione del filo è proporzionale alla sollecitazione (forza peso) che il sensore subisce. Grazie alla disposizione dei sensori ai quattro angoli della pedana, questa periferica è in grado di misurare l’indice di massa corporea, analizzare la posizione del baricentro e il peso corporeo. Nella versione europea la Balance Board può sostenere fino a un peso di 150Kg. La trasmissione dei dati misurati è continua, e avviene con un rate di 60 fps. Figura 5: Wii Balance Board 18 Capitolo 4. Interfacciamento e connessione dei dispositivi In questo capitolo vengono esposte le tecnologie e i meccanismi mediante i quali avviene la connessione tra i controller di Nintendo Wii e l’host (console o pc). 4.1 HID [5] Gli Human Interface Device (HID) sono dispositivi che interagiscono direttamente con l’utente. Sono tipicamente dispositivi di input, ma spesso emettono anche output. Il termine HID viene spesso associato alla specifica USB-HID, termine coniato da Mike Van Flandern (Microsoft) quando propose al comitato USB la creazione di un gruppo di lavoro per lo sviluppo delle tecnologie dei dispositivi di input. Il gruppo venne rinominato e nacque la Human Interface Device class, che denota la comunicazione bi-direzionale supportata dallo standard. Le motivazioni principali che portarono alla nascita di HID furono l’abilitazione di innovazioni per i dispositivi di input e la semplificazione del processo di installazione di tali dispositivi. 4.1.1 L’innovazione di HID Prima della nascita di HID, i dispositivi di input erano tipicamente utilizzati mediante protocolli restrittivi per mouse, tastiere e joystick. L’innovazione dell’hardware ha richiesto modifiche a protocolli esistenti o la creazione di driver personalizzati con conseguente pubblicazione di nuovi protocolli per gli sviluppatori di applicazioni. I dispositivi HID rilasciano dei pacchetti autodescrittivi che potrebbero contenere un’infinità di tipi di dati e formati. Un singolo driver HID installato in un PC analizza i dati e abilita l’associazione dinamica di informazioni di I/O con le funzionalità applicative. 19 Molti sistemi operativi possono riconoscere dispositivi USB-HID, come mouse o tastiere, anche senza l’utilizzo di un driver, e in questo caso un dispositivo viene riconosciuto come “HID-compliant device”. 4.1.2 Il protocollo HID Il protocollo HID si compone di due entità: l’host e il device. Il device è l’entità che interagisce direttamente con l’utente, mentre l’host comunica con il device ricevendo (o trasmettendo) dati in risposta ad azioni compiute dall’utente. Gli host sono tipicamente pc, ma possono anche essere telefoni cellulari, PDA e console. Il protocollo HID traduce l’implementazione dei dispositivi in modelli molto semplici. I dispositivi definiscono un proprio pacchetto dati e quindi presentano all’host un “HID descriptor”, che contiene la descrizione del contenuto del pacchetto dati. Le informazioni contenute nel descrittore sono: il numero di pacchetti supportati dal dispositivo, lo spazio occupato da ogni pacchetto e il significato di ciascun byte nel pacchetto. Tipicamente l’HID descriptor è memorizzato in una ROM all’interno del dispositivo. L’host è un’entità molto più complessa del device. Ad esso spetta il compito di ricevere l’HID descriptor dal device ed analizzarlo allo scopo finale di comunicare in modo pienamente funzionale con il device. 4.1.3 Bluetooth HID Il Bluetooth HID è una versione derivante dal protocollo HID definito per USB, alleggerita e adattata alla tecnologia della trasmissione Bluetooth. Questo permette il riutilizzo di alcune delle già esistenti funzionalità per USB-HID per il supporto di Bluetooth HID. Il profilo HID descrive il modo in cui utilizzare il protocollo USB-HID per rilevare una classe di driver USB-HID preesistente, dalla quale estrarre un set di funzionalità della classe HID del dispositivo; il profilo descrive inoltre come un dispositivo Bluetooth supporta servizi HID che sfruttano il livello L2CAP. Il profilo HID è progettato al fine di abilitare, inizializzare e controllare dispositivi auto-descriventi e di fornire una connessione a bassa latenza con bassi requisiti di alimentazione. 20 Il Wiimote e la Balance Board usano entrambi allo stesso modo il protocollo Bluetooth HID standard per comunicare con l’host, quello che cambia è l’identificativo con cui vengono individuati e associati all’host: il Wiimote viene riconosciuto come “Nintendo RVL-CNT-01”, mentre la Balance Board come “Nintendo RVL-WBC-01”. 4.2 Bluetooth [6] Il Wiimote si interfaccia alla console mediante la tecnologia Bluetooth, grazie a un dispositivo BCM2042 di Broadcom. Il Wiimote e la Balance Board utilizzano il protocollo HID Bluetooth standard per comunicare con l’host, direttamente basato sull’USB HID standard. Grazie a questa caratteristica essi possono essere rilevati come dispositivi di input standard da un qualunque host Bluetooth, quale ad esempio un pc dotato di scheda di rete Bluetooth o di un adattatore USB (una chiavetta Bluetooth). Viene quindi introdotta la possibilità di utilizzare il Wiimote e la Balance Board come dispositivi di input per applicazioni per pc, svincolandosi così da un loro uso esclusivo con la console Wii. 4.2.1 BlueSoleil [7] I primi tentativi di connessione dei dispositivi al pc hanno esito positivo, ma mostrano una carenza di affidabilità della connessione in quanto spesso essa si disattiva senza preavviso e non garantisce una continuità della comunicazione tra l’host e il device. La soluzione a questo problema è stata raggiunta con la sostituzione del software standard del sistema operativo che gestisce la rete e i dispositivi Bluetooth con un software avanzato e provvisto di migliori funzionalità. Questo software è BlueSoleil di IVT; è un’applicazione che consente a pc abilitati Bluetooth di collegarsi ad altre periferiche abilitate Bluetooth, ma anche di creare reti e scambiare dati tra dispositivi. 21 Figura 6: IVT Bluesoleil Funzione Bluetooth (Profilo) Client Server Advanced Audio Bluetooth √ √ √ Auricolare e microfono Bluetooth Connessione remota Bluetooth √ FAX Bluetooth √ Trasferimento file Bluetooth √ Periferica d'interfaccia umana (HID) Bluetooth √ OPP (Object Push) Bluetooth √ √ PAN (Personal Area Network) Bluetooth √ √ Stampa Bluetooth √ Porta seriale Bluetooth √ √ √ Tabella 1: Profili Bluetooth supportati da BlueSoleil Come illustrato in Tabella 1, BlueSoleil dispone di diverse funzionalità operative sulle reti Bluetooth. Il software consente la gestione delle reti sia nella erogazione dei servizi (Server) che nell’accesso a servizi (Client). 4.2.2 Connessione del Wiimote Il Wiimote viene rilevato dal software come Bluetooth HID (Joystick), e identificato attraverso un id univoco; Esso non richiede alcuna autenticazione o cifratura, l’interfacciamento consiste nella pressione contemporanea dei tasti 1 e 2 o del tasto rosso di sincronizzazione all’interno del coperchio delle batterie, che porta il Wiimote nella 22 modalità di rilevazione nella quale viene accoppiato all’host (console o pc) mediante il driver Bluetooth-HID. A sincronizzazione avvenuta, il Wiimote dirige automaticamente i propri pacchetti verso l’host a cui è accoppiato. L’interfacciamento con la console Wii è automatico una volta che il Wiimote viene portato in modalità di rilevazione, in quanto la console si accoppia automaticamente al dispositivo e vi associa un indice da 1 a 4 (alla console si possono interfacciare fino a 4 Wiimote contemporaneamente) che viene normalmente indicato dall’accensione di uno dei 4 led sul dispositivo. Per connettere il Wiimote a un pc è invece necessario anzitutto effettuare nel software BlueSoleil una ricerca dispositivi Bluetooth: se il Wiimote si trova in modalità di rilevazione, esso viene trovato, ma non accoppiato. Occorre mantenere il Wiimote nella modalità di rilevazione e indicare al software di connettere l’host al dispositivo. Se l’operazione ha esito positivo l’icona relativa al dispositivo diventa verde. In Figura 7 è mostrata la notifica della fase di sincronizzazione del dispositivo. Figura 7: Sincronizzazione Wiimote Tuttavia il Wiimote è inutilizzabile dai driver standard HID in quanto non usa né la tipologia standard di dati né lo stesso descrittore HID, ma si limita a fornire la lunghezza del pacchetto, senza descriverne il contenuto; questo aspetto ha reso necessaria la creazione di alcuni driver Wiimote. Il Wiimote utilizza un set di operazioni abbastanza complesso, trasmesse tramite il canale HID di output, e restituisce attraverso il canale di input differenti pacchetti contenenti dati provenienti dalle sue periferiche interne. La connessione della Balance Board avviene in modo del tutto analogo. 23 4.3 Wiimotelib Wiimotelib è una libreria .NET sviluppata da Brian Peek [8], che consente ad una applicazione .NET di interfacciarsi a un controller Wiimote e alle varie estensioni esistenti. Diverse versioni di questa libreria sono disponibili su CodePlex [9]. Gli algoritmi mediante i quali la libreria abilita la comunicazione con il dispositivo sono descritti nei paragrafi seguenti [10]. 4.3.1 Creazione del canale di comunicazione Quando il Wiimote e la Balance Board vengono sincronizzati con il pc, sono identificati come HID-compliant devices, ma i loro pacchetti non sono decodificabili. Pertanto, per connettersi funzionalmente ai dispositivi, occorre utilizzare le API di Win32 per la gestione dei dispositivi HID; queste API sono definite nel Windows Driver Kit (WDK). Non essendo disponibile in .NET un supporto integrato per tali API, diventa necessaria l’introduzione di uno strumento che permetta di chiamare direttamente i metodi delle API da .NET: questo strumento è P/Invoke. La difficoltà di questo passaggio consiste nella ricerca della corretta signature per ogni metodo e le definizioni delle strutture che introducono propriamente i dati attraverso Win32. Wiimotelib è scritta in C#, e i metodi inerenti P/Invoke sono contenuti nella classe HIDImports. Il processo attraverso il quale la libreria apre la comunicazione con il Wiimote (o con la Balance Board, che come detto è considerata a tutti gli effetti un Wiimote) si compone dei seguenti passi: 1. Trovare il GUID della classe HID definita da Windows 2. Trovare un gestore della lista di tutti i dispositivi che fanno parte di tale classe 3. Enumerare l’insieme di questi dispositivi e ottenere informazioni dettagliate riguardo ognuno di essi 4. Comparare Vendor ID e Product ID di ognuno dei dispositivi della classe con i già noti VID e PID del Wiimote 5. Una volta trovata la classe corrispondente, creare un FileStream per ricevere o inviare dati al dispositivo 6. Svuotare la lista dei dispositivi 24 Viene qui riportato il codice C# che esegue i passaggi precedentemente descritti: // read/write handle to the device private SafeFileHandle mHandle; // a pretty .NET stream to read/write from/to private FileStream mStream; bool found = false; Guid guid; uint index = 0; // 1. get the GUID of the HID class HIDImports.HidD_GetHidGuid(out guid); // 2. get a handle to all devices that are part of the HID class IntPtr hDevInfo = HIDImports.SetupDiGetClassDevs(ref guid, null, IntPtr.Zero, HIDImports.DIGCF_DEVICEINTERFACE);// | HIDImports.DIGCF_PRESENT); // create a new interface data struct and initialize its size HIDImports.SP_DEVICE_INTERFACE_DATA diData = new HIDImports.SP_DEVICE_INTERFACE_DATA(); diData.cbSize = Marshal.SizeOf(diData); // 3. get a device interface to a single device (enumerate all devices) while(HIDImports.SetupDiEnumDeviceInterfaces(hDevInfo, IntPtr.Zero, ref guid, index, ref diData)) { // create a detail struct and set its size HIDImports.SP_DEVICE_INTERFACE_DETAIL_DATA diDetail = new HIDImports.SP_DEVICE_INTERFACE_DETAIL_DATA(); diDetail.cbSize = 5; //should be: (uint)Marshal.SizeOf(diDetail);, but that's the wrong size UInt32 size = 0; // get the buffer size for this device detail instance (returned in the size parameter) HIDImports.SetupDiGetDeviceInterfaceDetail(hDevInfo, ref diData, IntPtr.Zero, 0, out size, IntPtr.Zero); // actually get the detail struct if(HIDImports.SetupDiGetDeviceInterfaceDetail(hDevInfo, ref diData, ref diDetail, size, out size, IntPtr.Zero)) { // open a read/write handle to our device using the DevicePath returned mHandle = HIDImports.CreateFile(diDetail.DevicePath, FileAccess.ReadWrite, FileShare.ReadWrite, IntPtr.Zero, FileMode.Open, HIDImports.EFileAttributes.Overlapped, IntPtr.Zero); // 4. create an attributes struct and initialize the size HIDImports.HIDD_ATTRIBUTES attrib = new HIDImports.HIDD_ATTRIBUTES(); attrib.Size = Marshal.SizeOf(attrib); // get the attributes of the current device if(HIDImports.HidD_GetAttributes(mHandle.DangerousGetHandle(), ref attrib)) { // if the vendor and product IDs match up if(attrib.VendorID == VID && attrib.ProductID == PID) { 25 // 5. create a nice .NET FileStream wrapping the handle above mStream = new FileStream(mHandle, FileAccess.ReadWrite, REPORT_LENGTH, true); } else mHandle.Close(); } } // move to the next device index++; } // 6. clean up our list HIDImports.SetupDiDestroyDeviceInfoList(hDevInfo); 4.3.2 Trasmissione dei pacchetti Nel mondo di HID, i dati vengono trasmessi sotto forma di report, sono cioè blocchi di dati di lunghezza predefinita e fissa con un header che descrive il report contenuto nel blocco. Il Wiimote trasmette e riceve vari report, ognuno dei quali ha una lunghezza di 22 byte. Una volta creato il FileStream su cui comunicare con il Wiimote, è possibile aprire la trasmissione dei dati. Poiché i report saranno trasmessi e ricevuti quasi sempre in modo continuo, è essenziale l’uso di operazioni di I/O asincrone; in .NET questo è particolarmente semplice. Il processo consiste nell’avviare un’operazione asincrona di lettura e fornire un metodo di risposta quando il buffer si riempie; terminato il metodo di risposta, i dati sono stati manipolati e il processo può essere ripetuto. // report length private const int REPORT_LENGTH = 22; // report buffer private byte[] mBuff = new byte[REPORT_LENGTH]; private void BeginAsyncRead() { // if the stream is valid and ready if(mStream.CanRead) { // create a read buffer of the report size byte[] buff = new byte[REPORT_LENGTH]; // setup the read and the callback mStream.BeginRead(buff, 0, REPORT_LENGTH, new AsyncCallback(OnReadData), buff); } } private void OnReadData(IAsyncResult ar) { 26 // grab the byte buffer byte[] buff = (byte[])ar.AsyncState; // end the current read mStream.EndRead(ar); // start reading again BeginAsyncRead(); // handle data.... } Questo è il codice sufficiente ad aprire e avviare la comunicazione con il Wiimote. Il resto del codice comporta l’analisi dei dati ricevuti dal dispositivo e l’invio di dati adeguatamente formati al Wiimote. Si può inviare un qualunque comando al Wiimote attraverso il seguente codice: mStream.Write(mBuff, 0, REPORT_LENGTH); 27 Capitolo 5. Ambiente di Sviluppo L’ambiente di sviluppo dell’applicazione è XNA Game Studio 3.1, estensione di Microsoft Visual Studio. Il linguaggio di programmazione utilizzato è C#. È stato possibile utilizzare l’edizione 2008 Professional di Visual Studio grazie alla licenza studenti per il Politecnico di Milano distribuita dall’MSDN Academic Alliance [11]. 5.1 Microsoft Visual Studio 2008 [12] È un IDE (Integrated Development Environment) di Microsoft, con nome in codice Orcas, ed è uno strumento rivolto a sviluppatori di piattaforme Windows e .NET Framework 3. Incorpora svariati linguaggi di programmazione tra i quali VB.NET, C#, C++ e altri ancora. Offre inoltre la possibilità di creare applicazioni e servizi Web ASP.NET. Visual Studio 2008 richiede il .NET Framework 3.5 che è stato rilasciato assieme all’IDE il 19 Novembre 2007, e per default compila su tale framework le applicazioni ma supporta anche la compilazioni degli assembly nelle versioni precedenti del framework. Il debugger di Visual Studio include funzionalità che semplificano il debug di applicazioni multithread. 5.2 C# [13] C# (C Sharp) è un linguaggio di programmazione Object-Oriented sviluppato da Microsoft all’interno dell’iniziativa .NET, e successivamente approvato come standard ECMA (associazione attualmente responsabile per molti standard). La sintassi del codice C# prende spunto da Delphi [14] (del medesimo autore, Anders Hejlsberg), da C++, da Java e Visual Basic per gli strumenti di programmazione visuale e per la semplicità. C# è il linguaggio che meglio descrive le linee guida del funzionamento di un’applicazione .NET; i suoi tipi di dati primitivi hanno una corrispondenza univoca con i tipi .NET e molte delle sue astrazioni come classi, interfacce, delegati ed eccezioni sono particolarmente adatte a gestire il .NET Framework. 28 5.3 Il Framework XNA [15] Microsoft XNA (Xna is Not Acronymed) è un insieme di strumenti per la progettazione, lo sviluppo e la gestione di software per videogiochi contraddistinto dalla semplicità del processo di creazione, poiché evita al programmatore l’inserimento di parti inutili di codice e consente l’appoggio a un framework unificato, che contiene tutti i set di istruzioni utili per un videogame. XNA attualmente comprende l’intera sezione di sviluppo videogiochi di Microsoft, incluso lo standard Xbox Development Kit. Il Framework XNA è basato sul .NET Framework 2.0 per Windows e sul .NET Compact Framework 2.0 per Xbox 360, pertanto è virtualmente supportato da tutti i linguaggi .NET, anche se è consigliato l’uso di C#. Esso appoggia sulle librerie grafiche di Microsoft DirectX e incapsula tutti i dettagli di basso livello riguardanti lo sviluppo del videogioco, risparmiando questo compito allo sviluppatore che può concentrarsi sul contenuto e sull’esperienza di gioco in quanto sarà il framework a gestire le varie piattaforme di gioco; sono inoltre presenti numerosi strumenti per la creazione di contenuti, come editor di suono, visuali e di modelli. Microsoft ha rilasciato degli IDE specifici per il game design (XNA Game Studio), che si possono installare come estensione dell’IDE principale (Visual Studio), così come il Framework XNA viene installato come estensione del .NET Framework. 5.4 Struttura di un progetto XNA [16] La colonna portante di un progetto XNA è una classe di tipo Game. Questa classe è implementata alla creazione di ogni progetto XNA e gestisce l’intera applicazione attraverso dei metodi predefiniti. In un progetto XNA è possibile separare le varie parti dell’applicazione mediante l’uso di vari GameComponents, ciascuno dei quali possiede metodi predefiniti ereditabili dalla classe Game. 29 5.4.1 Metodi predefiniti Ad ognuno dei metodi predefiniti per le classi XNA è assegnata una particolare mansione. Ogni metodo contiene il codice opportuno per eseguire tale compito. I metodi sono i seguenti: • Costruttore: chiamato al momento dell’istanziazione della classe • Initialize: chiamato dopo l’istanziazione della classe e usato per inizializzare gli attributi della classe • Update: viene invocato a runtime sessanta volte al secondo; contiene il codice che aggiorna la logica e i dati del componente • Draw: contiene il codice che gestisce la grafica di gioco e il rendering di oggetti 2D (Textures), oggetti 3D o effetti sullo schermo; viene chiamato per default alla stessa frequenza di refresh dello schermo • LoadContent: contiene il codice che gestisce il caricamento dati (immagini, modelli, audio) dall’hard disk; XNA gestisce e ottimizza il caricamento attraverso il Content Pipeline ottenendo così maggiore flessibilità • UnloadContent: viene chiamato prima della terminazione dell’applicazione e contiene il codice inerente la disposizione o la rimozione dei dati prima di effettuare l’uscita dal gioco 5.4.2 Componenti Il framework XNA fornisce dei componenti specifici che vengono usati per distribuire il codice relativo a diverse mansioni su più componenti semplificando perciò la struttura di ogni porzione di codice. Per utilizzare un componente nell’applicazione occorre crearne un’istanza nella classe principale Game, inizializzarla e aggiungere il componente alla Component List della classe Game. I componenti usati sono di tipo GameComponent e DrawableGameComponent; entrambi consentono la manipolazione e gestione della logica di gioco per mezzo dei metodi sopra citati, ma differiscono tra loro in quanto i GameComponent non dispongono di metodi e proprietà relativi alla gestione della grafica e pertanto non è possibile gestire e visualizzare 30 oggetti grafici in tali componenti. Solo i componenti di tipo Drawable dispongono del metodo Draw. Le proprietà più importanti dei componenti sono: • Enabled: indica se il componente è attivo • Visible (solo per DrawableGameComponent): indica se il componente è visualizzato sullo schermo 5.4.3 Grafica 2D Il framework XNA fornisce alcune funzionalità che consentono la visualizzazione di immagini per mezzo della classe SpriteBatch. Questa classe è stata ideata ponendo come priorità la facilità d’uso, ma possiede comunque notevoli potenzialità, tra cui differenti ottimizzazioni delle immagini. Nella programmazione grafica le immagini visualizzate su schermo vengono chiamate Sprite, mentre le immagini importate nelle applicazioni e poi successivamente rese accessibili al codice sono chiamate Texture. In un progetto di XNA Game Studio è possibile importare delle Texture e renderle accessibili al codice per mezzo di un asset, che costituisce il riferimento all’immagine memorizzata su disco. Nel codice esse possono essere inserite in una Sprite e visualizzate su schermo. public class Game1 : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; Texture2D myTexture; public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; } protected override void LoadContent() { myTexture = Content.Load<Texture2D>("image"); } protected override void Draw(GameTime gameTime) { spriteBatch.Begin(); spriteBatch.Draw(myTexture, new Vector2(0, 0), Color.White); spriteBatch.End(); } } 31 5.5 Audio XNA gestisce i suoni nello stesso modo in cui si occupa della grafica, attraverso il Content Pipeline. Differentemente dai contenuti grafici, ai quali è possibile un accesso diretto, i contenuti audio necessitano di essere importati in un particolare formato, generato dal un tool audio: XACT. 5.5.1 XACT XACT è un Cross-Platform Audio Creation Tool di Microsoft; viene utilizzato per creare un progetto contenente delle Sound Banks e Wave Banks. La compilazione del progetto produce tre file, che l’applicazione XNA può ricevere attraverso il Content Manager. Il processo consiste nella creazione di un progetto XACT, nel quale occorre creare una Wave Bank all’interno della quale inserire le diverse sorgenti audio (file WAV) che si vogliono utilizzare dall’applicazione; a questo punto bisogna creare una Sound Bank e trascinarvi le tracce audio precedentemente inserite nella Wave Bank; i nomi dei file audio vengono così aggiunti come contenuti della Sound List e Cue List nella Sound Bank. A questo punto si deve compilare il progetto XACT; il risultato della compilazione sono tre file (.xgs, .xwb e .xsb) che verranno poi importati nel progetto XNA e letti da una classe specifica. 5.5.2 Classe statica Audio Per rendere possibile la riproduzione di audio nell’applicazione XNA, è stata creata all’interno del progetto una classe statica che fornisce dei metodi specifici per la riproduzione di determinati suoni. I file audio da riprodurre non devono essere importati all’interno del progetto poiché grazie alla compilazione del progetto XACT sono ora contenuti nella Wave Bank; è invece necessario includere nel progetto il file .xap generato dal salvataggio del progetto XACT. 32 La classe creata fa uso dei seguenti tre oggetti, indispensabili per la gestione del contenuto audio: • AudioEngine: costituisce il riferimento ai servizi audio del pc, ed è usato principalmente come parametro per la creazione delle Wave e Sound Banks. La creazione dell’AudioEngine richiede il file (.xgs) che descrive le impostazioni globali del contenuto del progetto XACT, generato dalla compilazione del progetto stesso • WaveBank: è una collezione di file wave; la sua creazione richiede la previa creazione dell’AudioEngine e il file (.xwb) generato alla compilazione del progetto XACT. La WaveBank non viene esplicitamente utilizzata dal programma, ma è necessaria in quanto le Cue nella SoundBank dipendono dai file wave contenuti nella WaveBank • SoundBank: è una collezione di Cue, definite come riferimenti ai file wave memorizzati nella WaveBank congiunti a proprietà che dettagliano le modalità e i metodi che permettono la riproduzione dei file public static class Audio { private static AudioEngine engine; private static WaveBank waveBank; private static SoundBank soundBank; private static Cue noteCue, musicCue; public static Cue Play(string name) { Cue cue = soundBank.GetCue(name); cue.Play(); noteCue = cue; return cue; } public static void Stop(Cue cue) { cue.Stop(AudioStopOptions.Immediate); } public static void Initialize() { engine = new AudioEngine("Content/Sounds/Sounds.xgs"); waveBank = new WaveBank(engine, "Content/Sounds/Waves.xwb"); soundBank = new SoundBank(engine, "Content/Sounds/Sounds.xsb"); } public static void Update() { engine.Update(); } public static void ShutDown() { soundBank.Dispose(); waveBank.Dispose(); engine.Dispose(); } } 33 La creazione dei riferimenti all’audio del progetto XACT tramite l’istanziazione degli oggetti sopra descritti avviene all’interno del metodo Initialize, che deve essere chiamato prima dell’uso di qualunque altro metodo. Una volta eseguita l’inizializzazione dei componenti audio, è possibile riprodurre una qualunque traccia audio invocando il metodo Play passandogli come parametro il nome del suono da riprodurre. Durante l’esecuzione dell’applicazione è inoltre necessario aggiornare lo stato dell’AudioEngine, semplicemente richiamando il metodo Update della classe Audio all’interno della Update delle classi del progetto. 5.6 Requisiti di piattaforma La distribuzione di un progetto XNA su piattaforme differenti da quella sulla quale è stato sviluppato richiede l’installazione del framework XNA e del .NET Framework 3.5, in quanto in assenza di tali framework le applicazioni non sono eseguibili e generano degli errori. Grazie alla compatibilità di XNA con la tecnologia ClickOnce di Visual Studio, è possibile far si che l’installer dell’applicazione XNA controlli la presenza di tali pacchetti sulla piattaforma e, in caso di esito negativo della ricerca, ne richieda l’installazione. Entrambi i pacchetti sono scaricabili sui siti di Microsoft. 34 Capitolo 6. Ideazione del software La linea di pensiero che ha caratterizzato il concepimento dell’idea da cui nasce il software è legata all’elevata accessibilità all’applicazione, essenziale per l’uso da parte di utenti paraplegici, quanto al mantenimento di un buon livello di intrattenimento e divertimento, che possa stimolare l’utente a cimentarsi nelle attività previste dai moduli del software. 6.1 Specifiche del software Si è pensato di realizzare un’applicazione in un dominio musicale, introducendo di conseguenza una componente audio nel progetto, che nell’ambito dell’intrattenimento aiuta notevolmente l’utente a confortarsi durante la fase di gioco. Lo studio delle caratteristiche tecniche e delle modalità d’uso del Wiimote (e del Nunchuk) e della Balance Board ha portato alla decisione di implementare una batteria virtuale, emulando il suono di un set di percussioni [17] appartenenti ad una vera batteria musicale [18] attraverso lo scuotimento del Wiimote e del Nunchuk in sostituzione delle vere bacchette; inoltre, per mezzo della Balance Board, su cui l’utente è seduto, viene effettuato un controllo del baricentro dell’utente stesso, in modo che durante l’esperienza di gioco non pieghi in modo scorretto il busto assumendo una postura errata. Il modello virtuale della batteria è decisamente semplificato rispetto alla struttura dello strumento reale, in quanto si è reso necessario ridimensionare la complessità dello strumento adattandolo alle caratteristiche del contesto applicativo e della principale destinazione d’utenza per la quale il software è concepito. Allo stesso tempo si è cercato di mantenere un moderato livello di astrazione per inferire un carattere il più reale possibile, seppur semplice, alla batteria virtuale. 6.1.1 Design della batteria La progettazione della struttura della batteria è avvenuta in riferimento alla gamma di movimenti distinti utilizzabili per emulare il suono di ogni singola percussione, con il vincolo di escludere l’uso dei pulsanti dei telecomandi, correlando il suono di una 35 particolare percussione unicamente a uno specifico movimento di un telecomando. Questo dettaglio è fondamentale ai fini di un uso terapeutico del software in quanto questa soluzione consente ad un utente reduce da traumi di usare i telecomandi senza impugnarli ma eventualmente mantenendoli congiunti ad un supporto vincolato a ogni braccio. In ogni caso l’implementazione della sezione di menu e configurazione del videogame la rende completamente navigabile sia attraverso la pressione dei tasti del Wiimote o del Nunchuk sia con la tastiera del pc, consentendo così ad un qualsiasi utente la possibilità di modificare le opzioni di gioco anche a distanza dal pc, mentre nel caso di un utente paraplegico è possibile che un assistente applichi modifiche alle opzioni dal pc senza interferire con l’utente che può invece governare solo la fase di gioco muovendo le braccia e di conseguenza i telecomandi, senza che debba per forza impugnarli per premere pulsanti. 6.1.2 Criteri di movimento I vincoli tecnici posti dalla specifica del software hanno comportato una riduzione del numero di percussioni di cui si compone la batteria virtuale, fino ad ottenerne soltanto sei, di cui tre suonabili scuotendo il Wiimote e tre scuotendo il Nunchuk. Questa soluzione è derivata da una ricerca delle tecniche verosimili con cui simulare il suono delle percussioni, cioè da una discriminazione dei gesti compiuti dall’utente in relazione alla praticabilità di tali movimenti e al corretto funzionamento del software in risposta al compimento di tali gesti. La prima configurazione presa in considerazione prevede l’uso della Sensor Bar come riferimento per il puntamento del telecomando. Si divide così lo spazio in vari settori a seconda dell’angolo di puntamento del Wiimote verso la Sensor Bar, associando ad ogni settore una singola percussione. Tuttavia questa soluzione non garantisce una separazione netta dei settori virtuali relativi a ogni singola percussione, data la ristrettezza del campo di puntamento e l’incompatibilità tra il puntamento e il movimento del telecomando, in quanto spesso l’azione di suono di una percussione attraverso lo scuotimento del Wiimote porta anche ad un’indesiderata variazione di settore e quindi di percussione. Inoltre questa tecnica impone un utilizzo differente del Wiimote da quello previsto per il Nunchuk, poiché quest’ultimo non è provvisto di ricevitore infrarosso e pertanto non è possibile definire uno spazio di puntamento per tale dispositivo. 36 Vista quindi l’impraticabilità della soluzione precedente, dovuta all’impossibilità di suddividere lo spazio in settori ad ognuno dei quali associare un preciso strumento, si è scelta una strada alternativa, questa volta subordinata a una discriminazione del tipo di movimento effettuato con i telecomandi. Sono stati individuati e descritti quindi tre movimenti distinti compibili da un singolo dispositivo; l’uso annesso del Nunchuk e del Wiimote permette di suonare anche due percussioni contemporaneamente, compiendo un gesto con ciascun dispositivo. Si ottiene così un totale di sei strumenti, che vanno a comporre la batteria virtuale. Ad ognuno dei telecomandi sono associate tre percussioni, ognuna delle quali suonabile mediante l’esecuzione di uno dei tre gesti possibili. Tra i gesti previsti, vi è lo scuotimento classico dall’alto verso il basso del telecomando, tenendolo in posizione frontale; gli altri due gesti sono sempre degli scuotimenti dall’alto verso il basso, ma prevedono l’inclinazione del telecomando verso destra o sinistra durante la fase finale dello scuotimento, e cioè una rotazione del dispositivo dalla posizione frontale fino a percorrere un angolo retto (a destra o a sinistra) durante il movimento verso il basso del telecomando. In Figura 8 è illustrato uno schema dei movimenti predefiniti per il Wiimote per il suono di una percussione. Il dispositivo distingue tre diversi tipi di accelerazione ad esso impressa dall’utente: un’accelerazione sull’asse Z positiva nel movimento frontale, e un’accelerazione sull’asse X negativa (o positiva) nel movimento verso sinistra (o destra). L’uso esclusivo dei dati dell’accelerometro permette di controllare in egual modo i movimenti del Wiimote e quelli del Nunchuk. L’algoritmo di riconoscimento dell’esecuzione di un movimento corrispondente al suono di uno strumento consiste in: • uso di un buffer per ognuno dei quattro assi in movimento (assi X e Z di Wiimote e Nunchuk) al fine di emulare il gesto reale di suono di una percussione: il buffer emula l’effetto di ritorno della bacchetta una volta colpita la percussione; in assenza di tale buffer un singolo movimento verso il basso manderebbe in loop l’applicazione come se la bacchetta colpisse ripetutamente la percussione • valutazione dell’accelerazione impressa agli assi e conseguente rilevazione del movimento eseguito se l’accelerazione supera una soglia predefinita 37 Segue il codice che gestisce questo controllo per il movimento frontale del Wiimote: if (wiimoteForwardTriggerBuffer > -1) wiimoteForwardTriggerBuffer -= 1; wiimoteAxisZ = wiimote.GetState().PositionalState.Z; if (wiimoteForwardTriggerBuffer < 0 && wiimoteAxisZ > 2.5) { //Movimento frontale del Wiimote riconosciuto wiimoteForwardTriggerBuffer = 0; } I movimenti sono stati denominati appositamente per semplificarne il riconoscimento: ognuno dei tre gesti è eseguibile sia con il Wiimote che con il Nunchuk. L’uso corretto dei telecomandi nel gioco prevede l’impugnatura del Wiimote nella mano destra e del Nunchuk nella mano sinistra; è possibile suonare due strumenti contemporaneamente, ma poiché l’associazione tra le percussioni e i movimenti relativi è statica e predefinita, non è possibile suonare contemporaneamente due strumenti entrambi associati al Wiimote o al Nunchuk, ma soltanto uno strumento per ogni telecomando. La denominazione dei gesti compibili dall’utente è: WiimoteLeft, WiimoteForward, WiimoteRight, NunchukLeft, NunchukForward, NunchkRight. Figura 8: Visuale dei movimenti del Wiimote corrispondenti al suono delle percussioni Da sinistra: WiimoteLeft, WiimoteForward, WiimoteRight 38 6.1.3 Composizione e disegno della batteria Una volta distinti i gesti relativi al suono di ogni singolo strumento, si è passati alla composizione della struttura della batteria e all’associazione del suono di ogni strumento al movimento corrispondente. Si sono scelte, tra le sei percussioni che compongono la batteria, quattro membranofoni (tamburi) e due piatti (cymbals). In questa batteria non è presente la grancassa poiché non è previsto l’utilizzo di pedali o comunque degli arti inferiori; per lo stesso motivo, l’HiHat è modellizzato diversamente dal suo equivalente reale, in quanto è suonabile con la bacchetta come un normale piatto anziché tramite pedale. In particolare gli strumenti della batteria virtuale sono i seguenti: • Tamburi: Low Tom, Mid Tom, Floor Tom (Timpano), Snare Drum (Rullante); • Piatti: Crash Cymbal, HiHat (Charleston) I campioni dei suoni relativi ad ognuna delle percussioni sono stati prelevati da Freesound [19]. La mappatura ed il disegno degli strumenti non è perfetta in quanto l’obiettivo primario era quello di derivare dalla batteria reale un modello il più semplice possibile, anche se meno dettagliato. Per rendere graficamente realistica la batteria è stata inserita anche la grancassa, che ricopre però esclusivamente un ruolo decorativo nella struttura della batteria. Figura 9: Batteria Virtuale. Da sinistra a destra: Crash, LowTom, MidTom, FloorTom, Snare, HiHat 39 Scelti gli strumenti che compongono la batteria virtuale, si è creata l’associazione tra ogni strumento e il movimento da compiere per suonarlo. La disposizione degli strumenti nella grafica di gioco è strettamente correlata all’associazione del suono delle percussioni con i movimenti relativi, e favorisce l’ambientamento sul modello virtuale facilitando graficamente l’individuazione dello strumento da suonare. Inoltre, al suono di uno strumento con il Wiimote (o con il Nunchuk), il software lancia una routine che dispone nell’interfaccia visuale del gioco una figura del Wiimote (o del Nunchuk) in sovrapposizione all’immagine della percussione suonata, aiutando così l’utente ad associare i movimenti ai suoni correttamente. Movimenti Left Forward Right Nunchuk Crash LowTom MidTom Wiimote FloorTom Snare HiHat Tabella 2: Associazione tra movimenti e percussioni 6.1.4 Determinazione e controllo della posizione del centro di massa Dopo aver ideato la batteria e le associazioni tra movimento del Wiimote e suono della relativa percussione, si è passati all’implementazione del controllo di postura tramite la Balance Board. Per concepire questa parte del progetto si è utilizzato un lavoro precedente incentrato sullo studio del centro di massa di una persona in posizione seduta e sul suo calcolo sfruttando la tecnologia della Balance Board. Il centro di massa (comunemente detto baricentro) di un corpo generico è il punto intorno al quale la massa del corpo è equamente distribuita. Se per un corpo con densità uniforme il centro di massa coincide con il centro geometrico, questo non vale invece per il corpo umano, in quanto la distribuzione della massa varia continuamente con il variare della postura. Data la complessità del problema, è stato necessario prendere spunto da questo studio, limitandosi alla scrittura del codice che gestisse la rilevazione del baricentro dell’utente seduto sulla Balance Board, in modo da controllarne la postura per evitare piegamenti innaturali o eccessivi del busto. 40 Segue il codice che gestisce il calcolo della posizione del centro di massa dell’utente seduto sulla Balance Board, proiettata sull’asse x della schermata di gioco (è stato considerato solo il movimento del busto verso destra e verso sinistra, non quello in avanti o indietro): delta = ((balanceBoard.GetState().BottomRight + balanceBoard.GetState().TopRight) - (balanceBoard.GetState().BottomLeft + balanceBoard.GetState().TopLeft)); peso = ((balanceBoard.GetState().BottomRight + balanceBoard.GetState().TopRight) + (balanceBoard.GetState().BottomLeft + balanceBoard.GetState().TopLeft)); if (delta > 10) cursorePosition.X += Math.Abs(delta * 15 / peso); if (delta < 10) cursorePosition.X -= Math.Abs(delta * 15 / peso); 6.1.5 Fase di gioco Il gioco vero e proprio consiste nella riproduzione di una traccia musicale, composta da una sequenza di percussioni da suonare; le tracce sono predefinite e variano per difficoltà di esecuzione. La navigazione del menu consente di ascoltare e selezionare la traccia che si vuole riprodurre, dando così un’idea preliminare del motivo da eseguire. Inoltre sono disposti tre livelli di difficoltà che influiscono sia sulla velocità delle tracce da riprodurre, sia sulla tolleranza di accettazione del suono di una percussione, ovvero sul tempo reso disponibile per suonare correttamente uno strumento. Tale intervallo si riduce all’aumento della difficoltà richiedendo così una maggiore precisione nei movimenti. All’avvio della fase di gioco appare una schermata che visualizza uno scheletro della batteria; in fondo alla schermata compare una barra colorata con un cursore che si muove al suo interno, indicando la posizione del baricentro dell’utente e quanto essa sia corretta o sbilanciata; parte poi la traccia, durante l’avanzamento della quale, quando viene raggiunto l’intervallo utile per suonare una percussione, viene disegnato lo strumento relativo ed evidenziato nella grafica nella sua corretta posizione. La visualizzazione dello strumento viene interrotta nel momento in cui viene effettuato il gesto che corrisponde al suono dello strumento stesso, oppure quando termina il tempo a disposizione per suonare la percussione. Il suono corretto di uno strumento fa aumentare il punteggio, mentre il suono di uno strumento diverso da quello “attivato” ne comporta una diminuzione. Al termine della 41 riproduzione della traccia viene calcolato il punteggio sulla base del numero di suoni corretti, al quale viene sottratta la penalità relativa ai suoni errati. 6.1.6 Modalità Free Il software dispone inoltre di una sezione Free-Play nella quale si può suonare qualunque strumento della batteria senza vincoli di traccia o limiti di tempo; si può quindi prendere confidenza con i movimenti e gli strumenti, o anche creare ritmi e sequenze personalizzate. Inoltre il software dispone di una sezione Istruzioni nella quale sono spiegate le funzionalità del gioco e elencati i dettagli di navigazione dei menu e della fase di gioco, compresa una spiegazione dettagliata dei movimenti da compiere per suonare ogni singola percussione ottenendo maggiore precisione. 42 Capitolo 7. Gestione del Wiimote con Wiimotelib La libreria Wiimotelib è il mezzo che consente alle applicazioni la comunicazione con il Wiimote usando .NET. La fase iniziale del progetto è stata dedicata allo studio della corretta tecnica di connessione al dispositivo mediante le funzioni disposte dalla libreria; in secondo luogo si è studiato il metodo di prelievo delle informazioni dal telecomando e lo schema dati in cui tali informazioni vengono memorizzate e rese accessibili dalla libreria. Una volta compresa la modalità con cui accedere alle informazioni attraverso codice C#, si è implementata una classe che fungesse da tramite fra la libreria e le classi XNA del gioco, mettendo a disposizione di queste dei metodi in formato XNA, facendo riferimento alle classi predefinite della sezione input del framework XNA (GamePad, Keyboard, Mouse). 7.1 La classe Wiimote La classe Wiimote definita in Wiimotelib identifica il dispositivo. Si può aprire una comunicazione con le periferiche Nintendo creando un’istanza di questa classe; essa fornisce i metodi per connettere o disconnettere i dispositivi, e altri metodi che permettono di inviare comandi al Wiimote. Questa classe dispone inoltre due eventi, indispensabili per la lettura delle informazioni dai controller in quanto esse possono essere ricevute soltanto attraverso l’uso di event-handler che gestiscano tali eventi. Le informazioni relative ai dati letti dal controller vengono memorizzate nell’attributo WiimoteState. 43 7.1.1 Metodi • Connect: crea una connessione tra l’istanza della classe Wiimote e il primo dispositivo trovato (tra quelli sincronizzati all’host) • Disconnect: si disconnette dal controller e sospende la lettura dei dati da esso • ReadData: legge i dati direttamente dai registri del Wiimote • SetLEDs: accende o spegne i quattro LED del telecomando • SetReportType: imposta il tipo di report ricevuto dal Wiimote • SetRumble: avvia o ferma la vibrazione • WriteData: scrive i dati direttamente sui registri del Wiimote 7.1.2 Eventi • WiimoteChanged: sollevato ogni volta che varia lo stato del Wiimote o dell’estensione che vi è collegata • WiimoteExtensionChanged: sollevato all’inserimento o rimozione di un’estensione. 7.1.3 WiimoteCollection Nelle versioni più recenti di Wiimotelib è possibile gestire la connessione simultanea di più dispositivi sullo stesso host. Per un uso di questo genere non è possibile l’impiego di più oggetti Wiimote distinti, ma è necessario utilizzare un approccio diverso, cioè impiegare la classe WiimoteCollection, definita come collezione di Wiimote, e quindi dotata di metodi ed enumeratori per la gestione di un gruppo di elementi omogenei, ovvero di oggetti Wiimote. Una volta creato un oggetto di tipo WiimoteCollection, si può effettuare una ricerca di tutti i dispositivi sincronizzati all’host mediante il metodo FindAllWiimotes, che inserisce nella WiimoteCollection i riferimenti a tutti gli oggetti di tipo Wiimote trovati. La Collection è così utilizzabile, mediante un indice, come un array di Wiimote e per ognuno di essi si possono eseguire le operazioni descritte nei paragrafi precedenti. La classe WiimoteCollection è stata indispensabile per gestire l’utilizzo contemporaneo del Wiimote e della Balance Board. 44 7.2 Le strutture dati I dati letti dai dispositivi vengono organizzati da Wiimotelib in una serie di struct che definiscono ogni tipo di informazione ricevuta; ciascuna di queste strutture è adibita a contenere i dati prelevati dai dispositivi interni al Wiimote e da ogni tipo di estensione che vi si può collegare. La strutture definite in Wiimotelib dipendono strettamente dall’organizzazione dei pacchetti che il dispositivo invia all’host ogni qualvolta ne cambia lo stato; per questo motivo esse assumono una configurazione ad albero, in quanto vi è una classe principale (WiimoteState) che rappresenta interamente lo stato del dispositivo e di tutte le periferiche ad esso collegate, estensioni comprese. Questa classe contiene istanze di diverse struct che rappresentano lo stato di ognuno dei dispositivi interni al telecomando o alle estensioni; queste struct a loro volta contengono istanze rappresentanti ognuna delle informazioni relative a ogni singolo dispositivo interno, e così via fino ad arrivare alle foglie dell’albero che sono valori booleani o numerici scalari (o vettoriali, ad esempio per gli assi dell’accelerometro X, Y e Z). La classe Wiimote descritta nel paragrafo precedente possiede un attributo di tipo WiimoteState che, aggiornato al sollevamento dell’evento WiimoteChanged, contiene l’intero bagaglio di informazioni relative a qualunque dispositivo o estensione collegabile al Wiimote. Se una certa estensione non è collegata, i valori ad essa corrispondenti non verranno aggiornati e rimarranno valori di default. Nella pagina seguente sono elencati tutti i membri di Wiimotelib e le proprietà delle classi Wiimote e WiimoteState. È possibile intuire la struttura ad albero dai nomi delle struct della libreria. 45 Figura 10: Membri di Wiimotelib e delle classi Wiimote e WiimoteState 46 7.3 Eccezioni Wiimotelib dispone di due tipi di eccezioni che consentono la gestione di situazioni anomale: • WiimoteNotFoundException: viene sollevata quando non vengono rilevati Wiimote nella lista dei dispositivi HID • WiimoteException: viene sollevata quando occorrono errori durante l’esecuzione di funzioni della libreria La gestione delle eccezioni risulta notevolmente vantaggiosa per risolvere situazioni irregolari senza terminare l’applicazione, ad esempio se si tentasse di avviare un’applicazione senza che un dispositivo sia accoppiato con l’host. La gestione avviene mediante l’inserimento del codice in un blocco try/catch. try { // Codice da eseguire in condizioni regolari } catch (WiimoteException ex) { // Codice che gestisce l’eccezione sollevata } 7.4 Implementazione della classe WiiMote La classe WiiMote funziona da interfaccia tra le funzionalità intrinseche della libreria Wiimotelib e le classi di un progetto XNA; essa nasconde la struttura interna della libreria incapsulando le sue funzionalità in un insieme di metodi in stile XNA che si rifanno alle classi definite nella sezione del framework dedicata all’input. La classe WiiMote si occupa internamente del prelievo dei dati dal dispositivo e della loro memorizzazione in una serie di struct opportunamente articolate sulla struttura ad albero in cui vengono collezionati i dati provenienti dal Wiimote, attraverso gli handler degli eventi definiti nel paragrafo precedente. La classe WiiMote legge i dati dal dispositivo al sollevamento degli eventi di cui sopra; il lancio di tali eventi avviene periodicamente e ad alta frequenza, pertanto i dati letti dal telecomando sono continuamente aggiornati. La classe rende invece i dati accessibili per mezzo di un metodo che restituisce l’intera struttura dati memorizzata all’interno della 47 classe stessa, separando così le fasi di prelievo dei dati dal dispositivo e del loro utilizzo in due blocchi distinti. Inoltre la classe WiiMote dispone di metodi che effettuano la connessione o la disconnessione tra l’applicazione e il dispositivo gestendo l’eventuale sollevamento di eccezioni, e di altri metodi che consentono l’invio di comandi al dispositivo. 7.4.1 Metodi della classe WiiMote • Costruttore: inizializza la classe WiiMote, istanziando implicitamente l’oggetto Wiimote (di Wiimotelib) contenuto nella classe WiiMote, istanzia gli oggetti adibiti a contenere i dati e sottoscrive gli eventi • Connetti: esegue il metodo Connect della classe Wiimote di Wiimotelib gestendo l’eventuale sollevamento di eccezioni • Disconnetti: esegue il metodo Disconnect della classe Wiimote di Wiimotelib • GetState: restituisce una struttura contenente tutte le informazioni prelevate dal Wiimote e memorizzate nelle struct della classe WiiMote • SetLeds: accende o spegne i quattro LED del telecomando • SetRumble: avvia o ferma la vibrazione 48 Capitolo 8. Implementazione videogame del La logica del videogame è stata suddivisa in diversi componenti, ognuno dei quali si occupa di un aspetto particolare del sistema. In aggiunta alle classi che racchiudono i componenti, ve ne sono altre che si occupano di aspetti diversi, e il cui comportamento non rispecchia necessariamente quello dei componenti definiti sullo schema XNA, descritto nel paragrafo 5.4. Nome Classe Descrizione Classe statica i cui metodi consentono all’applicazione di Audio riprodurre effetti sonori (inseriti in un progetto XACT). Le specifiche della classe Audio sono elencate al paragrafo 6.5 Classe che incapsula le funzionalità della Wiimotelib relative BalanceBoard alla Balance Board, utilizzate poi dall’applicazione per comunicare con essa DrumAble Istruzioni È la classe principale dell’applicazione, gestisce l’interoperazione tra tutti i componenti Componente grafico che gestisce la sezione Istruzioni del Menu Componente standard che gestisce la logica di gioco, l’invio Logica di comandi per il disegno degli strumenti attivi al componente grafico e il calcolo del punteggio di gioco Menu Componente grafico che gestisce il menu principale, dal quale si può accedere a tutte le funzionalità dell’applicazione Classe che riceve dati relativi al movimento dei telecomandi e Percussione riconosce i gesti corrispondenti al suono di una particolare percussione, sollevando un evento in tale circostanza 49 Componente grafico che disegna il cursore per il controllo del PlayScreen busto e la batteria virtuale su schermo, evidenziandone solo gli strumenti da suonare se si è in fase di gioco oppure l’intera immagine se si è in modalità Free-Play Componente standard che riproduce un’anteprima delle tracce RiproduzioneSequenza audio suonabili nella fase di gioco nella sezione Tracklist del Menu Componente grafico che permette la selezione della velocità Speed di gioco, accessibile dal menu principale Classe che legge la composizione di una traccia da un file e ne Traccia memorizza i dati in una struttura apposita che verrà poi utilizzata dalla logica di gioco Tracklist Componente grafico che consente la selezione della traccia da riprodurre nella fase di gioco Classe che incapsula le funzionalità di Wiimotelib in metodi WiiMote in stile XNA, poi utilizzati dall’applicazione per comunicare con il Wiimote; le specifiche sono definite nel capitolo 8 Tabella 3: Classi implementate nel progetto 8.1 La classe DrumAble La classe DrumAble dirige l’intera applicazione; gestisce la totalità dei componenti dell’applicazione attraverso istanze delle classi corrispondenti, amministra direttamente la comunicazione con il Wiimote e con la Balance Board e fornisce diversi metodi che vengono chiamati dagli altri componenti per accedere ad alcune informazioni o per eseguire dei comandi su oggetti controllati direttamente dalla classe principale. Il software può trovarsi in diversi stati, o modalità, che vengono controllate per mezzo di una variabile il cui valore funziona da discriminante. Ad una variazione dello stato, la classe DrumAble si preoccupa di inizializzare i componenti attivi nella nuova modalità e di attivarli. 50 8.1.1 Modalità di esecuzione La specifica del software prevede che durante la fase di esecuzione, l’applicazione possa trovarsi in una particolare modalità; ogni modalità definisce un preciso funzionamento del programma in merito a logica di esecuzione e componenti utilizzati (attivi). Le modalità sono le seguenti: • Menu: schermata principale del menu • Free Play: modalità nella quale l’utente può suonare liberamente qualsiasi strumento della batteria • Tracklist: sezione del menu in cui l’utente può selezionare la traccia da riprodurre • Speed: menu di scelta della velocità di riproduzione delle tracce • Play: rappresenta la fase di gioco; è accessibile soltanto se è stata precedentemente selezionata una traccia • Instructions: contiene istruzioni per l’uso dell’applicazione • Exit: modalità di pre-uscita; vi si accede nel momento in cui l’utente decide di terminare il programma, ed è fondamentale per la deallocazione delle istanze create durante l’esecuzione e la corretta sequenza di operazioni da compiere prima di terminare il processo 8.1.2 Compiti della classe DrumAble Le mansioni della classe DrumAble vengono eseguite all’interno dei seguenti metodi predefiniti: • Il costruttore della classe DrumAble inizializza i vari componenti creandone le istanze e aggiungendoli alla Component List, inizializza la grafica e il Content Pipeline • Nel metodo Initialize avvengono le connessioni con il Wiimote e con la Balance Board e l’inizializzazione dell’audio; viene impostato lo stato iniziale dell’applicazione, ovvero l’accesso al menu principale • Il metodo Update valuta continuamente lo stato dell’applicazione, e nel caso rilevi una variazione dello stato, avvia una procedura specifica per passare nella nuova modalità; in questo metodo avviene inoltre l’aggiornamento dell’audio 51 Vi sono altri metodi invocati alla creazione o eliminazione dei vari componenti, durante un cambiamento di modalità o alla terminazione del programma. I dati provenienti dai dispositivi di input vengono prelevati dalla classe DrumAble: essa fornisce ai vari componenti soltanto una parte dei dati, strettamente necessaria al loro funzionamento; pertanto l’accesso alle informazioni da parte dei componenti è filtrato dalla classe principale. 8.2 I componenti della sezione menu Vengono qui elencate le classi i cui compiti rientrano nell’ambito del menu dell’applicazione. 8.2.1 La classe Menu Il menu è un componente grafico che descrive la schermata principale dell’applicazione, dalla quale sono accessibili tutte le altre funzionalità. Questa classe non esegue operazioni particolarmente complesse; si occupa della visualizzazione su schermo del menu principale e della selezione di una tra le varie voci del menu, evidenziando graficamente la voce correntemente “puntata” e notificando alla classe DrumAble il cambiamento dello stato del programma nel caso di selezione di una delle voci. 8.2.2 La classe Istruzioni È un componente grafico che contiene alcune schermate di introduzione al videogioco e nelle quali vengono spiegate le funzionalità e i gesti da compiere per suonare determinate percussioni. 8.2.3 La classe Tracklist La classe Tracklist descrive un componente grafico all’interno del quale è possibile selezionare, tra diverse tracce, quella da riprodurre durante la fase di gioco. Oltre a visualizzare un elenco di tali tracce e a notificare alla classe principale un’eventuale 52 selezione di una tra queste, dispone di due metodi che abilitano la riproduzione (o la sospensione) di un’anteprima della traccia evidenziata, operazione poi gestita dalla classe RiproduzioneSequenza. 8.2.4 La classe Speed Questo componente grafico rappresenta una sezione del menu in cui compaiono tre diversi livelli di velocità e difficoltà di riproduzione delle tracce. La selezione di uno di questi livelli provoca una notifica alla classe principale del livello scelto. 8.2.5 La classe RiproduzioneSequenza Si tratta di un componente standard la cui logica permette di riprodurre un’anteprima (audio) di una tra le tracce disponibili nella Tracklist. Una volta prelevati (mediante la classe Traccia) i dati relativi alla sequenza, viene valutato, all’interno del metodo Update, l’istante corrente e, se corrisponde all’istante in cui deve avvenire il suono di uno strumento, viene invocato il metodo Play della classe Audio, riproducendo il suono. 8.3 Le tracce predefinite 8.3.1 La classe Traccia Le tracce riproducibili nella fase di gioco, sono memorizzati in un file Xml con uno schema opportuno, che consiste in un insieme di tuple <Percussione, Istante>, ordinate per istante crescente, che rappresentano ogni suono della traccia. Della lettura di tale file e memorizzazione in una Struct adeguata si occupa la classe Traccia, tramite un oggetto DataSet. All’inizializzazione di un’istanza di questa classe, nel costruttore avviene la lettura del file Xml, e successivamente il contenuto viene memorizzato in un DataSet. Viene poi definita una Struct che rappresenta una tupla <Percussione, Istante>, adibita a contenere una riga della tabella definita nel file. La classe Traccia dispone di alcuni metodi che consentono di 53 prelevare una singola tupla, il numero di tuple presenti nel DataSet, o l’intera traccia (fornita come array di tuple). 8.3.2 I DataSet I DataSet consentono la lettura e la manipolazione di informazioni provenienti da una base di dati, o memorizzate in un file Xml, mediante codice C#; è così possibile prelevare e alterare grandi quantità di dati con poche e semplici istruzioni, come se si stesse operando su una base di dati. L’oggetto DataSet rappresenta un DataBase, ed è strutturato come segue: • DataSet o DataTable DataColumn DataRow Inoltre fornisce una quantità notevole di metodi per la manipolazione dei dati, nonché metodi che leggono o scrivono automaticamente file Xml all’interno dei quali viene memorizzata la totalità dei dati contenuti in una singola tabella o in un intero DataBase. 8.4 L’input della fase di gioco 8.4.1 La classe Percussione La classe Percussione svolge il compito fondamentale di rilevare i movimenti compiuti dall’utente mediante un’analisi dei valori dell’accelerometro letti dal Wiimote e dal Nunchuk. Questa classe non costituisce un componente XNA, ma è una classe standard C# il cui comportamento è direttamente controllato dalla classe principale e, per riferimento, dai componenti relativi alla fase di gioco. L’istanza della classe Percussione viene inizializzata all’accesso da parte dell’utente alla fase di gioco (o alla modalità Free). Alla creazione dell’istanza, la classe Percussione riceve un riferimento all’oggetto WiiMote dalla classe principale. Può così accedere direttamente alle informazioni lette dal dispositivo, e analizzarle per determinare il compimento di un particolare gesto corrispondente al suono di una percussione. 54 8.4.2 Rilevamento dei gesti La classe Percussione dispone di un metodo, IndividuaMovimento, che si occupa del rilevamento dei gesti compiuti dall’utente corrispondenti al suono di una percussione. L’invocazione di questo metodo è gestita dai componenti della fase di gioco; questa tecnica consente all’applicazione di porre un controllo restrittivo sui movimenti ed evitare l’erronea interpretazione di un piccolo spostamento di un telecomando come se corrispondesse al suono di uno strumento. Senza questo accorgimento l’applicazione non consentirebbe all’utente di riportare il telecomando nella posizione di partenza una volta eseguito un gesto, come effettivamente deve avvenire anche nel suono di una percussione reale. La logica che descrive questo controllo si basa sul fatto che se in un certo istante è stata suonata una certa percussione, e cioè è stato eseguito il gesto relativo a tale suono, in tale istante nessun altro gesto può essere stato compiuto. 8.4.3 Evento PercussioneChanged All’invocazione del metodo IndividuaMovimento, viene eseguito un controllo dei valori degli accelerometri del Wiimote e del Nunchuk. Se viene riconosciuto un movimento, viene lanciato l’evento PercussioneChanged, definito all’interno della classe Percussione. Gli argomenti di tale evento sono due variabili che rappresentano gli strumenti suonati mediante i movimenti del Wiimote e del Nunchuk. In questo modo è possibile rilevare gesti compiuti simultaneamente con entrambi i dispositivi. Nel caso in cui venisse scosso un solo telecomando, la variabile relativa all’altro assumerà valore null. 8.4.4 La classe BalanceBoard La classe BalanceBoard si occupa di individuare lo spostamento del centro di massa dell’utente mediante la lettura dei dati rilevati dai sensori di peso della Balance Board. Questa classe, così come la classe Percussione, non costituisce un componente XNA, ma è una classe standard C# il cui comportamento è direttamente controllato dalla classe principale e, per riferimento, dai componenti relativi alla fase di gioco. 55 L’istanza della classe BalanceBoard viene inizializzata dopo l’avvenuta connessione del dispositivo all’applicazione. Alla creazione dell’istanza, la classe BalanceBoard riceve un riferimento all’oggetto Wiimote dalla classe principale. Può così accedere direttamente alle informazioni lette dal dispositivo, e analizzarle per determinare l’eventuale spostamento del busto da parte dell’utente. 8.5 I componenti della fase di gioco 8.5.1 La classe PlayScreen Nella classe PlayScreen è descritto un componente grafico che si occupa della visualizzazione della batteria virtuale e del sistema di controllo della postura. Questo componente viene attivato sia nella modalità libera che durante la fase di riproduzione di una traccia. Nella modalità Free viene visualizzata una Texture che rappresenta l’intera batteria virtuale, mentre nella fase di gioco viene disegnato soltanto uno scheletro della batteria, sopra al quale vengono evidenziati man mano gli strumenti che devono essere suonati nei vari istanti della riproduzione. La possibilità di utilizzare lo stesso componente nelle due diverse modalità deriva dal fatto che esso si occupa esclusivamente di caricare nel Content Pipeline le Texture relative ai vari strumenti della batteria, e della visualizzazione su schermo di alcune di queste Texture all’invocazione del metodo Draw. La Texture da visualizzare viene impostata all’inizializzazione del componente e successivamente (solo se ci si trova nella fase di gioco) attraverso il metodo SetDrumKitTexture, invocato dalla logica di gioco. Il sistema di controllo della postura, per scelta progettuale, è invece presente in entrambe le modalità di gioco. La classe PlayScreen si occupa inoltre della riproduzione del suono corrispondente a un gesto compiuto dall’utente; essa possiede un riferimento all’istanza della classe Percussione contenuta nella classe principale e, mediante un event-handler, intercetta l’evento sollevato dalla classe Percussione e in risposta invoca il metodo Play della classe Audio riproducendo così il suono corrispondente al gesto compiuto. 56 Durante la gestione della risposta all’evento, il componente si occupa anche di posizionare una Texture relativa al Wiimote o al Nunchuk (o a entrambi) sullo strumento suonato dall’utente con il telecomando corrispondente, evidenziando così qual è la percussione che viene suonata al compimento di un gesto. 8.5.2 La classe Logica Questo è un componente standard il cui compito è la gestione della logica di gioco durante la fase di riproduzione di una traccia. All’inizializzazione, il componente preleva le informazioni della traccia da riprodurre per mezzo di un oggetto di tipo Traccia; usa quindi questi dati per elaborare la sequenza di percussioni da riprodurre e definire gli istanti di tempo inerenti il suono di ciascuna percussione. Durante l’intervallo di tempo utile per il suono di una percussione nella traccia, la logica invia i comandi al componente PlayScreen per la visualizzazione delle Texture attive. Queste operazioni avvengono nel metodo Update, utilizzando la variabile GameTime, che identifica il tempo di gioco, come riferimento per gli intervalli di tempo. Il componente Logica riceve nella propria inizializzazione il riferimento all’istanza della classe Percussione dalla classe DrumAble, e sottoscrive un event-handler all’evento PercussioneChanged; in questo modo, ogni volta che l’utente compie un gesto con un telecomando, la logica valuta il compimento di tale gesto che, se corrisponde al suono dello strumento previsto dalla traccia nell’intervallo di tempo corretto, viene validato, con un conseguente aggiornamento positivo del punteggio. Se invece all’intercettazione dell’evento la percussione suonata non corrisponde a quella corretta il punteggio viene ridotto. 57 Capitolo 9. Sviluppi futuri La tecnologia del Wiimote, per quanto riguarda la rilevazione dei movimenti, è efficace ma non particolarmente precisa: infatti nel luglio 2009, a quasi 3 anni di distanza dal debutto sul mercato del Wii, per correggere questo difetto Nintendo ha commercializzato Wii Motion Plus (vedi paragrafo 3.5.3). Un possibile sviluppo del progetto è l’implementazione di questo accessorio, in modo da rendere ancora più realistici i movimenti da compiere per suonare gli strumenti della batteria virtuale. Un’altra possibile estensione del progetto, è la sostituzione della grafica 2D, introducendo per la fase di gioco un ambiente 3D in stile Guitar Hero (videogame musicale particolarmente apprezzato dal grande pubblico), consistente in una pista sulla quale scorrono i simboli relativi agli strumenti da suonare. 58 Elenco figure Figura 1: Wiimote ..............................................................................................................7 Figura 2: Wiimote e assi direzionali ...................................................................................9 Figura 3: Sensor Bar ........................................................................................................12 Figura 4: Nunchuk collegato al Wiimote ..........................................................................16 Figura 5: Wii Balance Board ............................................................................................18 Figura 6: IVT Bluesoleil ..................................................................................................22 Figura 7: Sincronizzazione Wiimote ................................................................................23 Figura 8: Visuale dei movimenti del Wiimote corrispondenti al suono delle percussioni ..38 Figura 9: Batteria Virtuale. ...............................................................................................39 Figura 10: Membri di Wiimotelib e delle classi Wiimote e WiimoteState .........................46 Elenco Tabelle Tabella 1: Profili Bluetooth supportati da BlueSoleil ........................................................22 Tabella 2: Associazione tra movimenti e percussioni........................................................40 Tabella 3: Classi implementate nel progetto .....................................................................50 59 Bibliografia [1] http://www.nintendo.it/NOE/it_IT/systems/wii_1069.html [2] http://en.wikipedia.org/wiki/History_of_video_game_consoles_(seventh _generation) [3] I. Bromley “Tetraplegia And Paraplegia - A guide for physiotherapists”, Churchill Livingstone [4] http://wiibrew.org/wiki/ [5] http://en.wikipedia.org/wiki/Human_interface_device [6] http://www.bluetooth.com/Bluetooth/Technology [7] http://www.bluesoleil.com/ [8] http://www.brianpeek.com/ [9] http://www.codeplex.com/ [10] http://blogs.msdn.com/coding4fun/archive/2007/03/14/1879033.aspx [11] http://msdn.microsoft.com/it-it/academic/default.aspx [12] http://msdn.microsoft.com/it-it/vstudio/products/bb931331.aspx [13] Andrew Troelsen “Pro C# And The .Net 3.5 Platform”, Apress [14] http://it.wikipedia.org/wiki/Delphi 60 [15] http://creators.xna.com/ [16] Riemer Grootjans “XNA 3.0 Game Programming Recipes - A Problem-Solution Approach”, Apress [17] http://en.wikipedia.org/wiki/Percussion [18] http://en.wikipedia.org/wiki/Drumkit [19] http://www.freesound.org/ 61 Ringraziamenti Al termine della realizzazione di questo progetto, sentiamo di dover ringraziare tutte le persone che ci hanno dato la possibilità di arrivare alla conclusione di questo ciclo di studi. Ringraziamo in primis le nostre famiglie e tutti gli amici per il continuo supporto ricevuto, soprattutto nei momenti di difficoltà. Desideriamo inoltre esprimere la nostra gratitudine nei confronti dei relatori, che ci hanno saputo proporre un ambito di progetto interessante e allo stesso tempo divertente, instradandoci sulle linee guida più appropriate, e stimolando in noi particolare dedizione. Enrico Roberto 62
Documenti analoghi
Capitolo 1 - Università degli Studi dell`Insubria
La classe Giocatore ...................................................................................... 45