Gestire gli eventi in CreateJS (seconda parte)
Continuano gli articoli legati alla mi piccola guida su come programmare createJS con Adobe Animate. Nella prima parte di questo articolo, abbiamo introdotto i principali eventi gestiti dal linguaggio analizzandoli tramite qualche piccolo esercizio pratico. In particolare, abbiamo iniziato la creazione di una pagina in HTML5 utile per testare le interazioni generate dal mouse e l’evento ricorsivo tick. Di seguito vediamo come completare l’esempio.
Come anticipato la volta scorsa, il codice visto in precedenza aveva bisogno di due ritocchi finali: una procedura per interrompere o riattivare la rotazione del clip filmato e un meccanismo di sicurezza capace di impedire l’incremento della velocità di rotazione.
Per quanto riguarda la rimozione degli eventi, createJS non usa la solita prassi vista in altri linguaggi di programmazione, tuttavia possiamo comodamente “accendere” o “spegnere” un evento specifico grazie ad una coppia di metodi denominati rispettivamente on e off.
I due metodi, semplicissimi da usare, lavorano in squadra e sono il corrispettivo di addEventListener e removeEventListner. La sintassi generale dell’evento on è molto intuitiva:
nomeistanza.on(“evento”,nomefunzione);
Dove nomeistanza è l’oggetto al quale si vuole associare l’evento e nomefunzione() la funzione da eseguire. Con qualche piccola modifica possiamo predisporlo per l’utilizzo del metodo off. Vediamo come:
var mioevt=nomeistanza.on(“evento”,nomefunzione);
nomeistanza2.off(“evento”,mioevt);
Nella prima riga di codice assegniamo l’istruzione scritta precedentemente ad una variabile denominata mioevt. Si tratta di un riferimento che ci servirà più avanti. Nella riga successiva associamo ad un oggetto denominato nomeistanza2 il metodo off. Questo metodo ha due parametri: l’evento che vogliamo disattivare e la variabile di riferimento usata per il metodo on.
Chi mastica un pochino di JavaScript noterà la similitudine tra l’evento off e il metodo clearInterval: in entrambi i casi è necessario usare delle variabili come parametri, ed in entrambi i casi abbiamo metodi la cui finalità consiste nell’annullare un’istruzione complementare.
Per evitare un taglio troppo teorico facciamo un veloce esempio pratico. Supponiamo di avere una pagina HTML5 canvas caratterizzata da due pulsanti denominati p1 e p2. I due elementi sono semplici rettangoli colorati contraddistinti da una scritta. Il primo ruota ad ogni clic e il secondo rimuove l’evento che innesca la rotazione. Il codice createJes, collocato nel primo fotogramma, è il seguente:
var mioevt = this.p1.on("click", rt.bind(this)); function rt() { this.p1.rotation += 10; } this.p2.on("click", blocca.bind(this)); function blocca() { this.p1.off("click", mioevt); }
Nella prima parte del codice abbiamo un’istruzione che associa un evento click al pulsante p1. Ogni volta che l’utente clicca su di esso, verrà eseguita una funzione il cui compito è quello di incrementare la proprietà rotation dell’istanza. Come abbiamo visto precedentemente, per poter usare off, è necessario passare ad una variabile l’istruzione inerente il metodo on.
Nel secondo blocco di codice, abbiamo un evento click associato ad un pulsante p2. Quando l’utente lo preme, viene innescata la funzione listener la quale esegue il metodo off: tale metodo ha come primo parametro l’evento click e come secondo la variabile mioevt creata in precedenza. Ed il gioco è fatto: con poche semplicissime righe abbiamo visto come spegnere un evento click. A questo indirizzo trovate il sorgente:
Questa piccola digressione ci fornisce gli strumenti per completare l’esempio iniziato la volta scorsa. Usando i metodi on e off, potremo attivare e disattivare la rotazione del clip filmato rotella. Apriamo quindi il sorgente creato la volta scorsa in Adobe Animate e disegniamo un nuovo pulsante caratterizzato dalla scritta “Disattiva Tick”, poi diamogli come nome di istanza p5. Quindi riscriviamo la parte finale del listato visto in precedenza in questo modo:
// evento tick var tk; this.p4.addEventListener("click", accendi.bind(this)); function accendi() { tk=this.on("tick",ruota.bind(this)); campo1.text = "rotazione on"; } function ruota(){ this.rotella.rotation+=1; } this.p5.addEventListener("click", spegni.bind(this)); function spegni() { this.off("tick",tk); campo1.text = "rotazione off"; }
Usando la procedura appena illustrata, abbiamo cambiato le istruzioni associate a p4 usando il metodo on nel corpo della funzione accendi(). Successivamente, abbiamo associato al pulsante p5 le istruzioni che – tramite il metodo off – bloccano l’evento. Per cui adesso abbiamo un pulsante che innesca la rotazione e uno che la interrompe.
L’esempio è quasi ultimato, tuttavia resta il problema dell’incremento di velocità: se l’utente clicca più volte su p4 la ruota gira sempre più veloce. Per regolare anche questo aspetto è sufficiente inserire una semplice istruzione condizionale. Per cui, la parte final del nostro codice cambia in questo modo:
// evento tick var in_movimento=false; var tk; this.p4.addEventListener("click", accendi.bind(this)); function accendi() { if(in_movimento==false){ tk=this.on("tick",ruota.bind(this)); in_movimento=true; campo1.text = "rotazione on"; } } function ruota(){ this.rotella.rotation+=1; } this.p5.addEventListener("click", spegni.bind(this)); function spegni() { this.off("tick",tk); in_movimento=false; campo1.text = "rotazione off"; }
Per agevolare la lettura ho evidenziato le righe aggiuntive con un altro colore. In pratica abbiamo aggiunto una variabile booleana denominata in_movimento il cui valore iniziale è false e un if che ingloba il corpo della funzione accendi(). La condizione verifica che le istruzioni siano eseguite solo se la variabile ha come valore false. Inoltre, in concomitanza della prima esecuzione, la variabile assume il valore true, per cui l’istruzione che attiva la rotazione potrà essere eseguita una sola volta. E con questo il nostro piccolo esempio è ultimato. È possibile scaricare il sorgente a questo indirizzo.
Volendo, possiamo riadattare anche l’esempio visto nel primo articolo dedicato a questa miniguida. Se avete letto l’articolo, avevamo un clip filmato denominato mioclip, controllato da una serie di pulsanti, attraverso i quali era possibile cambiare la sua posizione e il suo aspetto. Solo, per spostarlo ad esempio verso il bordo destro, era necessario premere ripetutamente il pulsante di controllo. Usando i metodi on e off possiamo rendere il tutto più fluido, ottenendo un effetto interattivo degno del vecchio Flash. L’esempio modificato lo trovate QUI.
Per ottenere questo risultato abbiamo usato l’evento tick: le modifiche alle proprietà vengono attuate in modo ricorsivo alla pressione e interrotte al rilascio. Di seguito vediamo come cambia il codice nel primo fotogramma:
var tk; function blocco(){this.off("tick", tk)} // destra this.p_destra.on("mousedown",destra.bind(this)); function destra(){tk=this.on("tick",function(){this.mioclip.x+=5})} this.p_destra.on("pressup",blocco.bind(this)); // sinistra this.p_sinistra.on("mousedown",sinistra.bind(this)); function sinistra(){tk=this.on("tick",function(){this.mioclip.x-=5})} this.p_sinistra.on("pressup", blocco.bind(this)); // alto this.p_alto.on("mousedown",alto.bind(this)); function alto(){tk = this.on("tick",function(){this.mioclip.y-=5})} this.p_alto.on("pressup",blocco.bind(this)); // basso this.p_basso.on("mousedown",basso.bind(this)); function basso(){tk=this.on("tick",function(){this.mioclip.y+=5})} this.p_basso.on("pressup",blocco.bind(this)); //ruota this.p_ruota.on("mousedown",ruota.bind(this)); function ruota(){tk=this.on("tick",function(){this.mioclip.rotation+=5})} this.p_ruota.on("pressup",blocco.bind(this)); // aumenta larghezza this.p_aumentaL.on("mousedown",aumentaL.bind(this)); function aumentaL(){tk=this.on("tick",function(){this.mioclip.scaleX+=0.1})} this.p_aumentaL.on("pressup",blocco.bind(this)); // riduci larghezza this.p_riduciL.on("mousedown",riduciL.bind(this)); function riduciL(){tk=this.on("tick",function(){this.mioclip.scaleX-=0.1})} this.p_riduciL.on("pressup",blocco.bind(this)); // aumenta altezza this.p_aumentaA.on("mousedown",aumentaA.bind(this)); function aumentaA(){tk=this.on("tick",function(){this.mioclip.scaleY+= 0.1})} this.p_aumentaA.on("pressup",blocco.bind(this)); // riduci altezza this.p_riduciA.on("mousedown",riduciA.bind(this)); function riduciA(){tk=this.on("tick",function(){this.mioclip.scaleY-= 0.1})} this.p_riduciA.on("pressup",blocco.bind(this)); // trasparenza this.p_alfa.on("mousedown",alfa.bind(this)); function alfa(){tk=this.on("tick",function(){this.mioclip.alpha-= 0.1})} this.p_alfa.on("pressup",blocco.bind(this)); // ripristina this.p_ripristina.on("click", ripristina.bind(this)); function ripristina() { this.mioclip.alpha = this.mioclip.scaleY = this.mioclip.scaleX = 1; this.mioclip.x = 310; this.mioclip.y = 200; this.mioclip.rotation = 0; }
Per agevolare la leggibilità del listato nel blog, ed evitare testi chilometrici, ho accorpato le varie istruzioni a discapito della tabulazione prevista nelle regole di indentazione.
Cosa cambia rispetto alla prima versione? Semplicemente, attraverso un uso combinato di on e off, abbiamo ogni variazione delle singole proprietà affidate ad un evento tick. Analizziamo il primo blocco di codice, quello relativo al pulsante che muove il clip a destra (tutti gli altri pulsanti sono stati modificati seguendo lo stesso principio).
var tk; function blocco(){this.off("tick", tk)} // destra this.p_destra.on("mousedown",destra.bind(this)); function destra(){tk=this.on("tick",function(){this.mioclip.x+=5})} this.p_destra.on("pressup",blocco.bind(this));
Tanto per cominciare, abbiamo una variabile tk (necessaria per usare il metodo off) e una funzione denominata blocco() che useremo in tutto il listato tutte le volte che dovremo interrompere un evento on. Dopo il commento, nella terza riga di codice, abbiamo un evento on associato al pulsante p_destra: quando l’utente preme il pulsante viene innescata la funzione destra(). Tale funzione fa quello che faceva nella prima versione del codice (ovvero incrementare la x) ma svolge tale compito attraverso un evento tick associato al metodo on.
Nell’ultima riga di codice abbiamo l’istruzione che blocca la modifica della proprietà x: ogni volta che rilasciamo il pulsante attraverso l’evento pressup, la funzione blocco() annulla l’azione della funzione destra(). Quindi attraverso un uso combinato di on e off, muoviamo e fermiamo il clip a nostro piacimento. Quanto detto per questo primo pulsante vale anche per tutti gli altri, cambia solo il tipo di proprietà modificata. Il sorgente del file appena illustrato è reperibile a questo indirizzo:
Per finire, non è che il linguaggio non preveda la possibilità di rimuovere gli eventi senza usare off. Esistono delle alternative come removeAllEventListeners(). Ad esempio se volessimo eliminare tutti gli eventi associati all’oggetto pippo ci basterebbe scrivere:
pippo.removeAllEventListeners();
o in alternativa, se volessimo eliminate solo gli eventi legati al singolo click:
pippo.removeAllEventListeners(“click”)
Tuttavia, a questo approccio preferisco off, che trovo molto più veloce e intuitivo. E con questo per ora è tutto.