Como criar uma sequência de imagens com o Adobe Flash para seu App.

A plataforma Flash é bastante conhecida no mercado Web, por produzir um conteúdo mais interativo que o convencional Html & Css. Mas, isso tem mudado bastante.

Hum, tudo bem, mas que importância isso tem pra mim que sou um programador que utiliza o Titanium Studio?

Com o Flash você pode criar uma sequência animada de imagens (SpriteSheet) e importá-las para seu projeto feito no Titanium, deixando o seu projeto com um diferencial bem atrativo.

Se você não tem experiência com o Flash, não se preocupe. Pois, o que vou demostrar, não exige nenhum conhecimento e detalharei todos os passos, basta seguir com atenção.

Se você não tem o Flash instalado, você poderá baixar uma versão trial direto do site da Adobe. Se você tem o Flash instalado e for superior ou igual a versão “CS 3″ acredito que também não terá nenhum problema eu usarei a versão “CS 6″.

Primeiro baixe a imagem abaixo, pois criaremos uma animação de um coração pulsando.

Fígura 1.

Figura 1.

Abra o Flash e crie um novo documento com 278px de largura por 215px de altura, frame rate com 24 fps.  A versão do ActionScript não faz nenhuma diferença.

Figura 2.

Figura 2.

Agora importe a “Figura 1” para o palco com as teclas command + r no Mac ou ctrl + r no Windows, a “Figura 1″ deve ter aparecido no palco. A imagem está bem maior que o palco, pois nem estamos visualizando-o. Clique na imagem importada pressione command + k ou ctrl + k aparecerá a janela “Transform” em “Scale Width” e “Scale Hight” deixe em 31%.

Fígura 3.

Figura 3.

O palco é esse retângulo branco que você está visualizando, senão aperte command + 2 ou ctrl + 2 para visualiza-lo.

Clique na imagem, pois vamos centralizá-la no centro do palco. Pressione command + K ou ctrl + k, aparecerá uma janela “Align” então selecione a segunda e a quinta opção de “Align” e se a opção “Align to Stage” não estiver marcada marque-a.

Fígura 3

Fígura 3

A imagem está centralizada no palco, vamos converte-la em um símbolo. Clique direito sobre ela, escolha a opção “Convert to Symbol” nomeie para “coracao” em “Type” deixe como “Movie Clip” em “Registration” marque o pontinho branco  no centro caso ele esteja desmarcado.

Fígura 4.

Fígura 4.

Nosso símbolo está pronto para ser animado. Poderíamos criar uma animação de forma manual, mas vamos utilizar uma animação já definida pelo Flash. Vá em Window da barra de tarefa e escolha “Motion Presents” dentro da pasta “Default Presents” escolha “pulse” e clique no botão “apply“.

Fígura 5.

Fígura 5.

Observe que foi adicionado alguns quadros na timeline e você pode clicar em um deles e pressionar “Enter” para reproduzir a animação de “pulse” escolhida.

Se por algum motivo a imagem escolhida não estiver em uma resolução satisfatória, vá na “Library”. Se essa janela não estiver visível, vá em Window e clique em “Library“. Na “Library” você vai visualizar a imagem importada e o símbolo criado. Clique direito sobre a imagem e depois em “Properties…“, marque a opção “Allow smoothing” e em “Compression” escolha “Photo (JPEG)” em “Quality” deixa marcado a opção “Use imported JPEG data“.
Dessa forma, a imagem não vai ter nenhum tipo de compressão e ainda vai suavizar os pixels quando estiverem em movimento.

Fígura 6.

Fígura 6.

Agora vamos exportar essa animação em uma sequência de imagens para utilizarmos no Titanium. Na barra de ferramentas click File -> Export -> Export Movie escolha “PNG” como formato e nomeie como “coracao” e click em “save” aparecerá a janela “Export PNG” deixe-a como abaixo e click em “Export

Figura 7.

Figura 7.

Observe que foi gerado 24 imagens “coracao0001.png”, “coracao0002.png”… Pois a animação tem duração de 1 segundo a 24 fps. Se você precisar de mais frames por segundo basta aumentar o fps no Flash.

Ok, agora que temos a sequência de imagens vamos criar nosso projeto no Titanium. Estarei disponibilizando todos os arquivos, então se você não tem o Flash instalado e também não o instalou pode iniciar a partir daqui.

