2010-10-12 8 views
5

Come copiare oggetti di visualizzazione (sprite, clip da film ecc.) Mantenendo il loro contenuto (grafica, oggetti di visualizzazione aggiunti, ecc.) In AS3? La soluzione più comunemente suggerita da Kirupa (http://www.kirupa.com/forum/showpost.php?p=1939827 & postcount = 172) non sembra copiare qualsiasi grafica o oggetti di visualizzazione secondari:AS3: Impossibile copiare DisplayObjects con il contenuto?

// create a sprite 
var s:Sprite = new Sprite(); 
// add a text field 
var tf:TextField = new TextField(); 
tf.text = "nisse"; 
s.addChild(tf); 
// draw something 
s.graphics.lineStyle(1, 0x00FF00); 
s.graphics.drawCircle(10, 10, 10); 
s.x=100; 
// add it to parent 
this.addChild(s);  

// create a copy using Kirupas duplicate display object solution  
var sCopy:Sprite = duplicateDisplayObject(s, true) as Sprite; 
sCopy.x = 200; 
// confirem that the copy exists: 
trace(sCopy); 
// add to parent 
this.addChild(sCopy); // <- works, but the original textfield and graphics are gone! 

Esiste una soluzione? (Se non - Perché? Non è un oggetto di visualizzazione rappresentato da un'area di memoria che dovrebbe essere possibile copiare, come qualsiasi altro oggetto?)

risposta

6

Risposta breve:

grafica non sono introspectable in fase di esecuzione. Non importa quale sia il codice di Kirupa, non ha modo di sapere quale forma hai disegnato e nessun modo di copiarlo o ridisegnarlo. (Il campo di testo sempre lasciato fuori potrebbe essere un bug o di proposito, non ho idea, ma non c'è niente da fare intorno alla forma.)

Risposta lunga:

Un DisplayObject non è solo un pezzo di memoria , come una bitmap o una stringa. È un oggetto, con molte proprietà figlio, molte delle quali sono anche oggetti, funzioni, o classi, ecc. Quindi quando dici di voler duplicarne uno, vale la pena chiedersi che cosa significhi esattamente. Gli oggetti figlio, ad esempio gli array, possono essere copiati per riferimento o duplicati? Se qualcuno degli oggetti contiene riferimenti ad altri oggetti di visualizzazione, oltre alla loro lista di bambini, come fai a sapere se copiare il riferimento o duplicare il bersaglio? Se alcuni degli oggetti originali stavano ascoltando eventi di tastiera o timer in esecuzione, i duplicati funzionerebbero senza essere registrati? Et cetera, et cetera.

Tutto ciò è un modo prolisso per dire, nei linguaggi OOP (come AS3), non esiste un modo universalmente significativo di duplicare gli oggetti. Certo, puoi recitare attraverso un albero di MovieClip, crearne di nuovi e provare a copiare le proprietà dagli originali ai duplicati - ed è questo che presumibilmente sta facendo il codice di Kirupa. Ma per qualsiasi cosa, tranne contenuti banali, come stai scoprendo, questo non ti porterà quello che vuoi. Ecco perché non esiste un modo integrato per farlo, perché la maggior parte delle volte non farebbe ciò che la gente sperava.

In definitiva, la vera soluzione a questo tipo di problema è di dare un'occhiata a ciò che deve essere realizzato e di trovare un modo per farlo senza duplicare gli oggetti. Se hai bisogno solo di una copia visiva dell'originale, potresti considerare di disegnare l'originale in una bitmap ogni fotogramma. O forse l'approccio migliore è costruire una struttura di dati contenente tutte le informazioni rilevanti per il tuo oggetto, in modo da poter duplicare i dati e inizializzare un oggetto basato su di esso. O forse dovresti creare inizialmente un pool di oggetti e mantenerne uno ciascuno, in modo che quando hai bisogno di duplicati in seguito li hai.

In entrambi i casi, alla fine della giornata il problema è architettonico, quindi la soluzione dovrà essere altrettanto valida.

+0

Grazie, fenomas. Molto chiarificante! – Cambiata

+1

"La grafica non è introspectable in fase di esecuzione" true, ma è possibile copiare grafica. Vedi il mio post qui sotto. – Joony

+0

Ottima risposta, molto completa - questa risposta rende le altre risposte intrinsecamente confuse – 1owk3y

2

Questo perché AS3 sta cercando di essere un linguaggio orientato agli oggetti e l'OOP modo di fare quello che stai cercando di fare è creare una classe con un metodo clone() :) Penso che questo sarebbe il modo più flessibile, privo di bug e facile da leggere di copiare il tuo oggetto.

6

Non è possibile copiare nativamente la maggior parte delle classi interne, ma si potrebbe desiderare di guardare a IExternalizable (http://www.adobe.com/livedocs/flash/9.0/ActionScriptLangRefV3/flash/utils/IExternalizable.html)

è il metodo di serializzazione oggetti utilizzati internamente da AMF. Costringe i tuoi oggetti a creare due metodi, readExternal e writeExternal. L'idea è che writeExternal ti permette di impacchettare lo stato interno degli oggetti in un ByteArray, quindi viene creata una nuova istanza della classe, e AMF passerà quel ByteArray al metodo readExternal, dove puoi ricreare lo stato interno degli oggetti precedenti mano. La chiamata dei metodi e di istanze è tutto fatto per voi attraverso l'ObjectUtil.copy() il metodo (http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/utils/ObjectUtil.html?filter_flex=4.1&filter_flashplayer=10.1&filter_air=2#copy()) se si sta utilizzando Flex SDK, in caso contrario, l'applicazione copia è la seguente:

function copy(value:*):*{ 
    var buffer:ByteArray = new ByteArray(); 
    buffer.writeObject(value); 
    buffer.position = 0; 
    var result:Object = buffer.readObject(); 
    return result; 
} 

Come si puoi vedere qui, sono solo i metodi readObject e writeObject di ByteArray che eseguono effettivamente la serializzazione, non c'è una reale necessità per la classe ObjectUtil.

Potrebbe anche essere necessario registrare un alias di classe per la classe che si desidera copiare in modo AMF sa quello oggetto per creare, altrimenti sarà solo ottenere oggetti generici fuori l'altra estremità:

registerClassAlias("com.example.ExampleClass", com.example.ExampleClass); 

Dovrebbe essere ha osservato che non è possibile avere parametri obbligatori nel Costruttore di oggetti che si desidera copiare con questo metodo e che readObject di ByteArray controllerà l'oggetto per vedere se implementa IExternalizable, altrimenti copierà solo le sue proprietà pubbliche. Questo è il motivo per cui la maggior parte delle classi incorporate non riuscirà a copiare.

Sul punto di Grafica di copiatura dall'interno Mostra oggetti, ci sono alcuni metodi che è possibile utilizzare:

Come di FP 10, Graphics ha un altro metodo utile.

public function copyFrom(sourceGraphics:Graphics):void 

(http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/Graphics.html#copyFrom())

Quindi una volta che hai copiato l'oggetto, è possibile copiare manualmente la grafica sopra. Basta inserire questo nel metodo copy(). Basta controllare se estende Sprite o MovieClip e quindi chiama copyFrom(). Questo sarebbe il modo più semplice per scrivere.

E qui c'è un altro nuovo metodo.

public function drawGraphicsData(graphicsData:Vector.<IGraphicsData>):void 

(http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/Graphics.html#drawGraphicsData())

Se si dovesse memorizzare tutti i comandi come dati grezzi (anche loro JSON, o creare DTOs interni), quindi scrivere i metodi IExternalizable per copiare i comandi al nuovo oggetto e ripopolare la grafica usando questo metodo. Questo sarebbe un problema da scrivere, ma vorrebbe dire che basta chiamare il metodo copy() e si dispone di una copia, grafica e tutto, senza alcun codice personalizzato nel metodo copy(). È anche possibile chiamare i metodi grafici in modo dinamico in base ai comandi, in modo da poter far funzionare questo in FP9, se necessario. Questo ha il vantaggio in più di permetterti di cambiare i comandi come al momento non è possibile. Una volta che scrivi alla grafica, sei bloccato con esso.

+0

Grazie, Joony! Informazioni preziose sul soggetto IExernalizable! – Cambiata

1

Non è possibile creare una copia esatta, ma è possibile creare facilmente una bitmap sostitutiva. Che funziona per me nella maggior parte dei casi (riempimenti, miniature ecc.)

Vedere il metodo draw() di BitmapData.

+0

Grazie, poco! Ho pensato che questo avrebbe portato a problemi con la trasparenza bitmap (gli sprite che uso sono parzialmente trasparenti), ma lo proverò. Forse funziona bene! – Cambiata

+0

nessun problema, si crea un BitmapData trasparente come questo: nuovo BitmapData (larghezza, altezza, vero, 0). – poco

0
var newObject:DisplayObject; 
newObject = originalObject; 

addChild(newObject); 

Questo è come lo farei.Ha funzionato con tutti i tipi di oggetti di visualizzazione (mc, sprite, textField ecc.)

+2

Questo non copia affatto l'oggetto; crea solo un altro riferimento ad esso. Ad esempio, se 'originalObject' era figlio di un altro contenitore nel momento in cui è stato eseguito il tuo esempio, sarebbe stato rimosso da quel contenitore quando è stato chiamato' addChild (newObject) '. – hanenbro

Problemi correlati