Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Gestione della profondità con Actionscript 3

Analizziamo i comando utili per ricavare e variare la profondità di uno o più oggetti con Actionscript 3
Analizziamo i comando utili per ricavare e variare la profondità di uno o più oggetti con Actionscript 3
Link copiato negli appunti

Nella creazione di animazioni e progetti in Flash, un aspetto molto importante è la gestione della profondità dei vari elementi, ovvero l'ordine con cui vengono mostrati sullo stage e di conseguenza il modo in cui due o più oggetti vengono sovrapposti.

Nella fase di design, usando la timeline, il concetto è molto semplice: gli oggetti seguono l'ordine dei layer, dove gli oggetti di un livello saranno sempre sopra a quelli dei livelli inferiori. Per capire meglio, guardiamo la figura: notiamo che gli oggetti su un livello "coprono" eventuali parti in comune con oggetti posti sui livelli inferiori.

Figura 1. Sovrapposizione degli oggetti in base al loro layer
Sovrapposizione degli oggetti in base al loro layer

Screenshot dello stage

Supponiamo ora di voler cambiare dinamicamente la profondità di queste clip, in basse a un'azione dell'utente, oppure di voler aggiungere degli oggetti durante l'esecuzione del filmato: dovremo gestire la profondità degli elementi tramite Actionscript.

In questo articolo vedremo i comando utili per ricavare e variare la profondità di uno o più oggetti con Actionscript 3.

Ricavare la profondità di un oggetto

Per poter agire con Actionscript è necessario che l'oggetto abbia un nome istanza da utilizzare come riferimento; nel caso di clip e oggetti creati dinamicamente potremo invece usare la variabile di riferimento dell'oggetto.

Il comando Actionscript 3 per ricavare la profondità di un oggetto è getChildIndex:

getChildIndex(nomeistranza)

nomeistanza è il nome dell'oggetto di cui vogliamo sapere la profondità. Ad esempio convertendo in movieclip i tre oggetti visti in precedenza e usando il codice:

trace(getChildIndex(cerchio),getChildIndex(quad),getChildIndex(rett))

Come risultato nel pannello output otterremo 2 1 0; come per i layer, anche in Actionscript la profondità più alta ha la precedenza su quelle più basse, infatti il cerchio ha profondità 2 (la più alta), il quadrato profondità 1 (sarà sopra al rettangolo, ma sotto al cerchio) e il rettangolo profondità 0 (sta sotto a tutti gli altri oggetti). Nessun oggetto potrà avere una profondità inferiore a zero, come invece accadeva in Actionscript 2.

È anche possibile il procedimento inverso, ovvero sapere quale oggetto occupa una determinata profondità: per questo si usa getChildAt:

getChildAt(profondita)

Nel nostro esempio, usando il codice

trace(getChildAt(0).name)

Otterremmo come output "rett", che è infatti il nome dell'oggetto attualmente posto a profondità 0 (il rettangolo rosso).

Aggiungere un oggetto

In Actionscript 3 per aggiungere un oggetto allo stage è necessario aggiungerlo alla display list, in parole semplici non basta crearlo ma bisogna anche inserirlo sullo stage usando il comando addChild. Supponiamo di creare un nuovo quadrato usando i drawing methods:

Listato 1. Crea un quadrato con i drawing methods

var mc:MovieClip = new MovieClip()
mc.graphics.lineStyle(1,0x000000,100)
mc.graphics.beginFill(0x009900,.5)
mc.graphics.drawRect(50,50,100,100)

Con questo codice il nostro MovieClip sarà pronto per essere utilizzato, ma per vederlo nel filmato dovremo aggiungere la seguente riga di codice:

addChild(mc)

Il comando addChild aggiunge un elemento alla profondità più alta disponibile; questo significa che un oggetto aggiunto tramite addChild risulterà in primo piano rispetto a tutti gli altri elementi del filmato.

Qualora volessimo aggiungere l'oggetto a una profondità diversa, per esempio ponendolo sul fondo e non in primo piano, è necessario usare il comando addChildAt, che permette di specificare come parametro la profondità in cui inserire la clip; per aggiungere la clip sotto a tutte le altre quindi basterà scrivere

addChildAt(mc,0)

Di conseguenza tutte le altre clip aumenteranno di 1 la propria profondità (il rettangolo passerà a 1, il quadrato a 2 e il cerchio a 3).

Nota: in Actionscript 2 era possibile specificare una profondità a piacere quando si creava un movieclip dinamicamente ed era possibile ricavare la più alta disponibile tramite il comando getNextHighestDepth; quest'ultimo comando in pratica è "sostituito" da addChild, che offre lo stesso comportamento, mentre per quanto riguarda l'aggiunta ad una profondità a piacere si potrebbe pensare che anche addChildAt offra la stessa possibilità: non è così.

Se con Actionscript 2 potevamo tranquillamente usare un comando del tipo _root.createEmptyMovieClip("mc",999) e quindi posizionare "mc" alla profondità 999, se proviamo a usare addChildAt(mc,999) riceviamo il seguente errore:

RangeError: Error #2006: L'indice fornito è fuori intervallo. at flash.display::DisplayObjectContainer/addChildAt() at Untitled_fla::MainTimeline/frame1()

Questo perchè Actionscript 3 richiede che le profondità siano sequenziali: non è possibile avere un livello di profondità "vuoto"; nel nostro caso quindi, avendo già tre clip presenti sullo stage (e di conseguenza profondità da 0 a 2), l'intervallo consentito per il comando addChildAt sarà 0-3. Qualsiasi valore superiore a 3 causerà il RangeError appena visto.