No Titanium crie um novo projeto do tipo “Default Project” ou outro de sua preferência. Eu estou usando a versão 3.0.2 do SDK e vou exportar apenas para iPhone e Android.

Abra o arquivo “app.js” apague todo código e o deixe como abaixo.

//create window
var window = Ti.UI.createWindow();

//create view
var view = Ti.UI.createView({
	backgroundColor:'#ffffff',
	layout:'vertical'
});

//label
var label = Ti.UI.createLabel({
	color:'#000000',
	text:'Sequência de imagens',
	height:'auto',
	width:'auto',
	top:'10dp'
});

//add label in view
view.add( label );

//add view in window
window.add( view );

// open app
window.open();

Esses passos são bem básicos, então acho que você não vai ter nenhuma dificuldade. Isso é o que temos até o momento.
Figura 8.Vamos adicionar a sequência de imagens criada no app. Para isso, vamos criar um objeto do tipo ImageView. Mas, antes de tudo, criei uma pasta “images” dentro da ”Resources” e adicione as imagens.

Precisamos de uma array para setarmos o caminho de todas as imagens, que nesse caso são 24, com os seguintes nomes: ‘coracao0001.png’, ‘coracao0002.png’…
Não seria nem um pouco elegante criar uma array e setar todos esses valores na mão. Utilizaremos então, uma estrutura de repetição que todos já devem conhercer, o famoso “for”.

// images
var images = [];
for( var i = 1; i < 25; i++ )
{
	var path = '/images/coracao0' + (i < 10 ? '00' : '0') + i + '.png';
	images.push( path );
}

var image = Ti.UI.createImageView({
	images:images,
	width:'278dp',
	height:'215dp',
	top:'15dp',
	repeatCount:0, // 0 repetição infinita
	duration:(1/24) // configurando frame-rate
});

// add image in view
view.add( image );

Observe que fiz uma condição para verificar quantos zeros são necessários antes de concatenar o valor do “i” a “string“. Se for menor que 10, utilizo 2 zeros, senão apenas um. Se você executar o app nesse estágio, não vai visualizar nada diferente da última execução. Precimos adicionar um evento para saber quando todas as imagens foram carregadas e iniciar a animação com o método “resume“.

image.addEventListener('load', function(e){
	image.resume();
});

Execute novamente e o coração estará pulsando no seu app. Esse resultado deve ser praticamente o mesmo para o emulador Android.

Figura 8.

Figura 8.

Segue abaixo todo o código do app.

//create window
var window = Ti.UI.createWindow();

//create view
var view = Ti.UI.createView({
	backgroundColor:'#ffffff',
	layout:'vertical'
});

//label
var label = Ti.UI.createLabel({
	color:'#000000',
	text:'Sequência de imagens',
	height:'auto',
	width:'auto',
	top:'10dp'
});

var images = [];
for( var i = 1; i < 25; i++ )
{
	var path = '/images/coracao0' + (i < 10 ? '00' : '0') + i + '.png';
	images.push( path );
}

var image = Ti.UI.createImageView({
	images:images,
	width:'278dp',
	height:'215dp',
	top:'15dp',
	repeatCount:0, // 0 repetição infinita
	duration:(1/24) // configurando frame-rate
});

image.addEventListener('load', function(e){
	image.resume();
});

var changeStatus = Ti.UI.createButton({
	title:'clange-status',
	top:'15dp',
	color:'#ff0000'
});

changeStatus.addEventListener('click', function(e){
	image.animating ? image.pause() : image.resume();
});

//add label in view
view.add( label );

// add image in view
view.add( image );

//add button
view.add( changeStatus );

//add view in window
window.add( view );

// open app
window.open();

Vlw galera, até a próxima.

Baixe aqui os arquivos

Como utilizar o método “getDefinitionByName(“MyClassLibrary”)”

A vantagem em utilizar o método “getDefinitionByName()” é que você consegue instanciar objetos da sua biblioteca de forma dinâmica. Mas, como assim de forma dinâmica? Quer dizer que existe outra forma de instanciar um objeto além dessa: new MC()? Exatamente. Primeiro abra seu Flash e crie um “MovieClip” retangular de 117 x 154 ou das dimensões que você preferir. Depois seta o AS Linkage d0 mc para “MC”, como na figura 1 abaixo.

