Album Fotografico 3D in Actionscript 3 - Tutorial

Autorer: admin
24 Settembre 2008

Ciao a tutti,
da oggi voglio cominciare a proporvi una serie di tutorials. Inizialmente prenderò ispirazione da risorse che sono riuscito a trovare su Internet, ma ben presto spero di poter contribuire personalmente alla creazione di qualcosa totalmente nuovo.
In questo tutorial verrà mostrato come creare un album fotografico in 3d in Flash per presentare le proprie foto o illustrazioni (le mie foto sono del paese in cui vivo: Castellammare del Golfo).
Il risultato che si vuole raggiungere è questo. Spero :-) che vi piaccia.

Screeshot del risultato finale.

Screenshot del risultato finale.

Allora cominciamo.
Innanzitutto verranno utilizzate 2 particolari librerie in AS3: FIVe3D e la TweenLite.
Le librerie altro non sono che porzioni di codice già scritto che possono essere sfruttate per specifiche tipologie di progetto (diciamo come fossero dei componenti pre-fabbricati di una casa in costruzione).
La FIVe3d è una leggera libreria per il 3d e la TweenLite per l’animazione in Flash.

Carichiamo le foto.

Ma cominciamo ora il lavoro.
Aprite Adobe Flash CS3 (è fondamentale avere questa versione del programma perché dobbiamo scrivere il codice in AS3), cliccate in: File - Nuovo – File Flash (AS3). In basso, nelle proprietà dello stage, indicate come “classe documento” = “sorgenti/principale” (senza l’estensione .as) e salviamo col nome di “album.fla” il tutto in una precisa cartella.
La classe documento rappresenta, nei progetti in AS3, la collocazione di un file actionscript esterno di base (quindi .as) del filmato che si svilupperà. In questo modo è come se il codice inserito nel file principale.as fosse inserito nel primo fotogramma del filmato.
L’uniche altre cose da fare sul file “album.fla” sono l’indicazione della frequenza fotogrammi a 30 f/s e il ridimensionamento dello stage a 800 x 600 px.

Andiamo ora a lavorare sul file “principale.as” (che deve essere contenuto nella cartella “sorgenti”), qui svilupperemo tutto quello che ci serve. Prima di tutto creiamo il file su Flash cliccando su: File – Nuovo – File actionscript. Invece di usare Flash potrete utilizzare il software “FlashDevelop” per programmare in AS3, ha più funzioni del Flash ed è compatibilissimo con questo, comunque è lo stesso.
Importiamo ora le seguenti dichiarazioni, al fine di caricare le classi e le proprietà di particolari package che ci servono per sviluppare il filmato:

package  {

import flash.display.StageScaleMode;
import flash.display.StageAlign;
import flash.display.Sprite;

//carica la classe Bitmap, la quale rappresenta gli oggetti
//di visualizzazione che definiscono le immagini bitmap
import flash.display.Bitmap;

//carica la classe BitmapData, che consente di eseguire operazioni
//con i dati (pixel) di un oggetto Bitmap
import flash.display.BitmapData;

//carica la classe Loader, che consente di caricare
//file SWF o file di immagine (JPG, PNG o GIF)
import flash.display.Loader;

//carica la classe Event, che è utilizzata come classe
//base per la creazione e gestione di alcuni eventi
import flash.events.Event;

//carica la classe URLRequest, che permette di definire quale
//file esterno vogliamo caricare (lavora assieme al Loader)
import flash.net.URLRequest;

//le seguenti classi agiscono sul campo di testo, sul formato
//di testo e sull’allineamento e dimensionamento automatico
import flash.text.TextField;
import flash.text.TextFormat;
import flash.text.TextFieldAutoSize;

ora scriviamo la classe principale, che deve essere nominata come il file .as (quindi “principale”) ed effettuiamo un’estensione della classe “sprite”

public class principale extends Sprite {

//indichiamo in numero di foto
private var numero_foto:int = 9;

//indichiamo la cartella dove si trovano le nostre foto
private var percorso_foto:String = “foto/foto0″;

//definiamo il tipo di estensione che devono avere le
//nostre foto (altre tipologie di foto non verrano lette
private var estensione_foto:String = “.jpg”;
private var indice_di_caricamento:int = 1;
private var informazioni_di_caricamento:TextField;
private var array_foto:Array;
private var loader_foto:Loader;

Le prime 3 variabili potrebbero essere definite da un file XML collegato al filmato, in questo caso sviluppiamo il progetto direttamente e totalmente in AS3 e poi, in futuro, implementeremo il progetto anche con la lettura del file XML.

public function principale() {
informazioni_di_caricamento = new TextField();

//definiamo la formattazione testuale
informazioni_di_caricamento.defaultTextFormat = new TextFormat(”Verdana”, 10, 0xffffff);
informazioni_di_caricamento.autoSize = TextFieldAutoSize.LEFT;
informazioni_di_caricamento.text = “Caricamento foto ” + indice_di_caricamento + ” su ” + numero_foto;
informazioni_di_caricamento.x = stage.stageWidth/2 - informazioni_di_caricamento.textWidth/2;
informazioni_di_caricamento.y = stage.stageHeight/2 - informazioni_di_caricamento.textHeight/2;

//aggiungiamo il campo di testo sullo stage (dopo averlo
//creato, dobbiamo specificare a Flash di inserirlo sullo stage)
addChild(informazioni_di_caricamento);

//inizializziamo l’array che poi verrà riempito con gli
//elementi che indicano le foto.
array_foto = new Array();

//attiviamo ora la seguente funzione:
carica_foto();}

Abbiamo così creato il campo di testo che ci indica il processo di caricamento delle foto.

private function carica_foto() {
loader_foto = new Loader();

//per ogni caricamento aggiungo un listener per vedere quando il
//caricamento si conclude e posso avviare la funzione successiva
loader_foto.contentLoaderInfo.addEventListener(Event.COMPLETE, indica_caricamento);

//caricamento effettivo della foto, da notare la modalità di
//costruzione del percorso da dove caricare la foto realizzato
//con le variabili definite in precedenza
loader_foto.load(new URLRequest(percorso_foto + indice_di_caricamento + estensione_foto));

//s’incrementa il numero della foto al fine di caricarle tutte
indice_di_caricamento++;
}

private function indica_caricamento(e:Event):void {

//ogni volta che Flash carica immagini esterne (jpg, png o gif)
//queste vengono poi definiti come DisplayObject “Bitmap”, questa
//conversione è fatta automaticamente e facilita l’inserimento
//dell’immagine direttamente sullo stage. Ma considerando che
//il nostro obiettivo è mostrare le foto in un ambiente 3D, allora
//NON ci servono come “Bitmap” ma invece come “Bitmap Data”,
//quest’ultima classe infatti ci permette di operare sui pixel
//dell’immagine, ossia permette di modificarla.
//”e.target.content” indica che la tipologia dell’oggetto
//target del listener è classe “Bitmap”, aggiungendo il suffisso
//”.bitmapData” si trasforma questo in una classe “Bitmap Data”
var immagine:BitmapData = (e.target.content as Bitmap).bitmapData;

//aggiungi la foto caricata all’array
array_foto.push(immagine);

//se il numero della foto che abbiamo caricato è inferiore al numero
//totale d’immagini, vuol dire che dobbiamo indicare lo stato di
//caricamento nel campo di testo prima realizzato e riavviare la
//funzione di caricamento delle foto, per passare alla foto successiva
if (indice_di_caricamento <= numero_foto) {
informazioni_di_caricamento.text = “Caricamento foto ” + indice_di_caricamento + ” su ” + numero_foto;
carica_foto();
}
//altrimenti, se il numero della foto caricata è maggiore del num
//di foto totali, rimuovere il campo di testo e avviare stavolta
//soltanto la funzione di costruzione dell’album.
else {
removeChild(informazioni_di_caricamento);
costruzione_album();
}
}

private function costruzione_album():void {
trace(”Foto caricate!”);
}

A questo punto, provando il filmato, dovrebbe caricare le foto (non visualizzandole), indicare il caricamento e il messaggio “foto caricate!” in Flash, nient’altro.
Se è così, allora siamo a cavallo ;-)

Creiamo il mondo 3D

Passiamo alla programmazione 3D, qui si useranno quindi soprattutto le classi predefinite nella libreria FIVe3D e non quelle standard di Flash, cercherò di spiegarvi al meglio cosa stiamo facendo.

Innanzitutto aggiungiamo queste dichiarazione nella zona “import” iniziale (ricordiamo di aggiungere anche la cartella “five3D” nella stessa collocazione del file “principale.as”):

import five3D.display.Scene3D;
import five3D.display.Bitmap3D;
import five3D.display.Sprite3D;
import flash.geom.ColorTransform;

ed alcune variabili accanto a quelle già inserite:

private var scene:Scene3D;
private var album:Sprite3D;

//distanza fra le foto
private var padding:Number = 60;

//distanza dell’album 3D dallo schermo o profondità.
private var profondita_z:Number = 2400;

//questi servono per l’effetto di rollover, quando il muose passa
//sopra l’immagine questa si scurisce un po’, mentre l’effetto
//successivo serve per ritornare alla normale luminosità.
private var colore_scuro:ColorTransform = new ColorTransform(.8, .8, .8, 1, 0, 0, 0, 0);
private var colore_chiaro:ColorTransform = new ColorTransform(1, 1, 1, 1, 0, 0, 0, 0);

Ogni elemento di FIVe3D deve essere inserito in una SCENE3D per funzionare. Il nostro album diventerà invece uno SPRITE3D all’interno di questa “scene3d”, lo “sprite3d” è una estensione dello “sprite” standard di AS3, quindi molte operazioni possibili sullo “sprite” sono realizzabili anche sullo “sprite3d” (come la funzione “Transform.ColorTransform”) semplificando il codice.

Ritorniamo ora però alla funzione di costruzione dell’Album e cancelliamo l’operatore “trace”, qui andiamo a costruire la visualizzazione 3D. Ricorda però di ritornare nella funzione di costruzione dell’album.

//dichiariamo la scena 3d
scene = new Scene3D();

//posizioniamola al centro dello stage, il “Math.round”
//serve per arrotondare il risultato.
scene.x = Math.round(stage.stageWidth/2);
scene.y = Math.round(stage.stageHeight / 2);

//aggiungi il tutto allo stage
addChild(scene);

//creiamo ora l’album 3D
album = new Sprite3D();

//realizziamo un ciclo “for” e per ogni elemento interno
//all’array delle foto (quindi se sono 9, per 9 volte)
// avviamo le operazioni seguenti
for (var i:int = 0;  i < array_foto.length; i++) {

//trasformiamo ogni “BitmapData” (ossia ogni foto) in
//”bitmap3d” che permette modifiche 3D
var bitmap3d:Bitmap3D = new Bitmap3D(array_foto[i] as BitmapData);
var immagine3d:Sprite3D = new Sprite3D();

//posizioniamo la “x” e la “y” iniziali della foto
//rispettivamente a metà larghezza ed altezza.
bitmap3d.x = bitmap3d.bitmapData.width / -2;
bitmap3d.y = bitmap3d.bitmapData.height / -2;

//aggiungiamo ogni foto (ognuna come oggetto “bitmap3d”)
//all’interno di un “sprite3d” che le contiene, questo
//perché l’oggetto “bitmap3d” non permette le operazioni,
//che ci servono, permesse invece dall’oggetto “sprite3d”
immagine3d.addChild(bitmap3d);

//”Math.floor” arrotonda il risultato come numero intero
var riga:Number = Math.floor(i / 3) - 1;

//”%” fornisce il RESTO di una divisione
var col:Number = i % 3 - 1;

//aggiunge i padding + la larghezza o altezza
var pw:Number = bitmap3d.bitmapData.width + padding;
var ph:Number = bitmap3d.bitmapData.height + padding;
immagine3d.x = riga * pw;
immagine3d.y = col * ph;

//effettua la trasformazione del colore delle foto,
//rendendole più scure.
immagine3d.transform.colorTransform = colore_scuro;
immagine3d.buttonMode = true;

//aggiunge ogni foto all’album
album.addChild(immagine3d);
}

//indica la profondità (nella coordinata Z) dell’album
album.z = profondita_z;

//aggiunge l’album alla scena 3d
scene.addChild(album);

Aggiungiamo l’interattività

Come in precedenza dobbiamo aggiungere queste dichiarazioni nella zona “import” (ricordiamo di aggiungere anche la cartella “five3D” nella stessa collocazione del file “principale.as”):

import gs.TweenLite;
import fl.motion.easing.Sine;
import flash.events.MouseEvent;

e le seguenti variabili nella zona apposita:

//serve per indicare se stiamo zoomando la foto o no
private var modalita_zoom:Boolean = false;

//in caso di zoom il seguente “sprite3d” gestisce la foto
private var foto_zoomata:Sprite3D;

Ritorniamo alla funzione di costruzione dell’album e continuamo da dove abbiamo lasciato.

//listener per catturare il momento di rollover.
//in caso di rollover si attiva.
album.addEventListener(MouseEvent.ROLL_OVER, onOver, true);
album.addEventListener(MouseEvent.ROLL_OUT, onOut, true);

//listener in caso di ridimensionamento della pagina web
stage.addEventListener(Event.RESIZE, onResize);

//listener per dare l’effetto 3D al movimento del mouse
stage.addEventListener(MouseEvent.MOUSE_MOVE, muovi_album);

I 2 listener sono un po’ particolari, innanzitutto un occhio attento si accorge che il listener è inserito nell’oggetto “album” che contiene tutte le foto e che quindi, in caso di roll over, è questo l’oggetto target del listener, e non una sola foto. Come è possibile che però, andando col mouse sopra una foto, si modifica la luminosità di SOLO quella foto e non di tutto l’album?
Cerchiamo di capirlo.
Nel listener vediamo, in conclusione, la presenza (alquanto insolita) di un parametro booleano (true in questo caso), esso rappresenta un argomento denominato “useCapture” un po’ difficile da spiegare (riguarda i passaggi di propagazione di un evento, cose da puri programmatori), ma in pratica serve per far attivare il listener precisamente sull’oggetto interno che in questo caso viene colpito dal passaggio del mouse. In poche parole è come se il listener fosse su ogni foto e non su tutto l’album. In questo modo però si scrive meno codice (certo… se uno lo sa! :-)

private function onOver(evento_mouse:MouseEvent):void {
//la foto viene resa + chiara (con la trasformazione del colore),
//ma prima si controlla se non è zoomata (l’effetto di rollover
//è stato impostato che funzioni solo se la foto non è zoomata)
if (evento_mouse.target is Sprite3D && !modalita_zoom) {
(evento_mouse.target as Sprite3D).transform.colorTransform = colore_chiaro;
}
}

private function onOut(evento_mouse:MouseEvent):void {
//riporta la foto un pò + scura, in caso di rollout
if (evento_mouse.target is Sprite3D && !modalita_zoom) {
(evento_mouse.target as Sprite3D).transform.colorTransform = colore_scuro;
}
}

//in caso di ridimensionamento della pagina del browser
//automaticamente l’album si posiziona al centro.
private function onResize(e:Event):void {
scene.x = Math.round(stage.stageWidth/2);
scene.y = Math.round(stage.stageHeight / 2);
}

//funzione per l’effetto 3D
private function muovi_album(evento_mouse:MouseEvent):void {

//nel caso in cui è attivato lo zoom della foto, si attiva il
//”return”, ossia viene bloccata qui la funziona e non si
//continua, questo perché l’effetto 3D deve essere attivo
//solo quando la foto NON è zoomata
if (modalita_zoom) return;

var mouseXPos:Number = (evento_mouse.stageX - stage.stageWidth/2) / (stage.stageWidth / 2);
var mouseYPos:Number = (evento_mouse.stageY - stage.stageHeight/2) / (stage.stageHeight / 2);

Con “evento_mouse.stageX” si indica la coordinata orizzontale in cui si è verificato l’evento (in questo caso il movimento del mouse), quindi si calcola se si trovava a sinistra dello schermo o a destra, rispetto il centro. Infatti il calcolo matematico comporta una serie di risultati che vanno dal -1 (tutto a sinistra) all’1 (tutto a destra), con lo 0 che indica il centro preciso.
La stessa procedura avviene per le Y in ambito verticale.

//riprende il codice precedente e si crea un “object”
//per assemblare all’interno tutte le proprietà di
//movimento 3D
var oggetto_3d:Object = new Object();

//questi movimenti avvengono nello spazio 3D,
//x capirne le caratteristiche (difficili da
//descrivere verbalmente) provare ad aumentare
//nei valori e vedrete le differenze nel movimento.
oggetto_3d.rotationY = 45 * mouseXPos;
oggetto_3d.rotationX = -15 * mouseYPos;
oggetto_3d.x = 400 * mouseXPos;
oggetto_3d.y = 300 * mouseYPos;

//tipo di movimento, in questo caso rallenta alla fine
oggetto_3d.ease = Sine.easeOut;

//l’effetto di movimento viene quindi applicato all’
//album, avrà una durata di 0.3 secondi e le caratteristiche
//di movimento sono inserite nell’oggetto “oggetto_3d”
TweenLite.to(album, .3, oggetto_3d);
}

Giunti a questo punto possiamo testare quanto finora scritto.
Oh… finalmente qualche risultato interessante, ci sono le foto, il movimento 3D e l’effetto rollover, manca solo lo zoom delle foto e abbiamo finito.

Innanzitutto inseriamo questo listener là dove troviamo gli altri (sempre all’interno della funzione di costruzione dell’album).

stage.addEventListener(MouseEvent.CLICK, onClick);

Dopodiché ritorniamo al punto precedente e continuamo a scrivere la funzione del Click (no problem, sono le ultime cose):

private function onClick(evento_mouse:MouseEvent):void {
var oggetto_3d:Object;

//in questo caso si verifica se NON siamo già nella
//condizione di zoom della foto.
if (evento_mouse.target is Sprite3D && !modalita_zoom) {

//creiamo sempre un nuovo “object” per inserire le nuove
//caratteristiche di movimento, qui vengono azzerate le
//proprietà tridimensionali.
oggetto_3d = new Object();
oggetto_3d.z = 0;
oggetto_3d.rotationX = 0;
oggetto_3d.rotationY = 0;
oggetto_3d.x = 0 - evento_mouse.target.x;
oggetto_3d.y = 0 - evento_mouse.target.y;

//definiamo il nuovo tipo di movimento da realizzare e
//il nuovo tempo di percorrenza.
oggetto_3d.ease = Sine.easeInOut;
TweenLite.to(album, .6, oggetto_3d);

//specifichiamo che il target del Click viene inserito
//come “sprite3d”
foto_zoomata = evento_mouse.target as Sprite3D;

//avveriamo la condizione di ZOOM, in modo da far
//capire a Flash che stiamo zoomando la foto
modalita_zoom = true;
}

//se la condizione di ZOOM è vera
else if (modalita_zoom) {

//rimettiamo la foto un po’ + scura
foto_zoomata.transform.colorTransform = colore_scuro;

//e riposizioniamo l’album come l’inizio
oggetto_3d = new Object();
oggetto_3d.z = profondita_z;
oggetto_3d.x = 0;
oggetto_3d.y = 0;
oggetto_3d.ease = Sine.easeOut;

//appena il movimento è completato si avvia
//la seguente funzione
oggetto_3d.onComplete = ritorno_normale;
TweenLite.to(album, .3, oggetto_3d);
}
}

//ossia che la modalità di ZOOM è ora falsa
private function ritorno_normale():void {
modalita_zoom = false;
}
}
}

