Cubo 3D come Menù Interattivo con Papervision

Autorer: admin
2 Novembre 2008

E rieccomi qua :-) sono mancato un pochino di giorni (ho finalmente preso la specializzazione all’uni), ma spero non siete scappati… ;-) e che torniate sempre a leggermi.

Allora, continuiamo con qualche bel tutorial su papervision 3D e actionscript 3: stavolta cerchiamo di realizzare questo:

Non nego che la realizzazione di tale cubo è un procedimento un pò complesso, sicuramente non intuitivo ed immediato. Questo perchè la realizzazione del cubo e delle sue 6 facce non segue i metodi illustrati con le altre figure geometriche semplici (le primitive), comunque cercherò di essere più chiaro possibile.

Ad ogni modo, sono riechieste la conoscenza di actionscript 3 (almeno di base) e consiglio di leggersi i precendenti miei tutorial prima di affrontare questo.

Ma è soprattutto l’implementazione dell’interattività delle facce (ossia la capacità d’intercettare coi listener ed avviare azioni diverse a seconda della faccia cliccata) l’aspetto principale del progetto, che trasforma un semplice cubo tridimensionale in un fantastico menù.

Come al solito ;-) ecco a voi il codice… pappatevelo.

package {

//autore: www.enricoviola.it/blog
//——————————-
//Guida personale a Papervision3D

import flash.display.DisplayObject;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.display.Sprite;
import flash.net.URLRequest;
import flash.net.navigateToURL;

import org.papervision3d.core.proto.MaterialObject3D;
import org.papervision3d.materials.BitmapFileMaterial;
import org.papervision3d.materials.utils.MaterialsList;
import org.papervision3d.core.proto.MaterialObject3D;
import org.papervision3d.objects.primitives.Cube;
import org.papervision3d.view.BasicView;
import org.papervision3d.core.proto.CameraObject3D;
import org.papervision3d.objects.DisplayObject3D;
import org.papervision3d.events.InteractiveScene3DEvent;

//da notare l’estensione della classe come BasicView, in questo modo
//ne eredita tutte le proprietà e i metodi, che possono immediatamente
//essere utilizzati nella programmazione.

public class cuboInterattivo extends BasicView {

private var cubo:Cube;

//definizione di variabili utili per stoppare il cubo e posizionarsi sulla faccia cliccata
private var targetrotationX:Number = 0;
private var targetrotationY:Number = 0;
private var targetrotationZ:Number = 0;

//definizione dei materiali che compongono le facce del cubo
private var fronteMaterial:BitmapFileMaterial = new BitmapFileMaterial(”http://www.enricoviola.it/blog/risorse_varie/articoliVari/immagineCubo1.jpg”);
private var dietroMaterial:BitmapFileMaterial = new BitmapFileMaterial(”http://www.enricoviola.it/blog/risorse_varie/articoliVari/immagineCubo1.jpg”);
private var sinistraMaterial:BitmapFileMaterial = new BitmapFileMaterial(”http://www.enricoviola.it/blog/risorse_varie/articoliVari/immagineCubo1.jpg”);
private var destraMaterial:BitmapFileMaterial = new BitmapFileMaterial(”http://www.enricoviola.it/blog/risorse_varie/articoliVari/immagineCubo1.jpg”);
private var sopraMaterial:BitmapFileMaterial = new BitmapFileMaterial(”http://www.enricoviola.it/blog/risorse_varie/articoliVari/immagineCubo1.jpg”);
private var sottoMaterial:BitmapFileMaterial = new BitmapFileMaterial(”http://www.enricoviola.it/blog/risorse_varie/articoliVari/immagineCubo1.jpg”);

//definizione delle variabili che poi c’interessano per stoppare e riavviare la rotazione del cubo

private var clickSuFacceCubo:Boolean = false;
private var cuboCliccato:Boolean = false;

public function cuboInterattivo() {
//ricordiamo che l’istruzione super() in AS3 richiama la versione superclasse
//della funzione di costruzione. In questo caso è BasicView (l’estensione)
//e ne eredita le proprietà e i metodi, velocizzando la programmazione.
//BasicView(viewportWidth:Num = 640, viewportHeight:Num = 480,
//scaleToStage:Boolean = true, interactive:Boolean = false,
//cameraType:String = “Target”).
//Importante è definire TRUE il paramentro “interactive”.

super(0, 0, true, true);

stage.align = StageAlign.TOP_LEFT;

init3D();

createScene();

startRendering();
}

private function init3D():void {

camera.x = 0;
camera.y = 0;
camera.z = -500;
camera.zoom = 120;
}

private function createScene():void {

//impostiamo i vari materiali come interattivi, ossia indichiamo
//che essi devo rispondere ai listener impostati, se non indichiamo
//l’interattività come TRUE al click del mouse non accadrebbe niente.
//Inoltre impostiamo anche dei nominativi ai materiali per meglio
//riconoscerli.

fronteMaterial.interactive = true;
fronteMaterial.name = “frontale”;
dietroMaterial.interactive = true;
dietroMaterial.name = “dietro”;
sinistraMaterial.interactive = true;
sinistraMaterial.name = “sinistra”;
destraMaterial.interactive = true;
destraMaterial.name = “destra”;
sopraMaterial.interactive = true;
sopraMaterial.name = “sopra”;
sottoMaterial.interactive = true;
sottoMaterial.name = “sotto”;

//la costruzione del cubo si differenzia rispetto alle altre
//figure geometriche semplici, perchè per impostare i materiali
//da usare nelle superfici delle 6 facce bisogna usare
//il comando MaterialList, in questo caso definiamo un materiale
//differente per faccia (l’indicazione di front:, back:, left:,
//ecc. è obbligatoria per definire materiali diversi per faccia).

cubo = new Cube(new MaterialsList( {
front: fronteMaterial,
back: dietroMaterial,
left: sinistraMaterial,
right: destraMaterial,
top: sopraMaterial,
bottom: sottoMaterial
} ), 100, 100, 100, 3, 3, 3);
cubo.z = 0;
cubo.addEventListener(InteractiveScene3DEvent.OBJECT_PRESS, onPresss);

scene.addChild(cubo);
}

private function onPresss(e:InteractiveScene3DEvent):void {

if (!cuboCliccato) {
//realizziamo un ciclo e scopriamo su quale faccia
//è stato effettuato il Click col comando:
//”e.face3d.material.name”, “e” indica l’oggetto
//per il quale si è avviato il listener OBJECT_PRESS,
//partendo da questo oggetto “e” leggiamo il nome
//(precedentemente impostato)
//del materiale che è stato colpito dal CLICK

switch(e.face3d.material.name) {

//caso 1: se il nome del materiale colpito è
//”frontale” allora impostiamo nuovi parametri
//di rotazione, rendiamo TRUE la variabile
//”clickSuFacceCubo” ed apriamo la nuova pagina web

case “frontale”:
targetrotationX = 0;
targetrotationY = 180;
targetrotationZ = 0;
clickSuFacceCubo = true;
trace(”premutoFrontale”);
//per aprire una nuova pagina web, impostiamo
//l’indirizzo come URLRequest e successivamente
//avviamo il collegamento col comando
//”navigateToURL”, impostando l’apertura della
//pagina su una nuova finestra del browser.

var indirizzo0:URLRequest = new URLRequest(”http://www.enricoviola.it/blog”);
navigateToURL(indirizzo0, “_blank”);
break;


case “dietro”:
targetrotationX = 0;
targetrotationY = 0;
targetrotationZ = 0;
clickSuFacceCubo = true;
trace(”premutoDietro”);
var indirizzo1:URLRequest = new URLRequest(”http://www.enricoviola.it/blog”);
navigateToURL(indirizzo1, “_blank”);
break;


case “sinistra”:
targetrotationX = 0;
targetrotationY = -90;
targetrotationZ = 0;
clickSuFacceCubo = true;
trace(”premutoSinistra”);
var indirizzo2:URLRequest = new URLRequest(”http://www.enricoviola.it/blog”);
navigateToURL(indirizzo2, “_blank”);
break;


case “destra”:
targetrotationX = 0;
targetrotationY = 90;
targetrotationZ = 0;
clickSuFacceCubo = true;
trace(”premutoDestra”);
var indirizzo3:URLRequest = new URLRequest(”http://www.enricoviola.it/blog”);
navigateToURL(indirizzo3, “_blank”);
break;


case “sopra”:
targetrotationX = 90;
targetrotationY = 0;
targetrotationZ = 180;
clickSuFacceCubo = true;
trace(”premutoSopra”);
var indirizzo4:URLRequest = new URLRequest(”http://www.enricoviola.it/blog”);
navigateToURL(indirizzo4, “_blank”);
break;


case “sotto”:
targetrotationX = -90;
targetrotationY = 0;
targetrotationZ = 0;
clickSuFacceCubo = true;
trace(”premutoSotto”);
var indirizzo5:URLRequest = new URLRequest(”http://www.enricoviola.it/blog”);
navigateToURL(indirizzo5, “_blank”);
break;
}
}
//facciamo in modo che al successivo Click sul cubo
//già cliccato mi falsifichi la condizione di Click
//sulla figura e riavvii quindi la rotazione automatica

if (cuboCliccato && clickSuFacceCubo) {
clickSuFacceCubo = false;
cuboCliccato = false;
}
}

//la funzione “onRenderTick” altro non fà che simulare l’ENTER_FRAME, per
//funzionare è necessario però attivare la funzione “startRendering” che
//ha proprio il compito di attivare un listener ogni frame per la funzione
//”onRenderTick”. In questo caso faremo delle sostituzioni al metodo, al
//fine di realizzare l’animazione desiderata.

override protected function onRenderTick(event:Event=null):void {

if(clickSuFacceCubo) {
//Realizziamo il movimento di rotazione del cubo al Click,
//in modo da selezionare la faccia cliccata, basandoci sui
//valori delle variabili “targetrotation” per i vari assi.

if (cubo.rotationX <targetrotationX) {
cubo.rotationX += Math.sqrt(targetrotationX-cubo.rotationX);
cubo.rotationX = Math.round(cubo.rotationX);
}else if (cubo.rotationX> targetrotationX) {
cubo.rotationX -= Math.sqrt(cubo.rotationX-targetrotationX);
cubo.rotationX = Math.round(cubo.rotationX);
}

if (cubo.rotationY <targetrotationY) {
cubo.rotationY += Math.sqrt(targetrotationY-cubo.rotationY);
cubo.rotationY = Math.round(cubo.rotationY);
}else if (cubo.rotationY> targetrotationY) {
cubo.rotationY -= Math.sqrt(cubo.rotationY-targetrotationY);
cubo.rotationY = Math.round(cubo.rotationY);
}

if (cubo.rotationZ <targetrotationZ) {
cubo.rotationZ += Math.sqrt(targetrotationZ-cubo.rotationZ);
cubo.rotationZ = Math.round(cubo.rotationZ);
}else if (cubo.rotationZ> targetrotationZ) {
cubo.rotationZ -= Math.sqrt(cubo.rotationZ-targetrotationZ);
cubo.rotationZ = Math.round(cubo.rotationZ);
}
cuboCliccato = true;
}
if(!cuboCliccato) {
//in caso di non Click sul cubo avviamo una rotazione
//continua per creare un movimento.

cubo.rotationX += 2;
cubo.rotationY += 2;
//Se la rotazione nei 2 assi supera 360 gradi, allora
//riazzeriamo il valore.

if (cubo.rotationX>= 360) cubo.rotationX = 0;
if (cubo.rotationY >= 360) cubo.rotationY = 0;
}

//per attivare le modifiche bisogna richiamare la funzione “OnRenderTick”
//partendo dalla funzione “super” (ossia “BasicView”)

super.onRenderTick(event);
}
}
}

Scarica i file di progetto (PS in questo file non sono inclusi i file sorgenti di papervision 3D 2.0, ma potete utilizzare gli stessi che ho distribuito con i tutorial precedenti).

P.S. Alternativa 2 (su consiglio di Marco). POTETE FARE TUTTI I CLICK CHE VOLETE, ho tolto i link! E’ + divertente! ;-)

12 risposte to “Cubo 3D come Menù Interattivo con Papervision”

  1. Marco Says:

    Ciao enrico,
    ottimo blog.
    mi stavo studiacchiando il codice, ma mi chiedevo come fare per cambiare la dimensione del cubo. è un po che ci sbatto ma nulla.
    sarebbe anche carino secondo me se il cubo avesse il movimento legato al movimento del mouse.
    puoi aiutarmi?

  2. admin Says:

    Ciao Marco,
    Certo che posso aiutarti :-) Anzi spero ci siano sempre più commenti, perchè io sono qui pronto a rispondere (quando posso ;-) ).
    Allora… per modificare le dimensione del cubo devi intervenire al rigo 109 del file “.as”, cioè quando creiamo il “new Cube”, io ho inserito dimensioni: 100, 100 e 100. Basta modificarle per rimpicciolire o aumentare il cubo, puoi anche trasformarlo in un parallelepipedo.

    Beh, cmq hai ragione: + più carino legando la rotazione del mouse con il movimento del mouse. E poi è semplicissimo farlo, basta cambiare le righe 241 e 242 (0ssia:
    “cubo.rotationX += 2;
    cubo.rotationY += 2;”
    con
    “cubo.rotationY += (mouseX - stage.width/2) / 30;
    cubo.rotationX += (mouseY - stage.height/2) / 30;”
    :-0 già fatto ???? YA ;-)

  3. Marco Says:

    ottimo, tutto molto semplice. complimenti. un altra cosa però da dire…sono un rompiballe lo so:D…ora funziona benissimos econdo il movimento del mouse, ma se ci allontaniamo dal cubo abbiamo delle rotazioni molto veloci. se volessimo tipo farlo rallentare all’iontanamento del mouse?

  4. admin Says:

    No, assolutamente :-P :-)
    Cmq non ho capito bene cosa proponi di fare. Se vuoi solo far in modo che la rotazione non sia eccessiva allontanando il mouse, basta che aumenti il numero “30″ in cubo.rotationY.
    Se invece proponi di fare in modo che allontanandoci, col mouse, dal centro del cubo diminuisce la velocità di rotazione, posso dirti che secondo me è un movimento troppo innaturale.
    Ma non credo tu proponga questo… o sbaglio?

  5. Marco Says:

    no no io propongo proprio questo:D
    che il cubo si muova quando ci andiamo sopra, ma nel momento in cui ci allontaniamo cominci a fermarsi. non so se riesco a spiegarmi. cmq credo sia proprio il concetto che te pensi sia tremendo:D
    pensi sia fattibile?

  6. Marco Says:

    Finalmente un po di 3d nel web! :-o grazie mille per i post molto utili e soprattutto funzionanti che hai pubblicato!

  7. Marco Says:

    ciao enrico…sono sempre il marco cagacaxxi degli altri post:P

    senti…se volessi creare sotto al cubo(sempre in flash) dei pulsanti, ognuno dei quali linkasse allo stesso link della faccia del cubo, come dovrei fare?
    ipotizza che il cubo funzioni da menu, e che una faccia del cubo punti su lavori, ad esempio…dovrei creare sotto un pulsante lavori che punti alla stessa pagina e che cmq faccia ruotare il cubo fino a farlo fermare sulla facciata lavori…credi sia fattibile? dove dovrei agire nel caso?

    ti ringrazio gia da ora per la disponibilità.
    ciao belloo

  8. daniele Says:

    ciao enrico da poche settimane mi sono interessato al flash e per fortuna misono imbatutto sul tuo sito, in genere non lascio mai commenti nei blog sono un lupo solitarioa :D ma devo dire che il tuo non solo è molto grazioso da visitare ma è ricco di contenuti molto interessati sei davvero un grande ho metto il tuo blog tra i miai preferiti perche merita davvero il tuo lavoro …che dire se non un grazie di cuore
    Razza

  9. admin Says:

    Ciao a tutti, scusate se sono mancato.
    Allora ringrazio a Daniele, anch’io non commento mai :-) cmq mi fà piacere che ti sia utile quel che scrivo.

    Ciao Marco, quello che chiedi tu è lecito realizzarlo, assolutamente SI. Purtroppo però non posso aiutarti così su 2 piedi, devo vedere il tuo progetto. Cmq in poche parole vuoi fare 2 menù (uno 3d e l’altro no), basta che inserisci gli stessi link, poi dipende da cosa vuoi fare, ma in maniera generica YES, WE CAN o alla Veltroni: SE PUò Fààà ;-)
    Anche il fatto che cliccando sul secondo menù, il cubo deve girarsi come se avessi cliccato su quella faccia, basta che in quel pulsante inserisci lo stesso codice della faccia del cubo in questione.
    Bye

  10. marko Says:

    ciao ho ri fatto il cubo personalizzandomelo un pò:
    http://www.openspaces.it/test/cube_mk.html
    sono riuscito ad applicargli i filtri dropshadow anche se fan shcifo:
    http://www.openspaces.it/test/cube_mk2.html
    in realtà, vorrei inserirgli un piano che fa da “terra” e una luce che proietti l’ombra del cubo sul piano… suggerimenti? grazie.
    Marco

  11. Francesco Says:

    Ma perchè a me non funziona?Quando lo faccio partire vedo tutto nero!!!

  12. Marco Says:

    ciao, domandina. come eliminiamo il fatto che il cubo si blocchi al click?

Leave a Reply