A prima vista questo comportamento potrebbe sembrare fastidioso, ma nel caso in cui volessimo mantenere sempre un oggetto in primo piano basterà aver cura di sfruttare il comando addChildAt in modo che tutti i nuovi elementi vengano posti ad una profondità inferiore rispetto a quella dell'oggetto che vogliamo lasciare in primo piano.

Portare un oggetto in primo piano

Sfruttando il comportamento del comando addChild è possibile non solo aggiungere un nuovo oggetto in primo piano, ma anche portare in primo piano un elemento già esistente: se come parametro per questo comando utilizziamo un movieclip già presente sullo stage, infatti, non ne verrà creato uno nuovo, ma semplicemente quello presente nel filmato verrà portato in primo piano.

Per capire meglio, questa è la situazione attuale del nostro file SWF di esempio:

Figura 2. Situazione attuale del flimato di esempio
Situazione attuale del flimato di esempio

Screenshot del filmato

Vogliamo spostare in primo piano il rettangolo rosso; basterà utilizzare il codice

addChild(rett)

Figura 3. Il rettangolo rosso portato in primo piano
Il rettangolo rosso portato in primo piano

Screenshot del filmato

Questo comportamento è molto utile ad esempio nella creazione di RIA dove potremmo voler portare in primo piano un pannello quando l'utente lo seleziona: basterà associare al click sull'oggetto il comando addChild; nell'esempio seguente è stato fatto in modo che ogni oggetto, quando cliccato, venisse portato in primo piano.

Cambio della profondità al click del mouse

Listato 2. Codice per il cambio della profondità

// creiamo il nuovo clip (il quadrato verde)
var mc:MovieClip = new MovieClip()
mc.graphics.lineStyle(1,0x000000,100)
mc.graphics.beginFill(0x009900,.5)
mc.graphics.drawRect(50,50,100,100)
addChild(mc)

// Associamo all'evento CLICK la funzione primoPiano per tutti gli oggetti
rett.addEventListener(MouseEvent.CLICK,primoPiano)
cerchio.addEventListener(MouseEvent.CLICK,primoPiano)
quad.addEventListener(MouseEvent.CLICK,primoPiano)
mc.addEventListener(MouseEvent.CLICK,primoPiano)

// la funzione porta in primo piano l'oggetto cliccato
function primoPiano(evt:MouseEvent){
  addChild(evt.target as MovieClip)
}

Cambiare la profondità di un movieclip

Per cambiare la profondità di un movieclip abbiamo a disposizione il comando setChildIndex. Anche per questo comando vale quanto già precisato riguardo all'impossibilità di avere dei livelli di profondità "vuoti", per cui lo spostamento va sempre limitato all'intervallo a disposizione.

setChildIndex(nomeistanza, profondità)

In questo modo andiamo a cambiare la profondità di un singolo clip, ma volendo possiamo scambiare la profondità di due elementi utilizzando il comando swapChildren:

swapChildren(clip1,clip2)

Qualora non conoscessimo il nome delle due clip da scambiare di posizione, oppure volessimo variare tra due profondità indipendentemente dalle clip attualmente presenti, possiamo usare il comando swapChildrenAt:

swapChildrenAt(profondita1, profondita2)

Conoscere il numero di oggetti presenti

Nel caso di filmati dove vengano aggiunti dinamicamente molti oggetti risulta molto utile, se non fondamentale, conoscere il numero di oggetti presenti sullo stage o in un movieclip, questo principalmente per evitare di fare riferimento a profondità errate e ottenere quindi un RangeError; fortunatamente è disponibile la proprietà numChildren, che restituisce il numero di oggetti attualmente presenti in un elemento e da cui di conseguenza possiamo facilmente ricavare il numero di profondità disponibili: sappiamo infatti che non possono esserci livelli di profondità vuoti, di conseguenza se un oggetto ha x oggetti, l'intervallo di profondità disponibile sarà senza dubbio da 0 a x-1.

Grazie a questa proprietà usata in combinazione con il comando setChildIndex possiamo facilmente modificare l'esempio visto in precedenza e fare in modo che al click su un oggetto questo aumenti la sua profondità di 1, controllando al tempo stesso che la nuova profondità sia disponibile e non fuori intervallo. Modifichiamo rispetto all'esempio precedente solo la funzione primoPiano:

Listato 3. Scala la posizione dell'oggetto cliccato

function primoPiano(evt:MouseEvent){
  var clip = evt.target as MovieClip
  if(getChildIndex(clip) < numChildren-1){
    setChildIndex(clip, getChildIndex(clip)+1)
  }else{
    trace("Massima profondità raggiunta")
  }
}

Con questo codice, ad ogni click su un oggetto, aumenteremo la sua profondità di uno (un po' come avviene per la funzione "Porta avanti" di molti software) fino al livello massimo disponibile; sapendo che la minima profondità possibile è 0 possiamo anche eseguire il procedimento inverso e diminuire di volta in volta la profondità dell'oggetto (come per il comando "Porta indietro"), in questo modo:

Listato 4. Porta indietro l'oggetto cliccato

function primoPiano(evt:MouseEvent){
  var clip = evt.target as MovieClip
  if(getChildIndex(clip) > 0){
    setChildIndex(clip, getChildIndex(clip)-1)
  }else{
    trace("Minima profondità raggiunta")
  }
}

Ti consigliamo anche