Dividere un'immagine, in maniera dinamica, tramite Actionscript, può essere utile per tanti scopi, come ad esempio la creazione di un gioco di puzzle, la scomposizione in più elementi di una foto a grande formato oppure la creazione di particolari effetti visivi.
In questo articolo vedremo come dividere un'immagine tramite Actionscript 3, utilizzando una classe esterna.
Per aprire gli esempi allegati all'articolo è necessario Flash CS3.
Importazione dei package e dichiarazione delle variabili
I passaggi che la classe eseguirà saranno principalmente tre:
- Impostazione dei parametri per la divisione;
- Caricamento dell'immagine da dividere;
- Divisione dell'immagine.
Per eseguire queste operazioni sfrutteremo alcuni package di Actionscript 3, che dovremo quindi importare nella nostra classe, precisamente avremo bisogno dei package:
flash.display
, che sfrutteremo sia per la divisione dell'immagine (tramite le classi BitmapData e Sprite) sia per caricare l'immagine;flash.geom
, che sfrutteremo per la divisione dell'immagine (grazie alle classi Rectangle e Point);flash.events
, che useremo per rilevare il completo caricamento dell'immagine;flash.net.URLRequest
, comando che verrà utilizzato per caricare l'immagine esterna.
Creiamo quindi un nuovo file Actionscript (File -> New -> Actionscript file), che salveremo con nome dividi.as, e scriviamo questo codice:
package{
// importiamo il package flash.display
import flash.display.*;
// importiamo il package flash.geom
import flash.geom.*
// importiamo il package flash.events
import flash.events.*
// importiamo il comando URLRequest del package flash.net
import flash.net.URLRequest
public class dividi extends MovieClip {
Possiamo ora impostare le variabili necessarie alla nostra classe, che saranno soltanto 3: pezzi_h
e pezzi_v
, che utilizzeremo per impostare il numero di parti (orizzontali e verticali) in cui dividere l'immagine, e sprite_tasselli
che sarà lo sprite dove mostreremo i pezzi dell'immagine creati dalla nostra classe. Ecco il codice da aggiungere al precedente:
// Impostiamo le variabili per il numero di tasselli
private var pezzi_h:uint
private var pezzi_v:uint
// Creiamo lo sprite dove mostreremo i tasselli
var sprite_tasselli:Sprite = new Sprite();
A questo punto possiamo passare alla dichiarazione delle funzioni della classe: partiamo dal caricamento dell'immagine.
Caricare l'immagine da dividere
Ovviamente la prima operazione che la classe dovrà eseguire sarà il caricamento dell'immagine: da notare che non mostreremo la foto sullo stage, ma ci servirà solamente come riferimento per la funzione che creerà i tasselli, questi ultimi saranno poi mostrati sullo stage.
Per caricare un'immagine o un filmato esterni in Actionscript 3 si utilizza l'oggetto Loader e il comando URLRequest
, che abbiamo infatti importato ad inizio classe. Andiamo allora a creare la funzione imposta_divisione
, che prevederà tre parametri: il nome dell'immagine da caricare, il numero di parti orizzontali e il numero di parti verticali da creare. Ecco il codice:
public function imposta_divisione(quale:String,po:uint,pv:uint):void{
// impostiamo il numero di pezzi orizzontali
pezzi_h = po
// impostiamo il numero di pezzi verticali
pezzi_v = pv
var carica_foto:Loader = new Loader()
var richiesta:URLRequest = new URLRequest(quale)
carica_foto.contentLoaderInfo.addEventListener(Event.COMPLETE,dividi_foto)
carica_foto.load(richiesta)
}
Possiamo notare i parametri quale
(di tipo stringa) e po
e pv
(di tipo uint), inoltre, poiché la funzione non restituirà alcun valore il tipo del valore di ritorno è impostato su void. All'interno della funzione vediamo l'associazione di po
e pi
rispettivamente a pezzi_h
e pezzi_v
, le due variabili dichiarate precedentemente; vengono quindi creati il loader carica_foto
e la URLRequest richiesta
, quindi associamo al completo caricamento della foto (tramite l'evento Event.COMPLETE
) la funzione dividi_foto
. Come ultima operazione carichiamo l'URLRequest richiesta all'interno di carica_foto
. In questo modo l'immagine verrà caricata all'interno del loader carica_foto
; come già detto non vogliamo mostrare la foto sullo stage, notiamo infatti l'assenza del comando addChild
.
Ora che abbiamo impostato il caricamento della foto possiamo passare alla funzione che si occuperà di ricavare i tasselli dall'immagine originale, ovvero dividi_foto
, che ricordiamo verrà avviata soltanto una volta completato il caricamento dell'immagine esterna nel filmato SWF.
Effettuare la divisione dell'immagine
La funzione di divisione si occuperà, per prima cosa, di creare una copia dell'immagine caricata e di stabilire le dimensioni dei tasselli da creare, valori che verranno determinati in base alle dimensioni della foto e al numero di tasselli dichiarati nella funzione imposta_divisione
. Una volta ricavati questi valori utilizzeremo due cicli for per "muoverci" all'interno dell'immagine e copiare di volta in volta il pezzo desiderato.
Vediamo per prima cosa il codice della funzione:
public function dividi_foto(chi:Event):void{
// creiamo una copia dell'immagine
var immagine:Bitmap = Bitmap(chi.target.loader.content);
// stabiliamo larghezza e altezza di ogni pezzo
var l_pezzo = Math.floor(immagine.width/pezzi_h)
var a_pezzo = Math.floor(immagine.height/pezzi_v)
// iniziamo il taglio dei pezzi
for(var r:uint=0;r<pezzi_h;r++){ // percorriamo tutte le righe
for(var c:uint=0;c<pezzi_v;c++){ // e tutte le colonne
// creiamo una bitmap con le dimensioni del pezzo del puzzle
var img_pezzo:Bitmap = new Bitmap(new BitmapData(l_pezzo,a_pezzo));
// copiamo i pixel dall'immagine originale al pezzo creato
img_pezzo.bitmapData.copyPixels(immagine.bitmapData,new Rectangle(r*l_pezzo,c*a_pezzo,l_pezzo,a_pezzo),new Point(0,0));
// creiamo un nuovo sprite
var sprite_pezzo:Sprite = new Sprite();
// inseriamo nello sprite la bitmap creata
sprite_pezzo.addChild(img_pezzo);
// inseriamo lo sprite "sprite_pezzo" dentro a "sprite_tasselli"
sprite_tasselli.addChild(sprite_pezzo)
}
}
// aggiungiamo sprite_tasselli allo stage
addChild(sprite_tasselli)
}
Il codice aiuterà a capire la spiegazione dei vari passaggi; abbiamo già parlato della creazione della copia dell'immagine (immagine) e dell'impostazione di larghezza e altezza dei tasselli (l_pezzo
e a_pezzo
); abbiamo a questo punto due cicli for annidati uno dentro l'altro: praticamente per ogni riga dell'immagine (il numero di righe da usare è stabilito dalla variabile pezzi_h) percorriamo verticalmente l'immagine per il numero di colonne (stabilito dalla variabile pezzi_v); per ogni passaggio di questo secondo ciclo avverrà la duplicazione di un tassello dell'immagine originale.
La duplicazione avviene creando un nuovo oggetto di tipo Bitmap (img_pezzo
) che avrà dimensioni stabilite dalle variabili l_pezzo
e a_pezzo
; inizialmente questo tassello sarà vuoto, ma subito dopo vi copieremo un pezzo dell'immagine originale grazie al comando copyPixels
. Questo comando, come dice già il suo nome, si occupa di copiare dei pixel in un oggetto bitmapData
estrapolandoli da un altro bitmapData: in questo caso copiamo all'interno di img_pezzo
i pixel dell'immagine originale (immagine.bitmapData
) compresi in un rettangolo stabilito dai valori di r
e c
(rispettivamente riga e colonna dell'immagine attualmente analizzate) e da l_pezzo
e a_pezzo
. L'ultimo parametro (new Point(0,0)
) serve per impostare il punto di destinazione del rettangolo copiato dall'immagine originale, che nel nostro caso sarà 0,0 dato che per ogni tassello abbiamo un nuovo sprite.
Il concetto può sembrare un po' complicato, ma osservando il comportamento del filmato sarà sicuramente più facile comprendere il procedimento.
Una volta che abbiamo la copia dentro ad img_pezzo
, semplicemente inseriamo questo oggetto (che ricordiamo è di tipo Bitmap) all'interno di uno sprite creato appositamente (sprite_pezzo
), che a sua volta verrà aggiunto a sprite_tasselli
. Una volta conclusi i cicli di duplicazione delle parti dell'immagine andiamo a mostrare sullo stage lo sprite contenente tutti i pezzi, grazie al comando addChild(sprite_tasselli)
.
Ecco il codice completo della classe:
package{
// importiamo il package flash.display
import flash.display.*;
// importiamo il package flash.geom
import flash.geom.*
// importiamo il package flash.events
import flash.events.*
// importiamo il comando URLRequest del package flash.net
import flash.net.URLRequest
public class dividi extends MovieClip {
// Impostiamo le variabili per il numero di tasselli
private var pezzi_h:uint
private var pezzi_v:uint
// Creiamo lo sprite dove mostreremo i tasselli
var sprite_tasselli:Sprite = new Sprite();
public function imposta_divisione(quale:String,po:uint,pv:uint):void{
// impostiamo il numero di pezzi orizzontali
pezzi_h = po
// impostiamo il numero di pezzi verticali
pezzi_v = pv
var carica_foto:Loader = new Loader()
var richiesta:URLRequest = new URLRequest(quale)
carica_foto.contentLoaderInfo.addEventListener(Event.COMPLETE,dividi_foto)
carica_foto.load(richiesta)
}
public function dividi_foto(chi:Event):void{
// creiamo una copia dell'immagine
var immagine:Bitmap = Bitmap(chi.target.loader.content);
// stabiliamo larghezza e altezza di ogni pezzo
var l_pezzo = Math.floor(immagine.width/pezzi_h)
var a_pezzo = Math.floor(immagine.height/pezzi_v)
// tagliamo i vari pezzi
for(var r:uint=0;r<pezzi_h;r++){ // percorriamo tutte le righe
for(var c:uint=0;c<pezzi_v;c++){ // e tutte le colonne
// creiamo una bitmap con le dimensioni del pezzo del puzzle
var img_pezzo:Bitmap = new Bitmap(new BitmapData(l_pezzo,a_pezzo));
// copiamo i pixel dall'immagine originale al pezzo creato
img_pezzo.bitmapData.copyPixels(immagine.bitmapData,new Rectangle(r*l_pezzo,c*a_pezzo,l_pezzo,a_pezzo),new Point(0,0));
// creiamo un nuovo sprite
var sprite_pezzo:Sprite = new Sprite();
// inseriamo nello sprite la bitmap creata
sprite_pezzo.addChild(img_pezzo);
// inseriamo lo sprite "sprite_pezzo" dentro a "sprite_tasselli"
sprite_tasselli.addChild(sprite_pezzo)
}
}
// aggiungiamo sprite_tasselli allo stage
addChild(sprite_tasselli)
}
}
}
Test del filmato
Possiamo ora creare un nuovo file Actionscript 3, dove andremo ad impostare dividi
come Document Class.
Salviamo il FLA nella stessa cartella di dividi.as e inseriamo questo codice sul primo fotogramma:
imposta_divisione("Tramonto.jpg",5,5)
Testando il filmato noteremo come i tasselli vengano posizionati tutti uno sopra l'altro
A questo punto abbiamo varie scelte su come modificare il codice della classe e tutto dipende dalle nostre esigenze: ad esempio, potremmo optare per un posizionamento casuale, modificando in questo modo la funzione dividi_foto
:
public function dividi_foto(chi:Event):void{
// creiamo una copia dell'immagine
var immagine:Bitmap = Bitmap(chi.target.loader.content);
// stabiliamo larghezza e altezza di ogni pezzo
var l_pezzo = Math.floor(immagine.width/pezzi_h)
var a_pezzo = Math.floor(immagine.height/pezzi_v)
// tagliamo i vari pezzi
for(var r:uint=0;r<pezzi_h;r++){ // percorriamo tutte le righe
for(var c:uint=0;c<pezzi_v;c++){ // e tutte le colonne
// creiamo una bitmap con le dimensioni del pezzo del puzzle
var img_pezzo:Bitmap = new Bitmap(new BitmapData(l_pezzo,a_pezzo));
// copiamo i pixel dall'immagine originale al pezzo creato
img_pezzo.bitmapData.copyPixels(immagine.bitmapData,new Rectangle(r*l_pezzo,c*a_pezzo,l_pezzo,a_pezzo),new Point(0,0));
// creiamo un nuovo sprite
var sprite_pezzo:Sprite = new Sprite();
sprite_pezzo.x = Math.random()*500
sprite_pezzo.y = Math.random()*400
// inseriamo nello sprite la bitmap creata
sprite_pezzo.addChild(img_pezzo);
// inseriamo lo sprite "sprite_pezzo" dentro a "sprite_tasselli"
sprite_tasselli.addChild(sprite_pezzo)
}
}
// aggiungiamo sprite_tasselli allo stage
addChild(sprite_tasselli)
}
In alternativa potremmo sfruttare gli eventi per rendere trascinabili i vari tasselli, o altro ancora: a voi la possibilità di sperimentare le numerose possibilità di utilizzo di questa immagine divisa.