Figura 1

Vamos adicionar esse mc criado ao palco na forma convencional.

var mcCriado:MovieClip = new MC();
mcCriado.x = 30;
mcCriado.y = 30;

addChild( mcCriado );

Agora, utilizado o “getDefinitionByName(“”)“. A primeira etapa é criar uma variável do tipo “Class” que vai receber a classe capturada pelo método “getDefinitionByName(“”)“. Isso pareceu estranho, então vamos ver como funciona na prática.

import flash.utils.getDefinitionByName;
import flash.display.MovieClip;

/*var mc:MovieClip = new MC();
mc.x = 30;
mc.y = 30;

addChild( mcCriado );*/

var MyClass:Class = getDefinitionByName( "MC" ) as Class;
var mc:MovieClip = new MyClass();
mc.x = 30;
mc.y = 30;

addChild( mc );

Éeee funcionou, mas e aí? Eu poderia fazer sempre da forma convencional, que funcionaria da mesma forma que essa utilizando o “getDefinitionByName(“”)
Isso é verdade e eu concordo com você. Mas a vantagem de utilizar o “getDefinitionByName(“”)” é a forma dinâmica como eu disse acima.
Vamos supor que você precisa instanciar 5 mcs que estão na biblioteca. Ao invés de você fazer dessa forma:


var mc1:MovieClip = new MC1();
mc1.x = 30;
addChild( mc1 );

var mc2:MovieClip = new MC2();
mc2.x = 130;
addChild( mc2 );

var mc3:MovieClip = new MC3();
mc3.x = 230;
addChild( mc3 );

var mc4:MovieClip = new MC4();
mc4.x = 330;
addChild( mc4 );

var mc5:MovieClip = new MC5();
mc5.x = 430;
addChild( mc5 );

var mc6:MovieClip = new MC6();
mc6.x = 530;
addChild( mc6 );

você pode fazer assim:

for ( var i:uint = 0; i < 5; i++ )
{
	var MyClass:Class = getDefinitionByName( "MC" + (i+1) ) as Class;
	var mc:MovieClip = new MyClass();
	mc.x = 30 + (i * 100);
	addChild( mc );
}

E você obterá um resultado parecido como na figura 2,  independente da forma utilizada. Mas note que, com um simples laço de repetição, você simplifica bem seu código. Sem falar nas vantagens de setar valores das propriedades do seu objeto pela interação de cada repetição no laço.

Ok, já aprendi a utilizar o “getDefinitionByName(“”)“, mas eu consigo instanciar apenas “MovieClip”?

Não, você pode utilizar também para instanciar “BitmapData” e “Sprite“.

Para utilizar com imagem é bem simples e funciona da mesma forma. Importe uma imagem para sua biblioteca e depois nomeie seu “AS Linkage” para “IMG“, como na figura 3.

A única diferença é que agora vamos instanciar um “Bitmap” ao invés de um “MovieClip“.

import flash.display.Bitmap;
import flash.utils.getDefinitionByName;

var MyClass = getDefinitionByName( "IMG" ) as Class;
var bmp:Bitmap = new Bitmap( new MyClass() );
bmp.x = 20;
bmp.y = 20;
bmp.smoothing = true;
addChild( bmp );

Pronto, adicionamos uma imagem e poderíamos também adicionar imagens, como no laço de repetição mostrado acima com MovieClips.
Você também pode utilizar essa técnica para dispositivos móveis com Adobe AIR sem problemas.

Mas cuidado, se você estiver utilizando o Flash Builder com SWC você vai precisar utilizar o new MC() ou new IMG(), independe do nome que estiver seu mc ou imagem na biblioteca. Você precisa fazer isso para anexar seu objeto na VM do FlashPlayer ou Adobe AIR. Depois de instanciar seu objeto, você pode utilizar o “getDefinitionByName(“”)” sem problemas.

OBSERVAÇÃO.

Caso você queira obter qual é a classe de origem do seu objeto, você pode utilizar o método “getQualifiedClassName” veja:

import flash.display.Bitmap;
import flash.utils.getDefinitionByName;

var MyClass = getDefinitionByName( "IMG" ) as Class;
var bmp:Bitmap = new Bitmap( new MyClass() );
bmp.x = 20;
bmp.y = 20;
bmp.smoothing = true;
addChild( bmp );

