Qualche volta può capitare di voler creare delle trasformazioni interattive, attivabili utilizzando la tastiera o semplicemente muovendo il mouse sullo stage.
Inoltre, per certi scopi, può essere necessario far muovere automaticamente degli oggetti, senza alcun intervento dell'utente.
Sandy offre metodi più o meno elaborati per animare il proprio mondo 3D!
Per i movimenti più semplici è possibile utilizzare il "solito" oggetto Transform3D
, creando però degli eventi temporizzati per le animazioni, piuttosto che basarsi sugli interventi dell'utente. Chi ha utilizzato il metodo onEnterFrame
di Flash avrà familiarità con questo metodo: l'enterFrame
infatti richiama una determinata serie di azioni a ogni fotogramma, per cui, ad esempio, se il frame rate è di 12 frame al secondo (fps), le azioni presenti nell'evento EnterFrame
si verificheranno ogni 1/12 di secondo.
Allo stesso modo, all'interno dell'oggetto World3D
di Sandy, c'è un evento, onRenderEvent
, che viene richiamato ogni volta che la scena viene renderizzata, ovvero per ogni "frame" della scena di Sandy.
Nell'esempio creeremo una rotazione automatica di un gruppo (che conterrà il "solito" cubo). Dovremo pertanto implementare l'intercettazione dell'evento onRenderEvent
e preparare una funzione che aggiorni l'angolo di rotazione e di conseguenza modifichi l'oggetto sulla scena.
Nel file di esempio, per rendere l'effetto più gradevole, è stata usata una trasformazione combinata e il cubo ha una traslazione iniziale di 25,25,0.
Il pannello inserito all'interno del filmato, per avviare la rotazione, questa volta, ha tre pulsanti che permettono di scegliere su quale asse far ruotare il cubo, e due pulsanti "Run" e "Stop" per avviare o interrompere l'animazione.
Per mantenere memorizzato il valore della rotazione in ogni momento utilizzeremo le variabili xRot
, yRot
e zRot
, mentre per l'angolazione del box utilizzeremo le variabili xDel
, yDel
e zDel
.
Listato 22. Gestisce l'evento onRenderEvent
// Gestione degli eventi
function createHandlers(){
// Ogni volta che si verifica l'onRenderEVENT, viene chiamata la funzione rotate
world.addEventListener (World3D.onRenderEVENT, this, rotate);
// Il bottone startButton avvia la rotazione
startButton.onRelease = function(){
running = true;
}
// il bottone stopButton invece la ferma
stopButton.onRelease = function(){
running = false;
}
// A seconda del pulsante premuto viene scelto l'asse di rotazione
xRotButton.onRelease = function(){
xDel = angleStep;
yDel = zDel = 0;
}
yRotButton.onRelease = function(){
yDel = angleStep;
xDel = zDel = 0;
}
zRotButton.onRelease = function(){
zDel = angleStep;
xDel = yDel = 0;
}
}
Per ogni fotogramma di Sandy (quindi per ogni volta che si verifica l'evento onRenderEvent
), viene richiamata la funzione rotate()
, che aumenta la rotazione.
I bottoni di avvio e arresto dell'animazione semplicemente impostano la variabile running
su true o su false; tale variabile viene utilizzata dalla funzione rotate()
per stabilire se eseguire o meno il movimento.
Se guardiamo il codice associato all'evento onRelease
del pulsante xRotButton
, possiamo vedere che imposta la variabile xDel
al valore di angleStep
, mentre yDel
e zDel
vengono impostate a zero, ciò per impostare l'asse X come asse di rotazione; le azioni associate a yRotButton
e zrotButton
hanno lo stesso scopo per i rispettivi assi.
Vediamo infine la funzione rotate()
, che si occupa di ruotare il cubo all'interno della scena.
Listato 23. Ruota il cubo all'interno della scena
function rotate(){
if( running ){
xRot += xDel; yRot += yDel; zRot += zDel;
rotation.rot( xRot, yRot, zRot );
}
}
Vediamo che, se la variabile running
è impostata su true, la funzione calcola i nuovi valori per la rotazione attorno ai tre assi, quindi tramite la funzione rot()
dell'oggetto Transform3D
applica la rotazione con i nuovi valori. Il valore di angleStep
verrà incrementato per l'asse di rotazione scelto dall'utente, mentre rimarrà invariato per altri due assi:
Rotazione automatica su un asse
Dopo aver provato i pulsanti poniamoci le seguenti domande: c'è un punto del cubo che non si sposta mai dalla sua posizione originale? La rotazione avviene come ci aspettiamo di vedere?
Per la seconda domanda, suppongo che la risposta sia no, non sempre. Il motivo è l'ordine della rotazione intorno agli assi; ecco cosa dice la documentazione di Sandy riguardo alla funzione rot()
:
public function rot(px:Number, py:Number, pz:Number):Void
Realize the euler rotation matrix based on the three angles in degrees.
Parameters
px Number Angle of rotation in degrees around the X axis
py Number Angle of rotation in degrees around the Y axis
pz Number Angle of rotation in degrees around the Z axis
Non troviamo molte informazioni riguardo al nostro problema, ma notiamo che vengono menzionate le matrici di Euler (possiamo trovare molte informazioni su internet): per i matematici più bravi, consiglio il link "Euler angles", dove sono riportate discussioni e calcolo delle matrici. Per i meno esperti, consiglio una rapida occhiata a "Euler Angles are Evil", dove si trova una spiegazione meno "tecnica".
Possiamo concludere dicendo che per avere una rotazione "pulita" intorno a un asse per volta, sarebbe necessario utilizzare tre TransformGroup
e tre Transform3D
, uno per ogni asse.
"© Petit Publications 2006" - diritti riservati