Testate ora il vostro filmato, se è tutto OK, dovreste visualizzare la vostra bella galleria in 3D realizzata direttamente da voi.
Anche se il codice potrebbe sembrare abbastanza lungo e complesso, in verità si tratta di una programmazione semplice.
Certo stiamo parlando sempre di programmazione in AS3 (non ancora maneggiato da tutti gli esperti in Flash, soprattutto i designers) e in 3D (una novità dell’ultimo anno, che sta veramente prendendo campo e che stimola a sognare ad occhi aperti :-o   ) , la difficoltà consiste nell’apprendere bene ogni passaggio, ma ciò è necessario per diventare dei buoni programmatori.

In futuro cercheremo di implementare il progetto con altri spunti (per esempio: lettura da un file XML, oppure visualizzazione di filmati in .swf invece delle foto, ecc).
Se volete collaborare con me ;-) ne sarei felice, anche perché ancora mi reputo un apprendista, non un esperto in programmazione, quindi sono sempre in ascolto.
BYE

File sorgenti del progetto

2 risposte to “Album Fotografico 3D in Actionscript 3 - Tutorial”

  1. dosa85 Says:

    Complimenti::::

    Pero ho un problema, mi da questo errore alla visualizzazione:
    rror #2044: IOErrorEvent non gestito:. text=Error #2035: Impossibile trovare l’URL.

  2. mirjana Says:

    grazie per la spiegazione semplice e dettagliata

Leave a Reply