|
||||||
ROBOTICA
video
immagini
papers
progettati
costruiti
toolbox
vrml
simulatori
Vrmlscript |
Siamo ormai giunti al termine
del tutorial. Ma abbiamo ancora un problema da risolvere. L’interruttore dell’esempio
precedente non funziona a dovere.
Sono innumerevoli i problemi
che possiamo incontrare che non sono risolvibili con i mezzi che conosciamo.
Fino ad ora abbiamo fatto leva sui meccanismi di animazione offerti da vrml.
Esiste un meccanismo molto flessibile per programmare comportamenti anche
molto complessi. Questo meccanismo consiste nella possibilità di inserire
script all’interno del nostro mondo.
Parlando di scripting
ci si deve avvicinare ai concetti soliti della programmazione tradizionale.
Non faremo qui un’analisi dettagliata di vrmlscript. Ci fermeremo ad una sua
descrizione sommaria e tale da consentirci di risolvere il problema precedente
e altri simili.
Vrmlscript è un linguaggio
di scripting molto simile agli script java.
Ho tralasciato alcune
parti. I primi 3 campi riportati sono solo a tipo di esempio. Un nodo Script
può contenere un qualsiasi numero di eventIn, eventOut o fields.
Un campo eventIn sarà
un campo che viene settato da un altro nodo. Uno eventOut verrà esportato
verso l’esterno. Un field agirà solo all’interno dello script; posso dunque
settargli un valore iniziale.
I campi da inserire in
uno script e il loro tipo saranno decisi dal programmatore del mondo.
Il campo url è il più
interessante e contiene le funzioni necessarie a gestire gli eventi in ingresso
al nodo Script.
Vediamo un esempio per
chiarire a fondo questi concetti. Nella spiegazione assumo un minimo di conoscenza
del linguaggio C.
Come esempio, riconsideriamo
il caso dell’interruttore. Vogliamo che quando si clicca sull’interruttore
il cubo ruoti sino ad un futuro click. Abbiamo visto che non riusciamo a risolvere
il problema con i soliti meccanismi built-in. Proviamoci allora con uno script.
Riflettiamo sugli ingressi
che questo deve avere. Vogliamo che delle azioni vengano effettuate in conseguenza
del click dell’utente sulla placchetta. Per cui dovremo avere un evento in
ingresso legato all’evento in uscita del nodo TouchSensor. Pensiamo poi a
cosa vogliamo comandare. Vogliamo attivare o deattivare il campo enabled del
nodo TimeSensor. Dovremo dunque avere un eventOut che serve a tale scopo.
Il tipo del campo in
ingresso dovrà essere un SFBool perché il campo isActive del nodo TouchSensor
emette un valore booleano. Lo stesso per quanto riguarda il campo in uscita
in quanto deve matchare con il campo destinazione che è il campo enabled del
nodo TimeSensor.
Per cui a questo punto
so già che il mio script avrà un eventIn e un eventOut, entrambi di tipo SFBool.
Se pensiamo ancora un
po’ a come è realizzato un interruttore, non possiamo fare a meno di associargli
uno stato, una qualche memoria. Infatti il suo funzionamento dipende dallo
stato in cui si trova. Se il cubo sta ruotando devo mandare FALSE al campo
enabled. Viceversa dovrò mandare TRUE. Definisco allora una variabile interna
che serve appunto a ricordarsi dello stato (attivato o meno) dell’interruttore.
Questo campo non necessita di essere visto dall’esterno e di certo non nasce
da un evento esterno. Ne segue che avremo bisogno di un field. Chiamiamo questo
field con il nome di ‘stato’. Il tipo del campo sarà ancora un booleano e
verrà inizializzato a FALSE, ad indicare che il cubo inizialmente non ruota
e l’interruttore è disattivato.
Per cui possiamo scrivere
la prima parte dello script.
Ciò che manca ora è la
parte di risposta agli eventi. Lo script reagisce solo se riceve in ingresso
degli eventi. Dobbiamo dunque scrivere una funzione per ogni eventIn dichiarato.
Essa specifica cosa fare quando si riceve un certo evento. Il campo in uscita
esporta il suo valore ogniqualvolta viene modificato.
Per cui vediamo il nodo
completo :
Come si vede faccio il
routing di isActive del nodo TouchSensor al campo clicked che è appunto un
eventIn. Ho quindi pronta una funzione per gestire questo evento. Come avevo
detto in precedenza il nodo TouchSensor in occasione di un click emette due
eventi, uno per la pressione e uno per il rilascio del pulsante del mouse.
Quando si spedisce un evento si mandano due parametri alla funzione che lo
gestisce. In questo caso ne uso solo uno e lo chiamo button_pos. I due parametri
inviati sono il valore associato al campo in eventOut e il timestamp dell’evento
stesso (il tempo in cui l’evento è stato elevato). Nel caso del nodo TouchSensor
si spedisce un primo evento con isActive che vale TRUE e un secondo evento
con isActive che vale FALSE quando rilascio il pulsante. Ricordando che un
valore è FALSE quando vale 0, si vede che consideriamo solo il secondo evento,
tralasciando il primo. Così facendo riceviamo un solo evento per ogni click.
Per ogni evento considerato ci si chiede quale era lo stato precedente e lo
si inverte. Alla fine della funzione assegnamo il nuovo valore alla variabile
click_changed che, ricordo, è un eventOut.
Se osserviamo l’ultimo
comando ROUTE, si vede che la variabile click_ changed è collegata al campo
enabled del nodo TimeSensor da cui dipende l’animazione. Dato che il valore
di click_ changed è cambiato, essa emette un evento che viene catturato dal
nodo TimeSensor. Questo setta il campo enabled con il valore che gli viene
passato.
Risultato, il cubo continuerà
a girare sino al prossimo click e noi avremo ottenuto il nostro interruttore.
Ovviamente il sorgente
sopra riportato va inserito nell’esempio sviluppato nei precedenti paragrafi.
Stanza con orologio e cubo che gira a dovere!
Possiamo avere più eventIn.
In questo caso avremo più funzioni, definita una dopo l’altra tra gli apici
del campo url. La scritta vrmlscript è necessaria per indicare quale sia il
linguaggio di scripting da utilizzare.
Le specifiche in realtà
parlano di javascript ; ma sia Cosmo Player che Live3d supportano vrmlscript
per cui ho utilizzato questo. Del resto le differenze tra i due in pratica
non sussistono.
Abbiamo raggiunto ormai
la fine. Ora dovreste essere in grado di costruire mondi molto interessanti
dal punto di vista del realismo e dell’interazione.
Nelle prossime sezioni
vedrò di spiegare molto rapidamente come inserire fonti sonore e descriverò
a livello qualitativo l’interfaccia per Java e CGI.
Per definire uno script in vrml dobbiamo fare ricorso al nod Script. Analizziamone
la struttura.
Script {
...
eventIn tipo nomecampo
eventOut tipo nomecampo
field tipo nomecampo initial value
exposedField url [ ]
}
DEF accendi_spegni Script {
eventIn SFBool clicked
eventOut SFBool click_changed
field SFBool active FALSE
...
}
DEF accendi_spegni Script {
eventIn SFBool clicked
eventOut SFBool click_changed
field SFBool active FALSE
url “vrmlscript :
function clicked(button_ pos) {
if (button_pos == 0) {
if (active == 0)
active = 1 ;
else
active = 0 ;
click_changed = active ;
}
}
“
}
ROUTE interruttore.isActive TO accendi_spegni.clicked
ROUTE accendi_spegni.click_changed TO tempo.enabled