2010-10-12 15 views
5

¿Cómo copiar objetos de visualización (sprites, clips de película, etc.) manteniendo su contenido (gráficos, objetos de visualización agregados, etc.) en AS3? no parece la solución más comúnmente sugerido por Kirupa (http://www.kirupa.com/forum/showpost.php?p=1939827 & postcount = 172) para copiar los gráficos o los objetos de visualización secundarios:AS3: ¿Imposible copiar DisplayObjects con contenido?

// 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! 

¿Hay alguna referencia a esto? (Si no, ¿por qué? ¿No es un objeto de visualización representado por un área de memoria que debería ser posible copiar, como cualquier otro objeto?)

Respuesta

6

Respuesta corta:

Los gráficos no están introspectable en tiempo de ejecución. No importa qué está haciendo el código de Kirupa, no tiene forma de saber qué forma dibujaste, y no hay forma de copiarlo o volver a dibujarlo. (El campo de texto están quedando fuera puede ser algún error o por diseño, no tengo ni idea, pero no hay manera alrededor de la forma.)

Respuesta larga:

Un DisplayObject no es sólo un trozo de memoria , como un mapa de bits o una cadena. Es un objeto con muchas propiedades secundarias, muchas de las cuales también son objetos, o funciones, o clases, etc. Por lo tanto, cuando dice que quiere duplicar una, vale la pena preguntarse qué significa exactamente eso. ¿Deberían los objetos secundarios, como matrices, por ejemplo, copiarse por referencia o duplicarse? Si alguno de los objetos contiene referencias a otros objetos de visualización, además de su lista de hijos, ¿cómo sabe si copiar la referencia o duplicar el objetivo? Si algunos de los objetos originales estuvieran escuchando eventos de teclado o temporizadores en ejecución, ¿funcionarían los duplicados sin registrarse también? Et cetera, etcétera.

Todo lo cual es una manera larga de decir que, en los lenguajes de OOP (como AS3), no existe una forma universalmente significativa de duplicar objetos. Por supuesto, puedes recurrir a través de un árbol de MovieClips, crear nuevos e intentar copiar propiedades de los originales a los duplicados, y eso es lo que presumiblemente hace el código de Kirupa. Pero para cualquier cosa que no sea contenido trivial, como descubrirás, esto no te dará lo que quieres. Es por eso que no hay una forma incorporada de hacerlo, porque la mayoría de las veces no haría lo que la gente esperaba.

En última instancia, la solución real a este tipo de problema es observar detenidamente lo que se debe lograr y encontrar la forma de hacerlo sin duplicar objetos. Si solo necesita una copia visual del original, puede considerar dibujar el original en un mapa de bits en cada cuadro. O tal vez el mejor enfoque es construir una estructura de datos que contenga toda la información relevante para su objeto, para que pueda duplicar los datos e inicializar un objeto basado en él. O tal vez debería crear inicialmente un conjunto de objetos y mantener cada uno, de modo que cuando necesite duplicados más tarde los tenga.

De cualquier manera, al final del día, el problema es arquitectónico, por lo que la solución deberá ser también.

+0

Gracias, fenomas. Muy clarificador – Cambiata

+1

"Los gráficos no son introspectibles en el tiempo de ejecución" verdadero, pero puede copiar Gráficos. Ver mi publicación a continuación. – Joony

+0

Gran respuesta, muy completa: esta respuesta hace que las otras respuestas sean intrincadamente confusas – 1owk3y

2

Esto se debe a que AS3 intenta ser un lenguaje orientado a objetos y el OOP La forma de hacer lo que intenta hacer es crear una clase con un método de clonación() :) Creo que esta sería la manera más flexible, libre de errores y fácil de leer para copiar su objeto.

6

Usted forma nativa no puede copiar la mayoría de las clases internas, pero es posible que desee ver a IExternalizable (http://www.adobe.com/livedocs/flash/9.0/ActionScriptLangRefV3/flash/utils/IExternalizable.html)

Es el método de serialising objetos utilizados internamente por la AMF. Obliga a tus objetos a crear dos métodos, readExternal y writeExternal. La idea es que writeExternal le permite empaquetar el estado interno de los objetos en un ByteArray, luego se crea una nueva instancia de su clase, y AMF pasará ese ByteArray al método readExternal, donde puede recrear el estado interno de los objetos previos mediante mano. La llamada de los métodos y de instancias se hace todo para usted a través del método (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()) ObjectUtil.copy() si está utilizando el SDK de Flex, de lo contrario, la aplicación de copia es de la siguiente manera:

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

Como Puede ver aquí, solo los métodos readObject y writeObject de ByteArray que realmente hacen la serialización, no hay una necesidad real para la clase ObjectUtil.

También puede ser necesario registrar un alias de clase para la clase que desea copiar de manera AMF sabe qué objeto de crear, de lo contrario se acaba de obtener genérica por el otro extremo:

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

Debe ser notó que no puede haber parámetros requeridos en el Constructor de objetos que desea copiar con este método, y que readObject de ByteArray comprobará el objeto para ver si implementa IExternalizable, de lo contrario solo copiará sus propiedades públicas. Esta es la razón por la cual la mayoría de las clases integradas no podrán copiar.

En el punto de Gráficos de copiado desde el interior de los objetos de visualización, hay algunos métodos que puede utilizar:

A partir del FP 10, Gráficos tiene otro método útil.

public function copyFrom(sourceGraphics:Graphics):void 

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

Así que una vez que haya copiado de su objeto, a continuación, puede copiar manualmente los gráficos más. Simplemente ponga esto en el método copy(). Simplemente verifique si extiende Sprite o MovieClip y luego invoque copyFrom(). Este sería el más fácil de escribir.

Y aquí hay otro método nuevo.

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

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

Si se va a almacenar todos los comandos como datos en bruto (incluso JSON ellos, o crear dtos internos), a continuación, escribir los métodos IExternalizable para copiar los comandos al nuevo objeto y repoblar los gráficos usando este método. Esto sería un dolor de escribir, pero significaría que simplemente llama al método copy() y tiene una copia, Graphics y todo, sin ningún código personalizado en el método copy(). También puede llamar dinámicamente a los métodos gráficos en función de los comandos, de modo que pueda hacer que funcione en el FP9 si es necesario. Esto tiene la ventaja adicional de permitirle cambiar los comandos ya que actualmente no es posible. Una vez que escribes en los gráficos, te quedas atascado.

+0

¡Gracias, Joony! ¡Información valiosa sobre el tema IExernalizable! – Cambiata

1

No puede hacer una copia exacta, pero puede crear fácilmente un mapa de bits sustituto. Lo cual funciona para mí en la mayoría de los casos (rellenos, miniaturas, etc.)

Consulte el método draw() de BitmapData.

+0

¡Gracias, poco! He estado pensando que esto generaría problemas con la transparencia del mapa de bits (los sprites que uso son parcialmente transparentes), pero lo intentaré. Tal vez funciona bien! – Cambiata

+0

no hay problema, crea un BitmapData transparente como este: nuevo BitmapData (ancho, alto, verdadero, 0). – poco

0
var newObject:DisplayObject; 
newObject = originalObject; 

addChild(newObject); 

Así es como lo haría.Ha funcionado con todos los tipos de objetos de visualización (mc's, sprites, textField, etc.)

+2

Esto no copia el objeto en absoluto; simplemente crea otra referencia a eso. Por ejemplo, si 'originalObject' era un elemento secundario de otro contenedor en el momento en que se ejecutó su ejemplo, se eliminaría de ese contenedor cuando se llamara a' addChild (newObject) '. – hanenbro