trace( getQualifiedClassName( bmp ) );

Observe que o retorno foi “flash.display::Bitmap” é não IMG como definido. Mas se você estiver utilizando para Sprite e MovieClip o retorno vai ser a classe definida e não “flash.display::Sprite” ou “flash.display::MovieClip“.
Espero que esse material te ajude de alguma forma.

Mover objetos com seno e cosseno

O primeiro fato ao mover objetos com seno e cosseno e saber como funciona os ângulos no flash.

O segundo fato e que sempre precisamos converte o ângulo em radiano.
O terceiro fato e termos que ter um valor para o raio desse ângulo.
Observações:
O cosseno movimento objeto apenas na horizontal, ou seja, no eixo x.
O seno faz a movimentação no eixo y, ou seja, apenas na vertical.

Então, agora vamos abrir o Flash e criar um arquivo do tipo “ActionScript 3.0″ de 500px de largura por 500px de altura a 30 fps. Você pode criar o arquivo do tamanho que preferir.
Com a ferramenta “oval toll” ou pressionando “o” criei um círculo branco, e pressione f8 para converte-lo em Movie Clip com o ponto de registro no centro. Também definir que a classe responsável por esse círculo vai ser “Ball” isso possibilita que eu adicione esse círculo no palco por código.

Observe que na biblioteca está o movieclip que acabamos de criar e seu “linkage” é “Ball”. Se você não estiver visualizando a biblioteca pressione “f11″.
Se o círculo criado estiver no palco click sobre ele e pressione “Delete” para que seja excluído.
Pressione “f9″ para que abra a janela “Actions” é onde vamos inserir nosso código.

var ball:MovieClip = new Ball(); //instanciando o objeto criado
var posX:Number = stage.stageWidth * .5; //capturando metade do palco na horizontal
var posY:Number = stage.stageHeight * .5; //capturando metade do palco na vertical

//posicionado e adicionando no centro do palco
ball.x = posX;
ball.y = posY;
addChild(ball);

Apenas adicionei o objeto no palco, ele ainda não tem nenhum movimento. Para adicionar movimento objeto, vou utilizar o evento “ENTER_FRAME” esse evento é atualizando de acordo com o fps definido. Ou seja se você definiu com 30 fps a função responsável por esse evento vai ser chamada 30 vezes por segundo.

Vamos definir também, o raio e o ângulo de movimento. Como não vamos trabalhar com o ângulo diretamente, utilizaremos uma fórmula que vai converter o ângulo em radiano. Que é o seguinte: ângulo multiplicado por (Math.PI / 180)

import flash.display.MovieClip;
import flash.events.Event;

var radius:Number = 50;
var angle:Number = 0;

var ball:MovieClip = new Ball(); //instanciando o objeto criado
var posX:Number = stage.stageWidth * .5; //capturando metade do palco na horizontal
var posY:Number = stage.stageHeight * .5; //capturando metade do palco na vertical

//posicionado e adicionando no centro do palco
ball.x = posX;
ball.y = posY;
addChild(ball);

//adicionando o evento que vai atualizar a posição de ball
ball.addEventListener(Event.ENTER_FRAME, updateBall);

function updateBall(e:Event):void
{	
	var radians:Number = getRadians(angle);//converteno o ângulo em radiano	
	ball.x = (Math.cos(radians) * radius) + posX;
	ball.y = (Math.sin(radians) * radius) + posY;	
	
	angle += 10; //incrementando o ângulo
	angle %= 360; //o resto da divisão do ângulo por 360, assim esse valor não ultrapassa 360
}

function getRadians(angle:Number):Number
{	
	return angle * (Math.PI / 180);	
}

Nas linhas 23 e 24 é onde acontece os cálculos referente a nova posição. Utilizei os métodos Math.cos e Math.sin para calcular o cosseno e o senno, passei como parâmetro o valor do ângulo convertido em radiano e multipliquei pelo valor do raio. O ângulo determina a direção em que o objeto vai traçar e o raio determina a velocidade com que o objeto vai traçar a direção!

Faça alguns teste alterando o valor do ângulo, raio e o valor com que o ângulo é incrementado.
Observação:
O diâmetro do movimento de “ball” é 2 vezes o valor do raio, sendo assim 2 * radius = 100.
Você pode movimentar “ball” apenas na direção x ou y comentando as linhas 22 e 23.
Você pode usar valores negativos para o valor do ângulo.
Exemplo: -90 que seria exatamente o mesmo que 270.

