Adeus duplicateMovieClip, mas cadê o clone?

No ActionScript 3 não existe o duplicateMovieClip e a DisplayObject não implementa nenhum método de clone (espero que isso não dure muito). Ué, mas qual é o problema? É simples. As vezes não é necessária apenas uma nova instância de um objeto, mas uma que carregue consigo o estado do objeto original. Para isso serve (ou serviria) o método clone. Na prática, em um dado momento, elas são iguais e são diferentes. Isso quer dizer que elas possuem referência a endereços de memória distintos e se uma delas sofrer alteração  a outra se manterá intacta. Ou seja, no momento em que a instância clone é criada ambas possuem o mesmo estado, mas não a mesma identidade.

Onde isso faz falta?

Suponha que você queira manter 2 imagens iguais aparecendo na tela para simular um efeito de espelho ou que você precise mostrar um thumb e uma imagem grande e esta imagem é carregada dinâmicamente. Você não pode simplesmente dar addChild uma segunda vez, pois o seu objeto vai se mover. Sim, ele vai sumir do lugar antigo e aparecer no novo lugar, mas por quê? Não era para ser uma referência na memória? Sim, continua sendo, mas… Todo DisplayObject possui uma propriedade parent que faz referência ao DisplayObjectContainer onde ele foi adicionado. Sempre que o método addChild é chamado o valor da propriedade parent é alterado e consequentemente o DisplayObject deixa de estar no lugar anterior, porque afinal de contas ele só tem um pai.

Para Bitmap felizmente existe um jeitinho, mas para outros DisplayObject, não. Mas o que um Bitmap tem de tão especial? Um objeto Bitmap tem em sua composição um objeto BitmapData, e este por sua vez tem o método clone implementado. É na propriedade bitmapData que estão armazenadas todas as características da imagem. Segue um exemplo com um Bitmap gerado pelo código, mais especificamente um quadrado vermelho, veja como é simples:

// criando um bitmap (quadrado)
var bitmap:Bitmap = new Bitmap(new BitmapData(100, 100, false, 0xBB0000));
 
// adicionando bitmap no palco
this.addChild(bitmap);
 
// criando um novo bitmap com o clone do bitmap data
var bitmapClone:Bitmap = new Bitmap(bitmap.bitmapData.clone());
 
// modificando o posicionamento p/ enxergarmos os 2 elementos
bitmapClone.x = 100;
bitmapClone.y = 100;
 
// adicionando o clone no palco
this.addChild(bitmapClone);

Se uma imagem é carregada dinamicamente o processo é exatamente o mesmo, já que todo objeto Bitmap possui em sua composição um BitmapData sendo ele carregado externamente ou não. Então aproveitamos o que a imagem já tem. Segue um exemplo:

// declara e instancia um objeto loader
var loader:Loader = new Loader();
 
// adiciona listener para o carregmento da imagem
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, handleLoadComplete);
 
// define uma url para carregamento
var urlRequest:URLRequest = new URLRequest("http://www.nyan.com.br/ico/it.png");
 
// inicia o processo de carregamento
loader.load(urlRequest);
 
// handle para o evento de complete
function handleLoadComplete(event:Event):void 
{
	// cria referencia para a imagem carregada
	var image:Bitmap = loader.content as Bitmap;	
 
	// adiciona a imagem no palco
 	this.addChild(image);
 
	// cria um novo bitmap e adiciona um clone 
	// do BitmapData contido no Bitmap carregado
	var imageCopy:Bitmap = new Bitmap(image.bitmapData.clone());
 
	// adicionando copia no palco
	this.addChild(imageCopy);
	// mudando posicionamento para enxergarmos
	imageCopy.x = 100;
 
}

Tem mais uma coisa interessante nisso: se você declarar um novo Bitmap, atribuindo a ele um BitmapData existente mas sem chamar o método clone, também vai funcionar. A diferença é que se você fizer qualquer alteração no bitmapData através de qualquer um dos Bitmaps, ambos serão alterados, o que não acontece quando invocamos o método clone, pois ele sempre retorna uma nova instância. Este é um bom exemplo pra entender a diferença entre instâncias e referências.

Tags: , ,

3 comments

  1. Tiago Braga

    Olá Daniela,

    Achei seu site meio por acaso, pq busco na net mais explicações sobre OOP e AS3. Seu site é muito bom, muito bom mesmo e se todo conteúdo postado for assim, estou feito! :P

    Bom, tenho vc no meu twitter (@tiagobraga), e estou sendo ligado no que vc está colocando no seu blog.

    Você realmente está de parabéns!!!

    Até

  2. Dieggo Carrilho

    Daniela, queria saber se isto se aplica também a um MC, ja no palco, para duplicar ele ???

  3. Oi Dieggo,

    Se o método clone existisse em AS3 para DisplayObject, seria possível “duplicar” qualquer elemento visual pelo simples fato de que, quando um elemento está no palco, significa que o estado dele está alterado e isso fica definido pela propriedade stage do elemento. Então na hora de clonar o elemento a propriedade parent e stage seriam as mesmas.

    Quanto a este processo que descrevi aqui, funciona se o elemento estiver no palco sim, mas somente para bitmaps porque voce pode recuperar o bitmapData dele (e este possui o método clone). Para MCs ainda não existe uma forma nativa de “duplicar”, mas já se fala em algumas bibliotecas para isso, porém ainda não testei nada do tipo.

    Um abraço.

Leave a comment