Cos è il VrmlScript
Procedendo nell'elaborazione di animazioni più complesse e soprattutto con un alto grado di interattività, si dovranno affrontare spesso problemi che non sono risolvibili con i semplici meccanismi di animazione offerti dal puro VRML. In effetti, come si è visto nel precedente capitolo, l'interruttore del nostro esempio non funziona come un reale interruttore. Con il VRML 2.0 si è deciso di fornire un meccanismo sufficientemente flessibile per programmare comportamenti anche piuttosto complessi. Esiste cioè la possibilità di programmare gli eventi all'interno dei mondi, mediante l'inserimento di codice script, utilizzando il linguaggio denominato VrmlScript.
Vrmlscript è un linguaggio di scripting molto simile a JavaScript. E in realtà, le specifiche fanno pieno riferimento a JavaScript quale linguaggio di scripting per il VRML; ma nel nostro caso si è deciso di utilizzare VrmlScript. Primo perché in questa sede ci è sembrato più appropriato illustrare, seppur in maniera succinta, il funzionamento del meno noto VrmlScript;
e poi perchè in pratica non sussistono reali differenze tra i due linguaggi.
Il nodo Script
Per definire uno script in VRML è necessario ricorrere al nodo Script. Ne analizzeremo la struttura fondamentale, tralasciando le parti che non sono necessarie ai nostri scopi:
Script {
eventIn
eventOut
field tipo
exposedField
url
}
Un campo eventIn come si sà è un campo i cui valori vengono settati da un altro nodo. Uno eventOut, viceversa, esporta i propri valori verso l'esterno. Un field, agisce solo all'interno dello script, in quanto i nodi esterni non hanno alcun accesso ai suoi valori: è possibile dunque settargli un valore iniziale. Un tipo exposedField infine, indica un campo i cui valori sono "esposti": nodi esterni possono cioè accedere a questi valori sia in lettura che in scrittura.
Si tenga presente che il nodo Script può contenere un qualsiasi numero di eventIn, eventOut o fields. I campi da inserire in uno script e il loro tipo saranno quindi decisi dal programmatore del mondo.
L'ultimo campo presentato, url è il più interessante e contiene le funzioni necessarie a gestire gli eventi in ingresso al nodo Script.
Nella spiegazione che segue, si assume un minimo di conoscenza del concetto di "eventi" e della sintassi del linguaggio JavaScript. In ogni caso si è tentato di essere il più chiari possibile, anche a rischio di risultare un po' pedanti.
Interruttore gestito dal VrmlScript
Riconsideriamo il caso dell'interruttore:
1) Vogliamo che quando si "clicca" sull'interruttore l'animazione venga avviata sino al "click" successivo. Vogliamo in pratica che in risposta all'evento "click" causato dalla pressione dell'utente sul'interruttore, vengano eseguite delle azioni. Il nostro script quindi, dovrà essere in grado di ricevere in ingresso un evento che è legato all'evento "click" in uscita dal nodo TouchSensor. Si è deciso, per chiarezza espositiva, di assegnargli il nome "interruttorecliccato":
eventIn SFBool interruttorecliccato
2) Come si è visto, nel nostro caso l'evento "click" sul nodo TouchSensor può avere due significati: se l'animazione è inattiva, l'evento "click" significa in pratica:"lancia il missile", quando invece il nostro missile è già in viaggio, lo stesso evento significa:"blocca il missile". Pertanto, se il missile è fermo il "click" sul bottone deve "resettare" il campo enabled del nodo TimeSensor con il valore trUE in modo da avviarlo. Viceversa dovrà inviare lo stato FALSE in modo da disattivare il nodo TimeSensor.
Quindi, dovremo avere un eventOut che attivi o disattivi il campo enabled del nodo TimeSensor:
eventOut SFBool significatodelclick
3) Infine è necessario stabilire una variabile interna che serva a registrare lo stato (attivato o meno) dell'interruttore. Chiamiamo questo field con il nome di "statodelmissile". Anche in questo caso il tipo del campo dovrà essere di tipo SFBool e verrà inizializzato a FALSE, ad indicare che lo stato iniziale del missile è immobile e l'interruttore è disattivato.
field SFBool statodelmissile FALSE
Ricapitolando, la prima parte dello script risulta essere la seguente:
DEF on_off Script {
eventIn SFBool interruttorecliccato
eventOut SFBool significatodelclick
field SFBool statodelmissile FALSE
...
}
Si noti che al momento della definizione dello script gli abbiamo assegnato il nome "on_off".
4) Definiti gli elementi dello script, occorre ora stabilire quali sono le azioni che si vogliono eseguire in risposta agli eventi. Lo script, evidentemente, reagisce se riceve in ingresso degli eventi. In questo caso, la nostra funzione deve specificare come rispondere al verificarsi di un certo evento. Si tenga anche presente che un campo in uscita invia il suo valore ogni volta che viene modificato.
Vediamo la porzione di codice contenente la nostra funzione :
url "vrmlscript:
function interruttorecliccato(bottone) {
if (bottone == 0) {
if (statodelmissile == 0)
statodelmissile = 1 ;
else
statodelmissile = 0 ;
significatodelclick = statodelmissile ;
}
}
"
}
La dichiarazione vrmlscript risulta necessaria per indicare quale è il linguaggio di scripting da utilizzare. Dopodiche si è dichiarata la funzione denominata interruttorecliccato. Questa contiene tra parentesi il parametro che abbiamo chiamato bottone.
Infine si sono indirizzati gli eventi in uscita per quanto riguarda il funzionamento dell'interruttore:
ROUTE interruttore.isActive TO on_off.interruttorecliccato
ROUTE on_off.significatodelclick TO tempo.enabled
Come si vede il primo ROUTE invia il valore di isActive del nodo TouchSensor al campo interruttorecliccato. Sarà quindi compito della funzione gestire questo evento.
L'ultimo comando ROUTE, dichiara che la variabile significatodelclick è collegata al campo enabled del nodo TimeSensor da cui, come sappiamo, dipende l'attivazione o meno dell'animazione. Quando il valore di significatodelclick cambia, essa emette un evento che viene catturato dal nodo TimeSensor. Questo, infine "resetta" il campo enabled con il nuovo valore che gli viene passato ad ogni "click".