Na próxima etapa desse tutorial, vou apresentar alguns exemplos práticos que utilizei na criação de uma game.
Valew galera.

Adicionar smoothing em tempo de execução

Ei galera, esse é meu primeiro tutorial e espero que vocês gostem, então vamos ao que interessa.

Primeiro abra o flash e crie um novo arquivo do tipo “ActionScript 3.0″, logo em seguida pressione CTRL + J, e configure seu documento como a imagem seguinte.

Agora, vamos usar essa imagem abaixo ou uma outra qualquer para fazer o carregamento dela via actionscript, de preferência salve está imagem no mesmo diretório do seu arquivo flash.

Agora dentro do flash pressione F9 para abrir o painel “actions” e digite

//caminho relativo da imagem em relação ao arquivo flash
var urlImg:URLRequest = new URLRequest("naruto.jpg");
//classe loader utilizada para carrregar imagens e swfs
var imgLoad:Loader = new Loader();
//método load precisa como parametro um objeto do tipo "URLRequest"
imgLoad.load(urlImg);

//adiciona o loader que no nosso caso é uma imagem ao stage
addChild(imgLoad);

Nossa imagem foi adicionada ao palco, vamos alterar a scala dela para 60% para percebermos as alterações ocorridas, digite

imgLoad.scaleX = .6;//.6 é igual á 0.6 que por sua vez é igual 60%
imgLoad.scaleY = .6;

Perceba que nossa imagem fico bem detonada, para suavizar esse desgaste na imagem, vamos criar uma função que vai adicionar um smothing em tempo de execução.

function suavizaImg(img:Loader):void
{
	//pega o contéudo do Loader e o transforma em um Bitmap
	var image:Bitmap = img.content as Bitmap; 
	//ativando o smoothing
	image.smoothing = true;
}

Faça a chamada da função na linha debaixo onde estamos adicionando a imagem no palco e passe como parâmetro o objeto Loader, ficando assim

addChild(imgLoad);
suavizaImg(imgLoad);

Observe que vai acontecer um erro, esse diz que não pode acessar um método ou uma propriedade de referência nula.

Mas por que isso acontece? Quando utilizamos o método load da classe Loader fazemos o download do arquivo e no momento que fazemos essa chamada suavizaImg(imgLoad); esse download ainda não foi concluído. Solução: adicionar um evento que vai nos dizer quando esse download está completo.
Vamos remover

addChild(imgLoad);
suavizaImg(imgLoad);
//e logo abaixo de imgLoad.load(urlImg), vamos adicionar o nosso evento

imgLoad.contentLoaderInfo.addEventListener(Event.COMPLETE, imgCarregada);

Observação: a função “imgCarregada” é responsável pelo evento ou seja, essa função apenas vai ser executada quando o download estiver completo e dentro dela vamos adicionar aquelas 2 linhas que agente apagou

function imgCarregada(e:Event):void
{
addChild(imgLoad);
suavizaImg(imgLoad);
}

Pronto, chegamos ao fim do meu primeiro tutorial. Segue abaixo o código completo.

//caminho relativo da imagem em relação ao arquivo flash
var urlImg:URLRequest = new URLRequest("naruto.jpg");
//classe loader utilizada para carrregar imagens e swfs
var imgLoad:Loader = new Loader();
//método load precisa como parametro um objeto do tipo "URLRequest"
imgLoad.load(urlImg);

//evento que vai nos dizer quando o download estiver concluido
imgLoad.contentLoaderInfo.addEventListener(Event.COMPLETE, imgCarregada);

imgLoad.scaleX = .6; //.6 é igual á 0.6 que por sua vez é igual 60%
imgLoad.scaleY = .6;

function imgCarregada(e:Event):void
{
	//adiciona o loader que no nosso caso é uma imagem ao stage
	addChild(imgLoad);
	suavizaImg(imgLoad);
}

function suavizaImg(img:Loader):void
{
	//pega o contéudo do Loader e o transforma em um Bitmap
	var image:Bitmap = img.content as Bitmap; 
	//ativando o smoothing
	image.smoothing = true;
}