Archive

Posts Tagged ‘ActionScript’

Manipulação de audio

June 21st, 2010 No comments

Entre as novidades do Flash Player 10.1 existe a possibilidade de trabalhar a manipulação de som vinda do microfone. Dê uma olhada no estudo abaixo e deixe sua sugestão.

Ligue seu microfone e fone (é importante usar o fone), a webcam e dê uma olhada.

*Requer Flash Player 10.1

The Flash plugin is required to view this object.

Quer saber mais sobre transformações de audio, veja os links abaixo.

http://labs.hellokeita.com/

http://tv.adobe.com/watch/adc-presents/microphone-access-in-flash-player-101/

http://blog.onebyonedesign.com/?p=416

http://www.nickkuh.com/flash-flex-air/pitching-the-microphone-with-flash-player-10-1-beta/2010/03/

http://blog.andre-michelle.com/2009/pitch-mp3/

http://blog.onebyonedesign.com/?p=416

http://www.smart-page.net/blog/2009/12/30/sing-like-hal-with-the-flash-player-101/

Categories: ActionScript Tags: ,

Multitouch – Parte I

June 9th, 2010 No comments

Como (quase) todo mundo sabe, o Flash Player 10.1 e AIR 2.0 trazem suporte ao Multitouch, isso torna inúmeras possibilidades de interação viáveis. Ainda existe um grande problema que é a ausência de dispositivos preparados para este tipo de interação.

Para quem tem um Macbook Pro (entre outros dispositivos), já pode utilizar o Multitouch. No caso do Macbook, ainda existe a necessidade da aplicação estar rodando no AIR. Apesar disso, o desenvolvimento é extremamente simples, porém, é preciso muito cuidado com o que o dispositivo suporta.

Uma maneira simples de saber quais eventos o dispositivo suporta é usando:

trace(Multitouch.supportsTouchEvents, Multitouch.supportsGestureEvents);

Neste trace você poderá avaliar que tipo de eventos o dispositivo suporta, caso ele tenha suporte a Gestures, você ainda pode verificar quais eventos estão disponíveis.

trace(Multitouch.supportedGestures);

O código abaixo mostra as fases dos eventos, como não faria sentido disponibilizar um aplicativo em AIR para isso, depois do código está o print do retorno.

package net.brunoribeiro.multitouch
{
  import flash.display.Sprite;
  import flash.display.StageScaleMode;
  import flash.events.Event;
  import flash.events.TouchEvent;
  import flash.events.TransformGestureEvent;
  import flash.ui.Multitouch;
  import flash.ui.MultitouchInputMode;

  /**
   * @author Bruno Ribeiro
   */


  [SWF(backgroundColor="#FFFFFF", frameRate="31", width="800", height="600")]
  public class Main extends Sprite
  {
    public function Main()
    {
      Multitouch.inputMode = MultitouchInputMode.GESTURE;
      stage ?_init(null) : addEventListener(Event.ADDED_TO_STAGE, _init);
    }

    private function _init(event : Event) : void
    {
      stage.scaleMode = StageScaleMode.NO_SCALE;
      txtTouch.text   = Multitouch.supportsTouchEvents ? "disponível" : "indisponível";
      txtGesture.text = Multitouch.supportsGestureEvents ? "disponível" : "indisponível" ;
     
      if(Multitouch.supportsGestureEvents)
      {
        stage.addEventListener(TransformGestureEvent.GESTURE_ZOOM, _updateInfo, false, 0, true);
        stage.addEventListener(TransformGestureEvent.GESTURE_ROTATE, _updateInfo, false, 0, true);
        stage.addEventListener(TransformGestureEvent.GESTURE_SWIPE, _updateInfo, false, 0, true);
        stage.addEventListener(TransformGestureEvent.GESTURE_PAN, _updateInfo, false, 0, true);
      }
    }
   
    private function _updateInfo (e:*) : void
    {
      txtTipo.text = e.type;
     
      txtLog.text += "\n--------";
      txtLog.text += "\n Tipo: " + e.type;
      txtLog.text += "\n Fase: " + e.phase;
     
      if(e.type == TransformGestureEvent.GESTURE_ZOOM)
      {
        txtLog.text += "\n Valor: " + e.scaleX;     }
      else if (e.type == TransformGestureEvent.GESTURE_ROTATE)
      {
        txtLog.text += "\n Valor: " + e.rotation;
      }
   
      txtLog.scrollV  = txtLog.maxScrollV;
    }
  }
}

Fases do evento

Categories: ActionScript Tags: ,

Flash, Flex, Air e AS3

March 17th, 2010 No comments

Eu sei que existe farto material sobre a diferença disso tudo na internet, mas por conta de recentes fatos, me vi quase que obrigado a escrever sobre isso. Espero com isso esclarecer as diferenças e uso disso tudo.

Flash IDE

Ambiente de desenvolvimento, normalmente utilizado para a criação de efeitos visuais, animações e look’n feel do site/aplicação. É pouco utilizado por desenvolvedores, mas permite, entre outras coisas a compilação de arquivos para gerar SWFs.

Flex Builder / Flash Builder

IDE para construção de aplicações, tanto (E não somente) utilizando o MXML quanto AS3 puro.

Flex

Framework – conjunto de classes e componentes – usado para a construção de aplicativos em AS3.

MXML

Linguagem de marcação para construir aplicações Flex. No momento da compilação a marcação é “substituida” por AS3.

SWF

Arquivo gerado após compilação no Flash e/ou Flex.

Air SDK

Pacote de desenvolvimento para distribuição de aplicativos em Air

Air Runtime

Em linhas gerais, é uma forma de distribuição de suas aplicações criadas no Flash, Flex ou mesmo em HTML. Usa o Webkit e Flash Player para renderização do HTML e arquivos SWF.

Categories: ActionScript, Mercado, Work Tags: ,

Flash Camp Brasil

December 16th, 2009 1 comment

Finalmente vai começar o primeiro evento de grande proporção focado na comunidade que utiliza o Adobe Flash. É a melhor oportunidade de conhecer pessoas e trocar conhecimento.

FlashCamp

flashcamp2

Compreendendo como funciona uma aplicação do Facebook

December 5th, 2009 2 comments

Na última semana estive trabalhando no projeto de uma aplicação que roda dentro do Facebook, como eu nunca tinha feito nada pro Facebook, no começo achei tudo meio estranho, mas no fim das contas as coisas começaram a fazer sentido.

A primeira coisa a fazer é baixar a biblioteca do php e a biblioteca AS3, na hora de editar seu arquivo index, não esqueça de dar uma olhada na documentação do FBML e no Developer roadmap.

Quando você adiciona um SWF via FBML, ele mesmo já passa algumas informações importantes via flashvars, secret e fb_sig_user (id do usuário que está usando sua aplicação). Com isso já é possível começar a aplicação. O Fluxo no Facebook está representado (toscamente, claro) no diagrama abaixo.

Facebook

Para que se possa entender melhor, um exemplo.

Imports:

import com.facebook.events.FacebookEvent;
import com.facebook.Facebook;
import com.facebook.net.FacebookCall;
import com.facebook.utils.FacebookSessionUtil;
import com.facebook.data.users.FacebookUser;
import com.facebook.data.users.FacebookUserCollection;
import com.facebook.commands.users.GetInfo;
import com.facebook.data.users.GetInfoData;

Declarações:

private var _facebook       : Facebook;
private var _session        : FacebookSessionUtil;
private var _userCollection : FacebookUserCollection;
private var _user           : String;

Inicialização:

_user       = loaderInfo.parameters.fb_sig_user;
_session    = new FacebookSessionUtil(API_KEY, SECRET, loaderInfo);
_session.verifySession();
_facebook   = _session.facebook;

Chamando um dos métodos e tratando a informação:

/**
* Chamada para recuperar todos os amigos do usuário
*/

private function _getFriends () : void
{
var _getFriendsCall : FacebookCall  = _facebook.post(new GetFriends(null, _user));
_getFriendsCall.addEventListener(FacebookEvent.COMPLETE, _getFriendsComplete, false, 0, true);
}

/**
* Recupera os ids dos amigos do usuário e dispara a chamada para buscar as informações dos usuários
*/

private function _getFriendsComplete(e:FacebookEvent):void
{
e.currentTarget.removeEventListener(FacebookEvent.COMPLETE, arguments.callee, false);
var friends : FacebookUserCollection    = GetFriendsData(e.data).friends || new FacebookUserCollection();
var i       : int   = friends.length;
var aFriends: Array = [].concat();

while (i--)
{
aFriends.push(FacebookUser(friends.getItemAt(i)).uid);
}

_toCollection(aFriends);
}

/**
* Busca os detalhes selecionados de todos os amigos do usuário
*/

private function _toCollection (aUids : Array = null) : void
{
var columns : Array         = [GetInfoFieldValues.NAME, GetInfoFieldValues.PIC_SQUARE, GetInfoFieldValues.PIC];
var info    : FacebookCall  = _facebook.post(new GetInfo(aUids, columns));
info.addEventListener(FacebookEvent.COMPLETE, _createCollection, false, 0, true);
}

/**
* Armazena numa collection as informações dos amigos do usuário
*/

private function _createCollection(e:FacebookEvent):void
{
e.currentTarget.removeEventListener(FacebookEvent.COMPLETE, arguments.callee, false);
_userCollection = GetInfoData(e.data).userCollection;
//trace(FacebookUser(_userCollection.getItemAt(0)).name)
}

Acho que com isso já fica mais fácil começar a desenvolver seus aplicativos, daí é possível se aprofundar mais estudando a documentação da API do Facebook e da biblioteca AS3.

Ps.: Se você usou este post para começar sua aplicação, deixe o link nos comentários!

Categories: ActionScript, Work Tags: ,

Outlander GT

October 28th, 2009 No comments

www.outlandergt.com.br

Abertura

Home

Votação

Features

TECNOLOGIAS:

AS3, Flash Remoting.

FICHA TÉCNICA INTERNET:
Agência: Africa
Anunciante: Mitsubishi Motors do Brasil
Produto: Mitsubishi Outlander GT
Criação: Humberto Fernandez/Flavio Waitman/Daniel Matsumoto
Diretores de Criação: Nizan Guanaes/Sergio Gordilho/Cassio Zanatta/Humberto Fernandez/Flavio Waitman
Atendimento: Marcio Santoro/ Carolina Barreto/ Veridiana Gerbasi
Mídia: Luiz Fernando Vieira/Fábio Freitas /Eduardo Shinohara / Wagner Torreti
Planejamento: Pedro Cruz/Márcia Neri
Art Buyer: Andrea Mancini
Fotógrafo: Leonardo Vilela / Platinum
Produção: Platinum
Aprovação/cliente: Corinna de Souza Ramos, Renata de Souza Ramos e Letícia Mesquita

Produção: Juice Comunicação Concentrada
Direção Geral: Fábio Pinho
Direção de Criação: Bernardo Annechino
Design: Raul Queiroz
Arte 3D: Alexej Tykac
Animação: Raul Queiroz/Vladimir Andrade/Ruy Chagas Jr
Redação: Natasha Szczerb, Bernardo Annechino
Desenvolvimento Action Script: Bruno “Tatuí” Ribeiro
Desenvolvimento Server Side: Leandro Carneiro
Desenvolvimento Client Side: Thiago Velloso
Atendimento: Larissa Raposo

Categories: ActionScript, Work Tags: , ,

Respondendo ao analytics

August 1st, 2009 1 comment

Olhando os dados do Google analytics resolvi escrever um post respondendo as palavras-chave que trouxeram pessoas pro meu blog.

Como salvar o Bitmap de um MovieClip com ActionScript 3? (actionscript 3 salvar bitmap de um movie clip)

Não tenho certeza se entendi o que queriam dizer, mas vou colocar duas possibilidades

  • Como copiar o conteúdo de um MovieClip para um Bitmap:

<br />
var bmpdata: BitmapData = new BitmapData(mcOriginal.width, mcOriginal.height, false);<br />
bmpdata.draw(mcOriginal, null, null, null, null, true);<br />
var bmpCopy : Bitmap = new Bitmap(bmpdata, "auto", true);<br />

  • Como enviar isso para o cliente:

<br />
var jpgSource   : BitmapData    = new BitmapData (mcImg.width, mcImg.height);<br />
jpgSource.draw(mcImg, null, null, null, null, true);</p>
<p>var jpgEncoder:JPGEncoder = new JPGEncoder(100);<br />
var jpgStream:ByteArray = jpgEncoder.encode(jpgSource);</p>
<p>var header:URLRequestHeader = new URLRequestHeader("Content-type", "application/octet-stream");<br />
var jpgURLRequest:URLRequest = new URLRequest("download.php?name=img.jpg");<br />
jpgURLRequest.requestHeaders.push(header);<br />
jpgURLRequest.method = URLRequestMethod.POST;<br />
jpgURLRequest.data = jpgStream;<br />
navigateToURL(jpgURLRequest, "_self");<br />

Dessa forma você também pode salvar no servidor. Existe também um jeito mais simples de forçar o download da imagem usando o método download da classe FileReference.

Como carregar imagens  e deixar em cache?

Em alguns casos, o que eu acho mais simples é criar um Vector ou Array com as imagens que preciso e depois é só consultar o Array.

Como aumentar a performance do TweenLite?

Você pode tentar otimizar a engine, mas uma dica é evitar o uso de muitos tweens ao mesmo tempo.

Como me graduar sem estudar?

Ok, essa eu não sei responder.

Como conversar com programador?

Isso pode ser muito complicado, mas tente ser direto, lógico e falar apenas quando necessário, isso ajuda.

Qual a diferença entre public e private no AS3?

  • public: Pode ser acessado por qualquer classe;
  • private: Classes filhas podem acessar;
  • internal: Classes do mesmo pacote podem acessar;
  • protected: Classes filhas podem acessar e compartilhar;

Como jogar um MovieClip pra frente usando AS3?

<br />
setChildIndex(mc,numChildren-1);<br />

Sou graduando, colocar isso no curriculum?

Simples, diga qual o curso e o status (em curso).

Quem é Alexej Tykac?

Alexej é o responsável pelo 3D dos projetos online da Mitsubishi Motors e atualmente trabalha na Juice Comunicação (RJ).

E só pra fechar, a mais estranha; Devo ou não contar que gosto dele?

E por que não? Vai lá, conte sim!

devo ou não contar que gosto dele?

Vanishing point

May 9th, 2009 No comments

Quando comecei a tentar fazer as coisas com o 3D nativo do Flash achei que seria uma boa idéia, mas com o passar do tempo algumas questões começaram a aparecer e percebi que existem alguns detalhes que realmente tem muito a melhorar.

Apesar disso, em alguns projetos onde o 3D é mais simples e com poucas animações e interatividade, tenho optado pelo 3D nativo. Nesses projetos, acabei me deparando com algumas situações e as saídas podem ser úteis para outras pessoas, o problema mais recente que tive foi com relação ao vanishing point (ponto de fuga) então vamos lá.

Nesse primeiro código estou apenas criando um MovieClip, posicionando no centro do stage e rotacionando no eixo Y, sem definir nada mais.

var _plane : MovieClip	= addChild(new MovieClip()) as MovieClip;
_plane.graphics.beginFill(0x000000);
_plane.graphics.drawRect(0, 0, 200, 100);
_plane.graphics.endFill();	

_plane.x		= (stage.stageWidth - _plane.width) * .5;
_plane.y		= (stage.stageHeight - _plane.height) * .5;
_plane.rotationY 	=  -60;

E o resultado é esse:

img_3d_11

 

Você pode usar o código abaixo e definir o vanishing point que desejar.

import flash.geom.PerspectiveProjection;
import flash.geom.Point;

var _plane		= addChild(new MovieClip()) as MovieClip;
_plane.graphics.beginFill(0x000000);
_plane.graphics.drawRect(0, 0, 200, 100);
_plane.graphics.endFill();	

_plane.x		= (stage.stageWidth - _plane.width) * .5;
_plane.y		= (stage.stageHeight - _plane.height) * .5;
_plane.rotationY 	=  -60;

var _vp : PerspectiveProjection 	= new PerspectiveProjection();
_vp.projectionCenter			= new Point(505, 285);
_plane.transform.perspectiveProjection  = _vp;

Tendo como resultado:

img_3d_3

 

Caso você tenha algum objeto no stage com alguma transformação 3D o vanishing point dele se torna o padrão para os demais objetos, logo, se você não definir nada no seu código, o resultado poderia ser algo do tipo:

img_3d_2

Daí vem algumas questões; Posso ter vanishing point distinto para n Objetos?; Se um Display Object estiver dentro de um outro Display Object, qual será o ponto de referência do filho?

Vamos por partes, primeiro sobre distintos vanishing points. Diretamente na timeline eu não consegui – o que não quer dizer que seja impossível – criar pontos distintos para os objetos que sofreram transformação 3D, porém, via código isso é possível.

 

import flash.geom.PerspectiveProjection;
import flash.geom.Point;

var _vp : PerspectiveProjection = new PerspectiveProjection();

/** Primeiro plano **/
var _plane			= addChild(new MovieClip()) as MovieClip;
_plane.graphics.beginFill(0x000000);
_plane.graphics.drawRect(0, 0, 200, 100);
_plane.graphics.endFill();	

_plane.x		= (stage.stageWidth - _plane.width) * .5;
_plane.y		= 20;
_plane.rotationY 	=  -60;

_vp.projectionCenter 	= new Point(505, 285);
_plane.transform.perspectiveProjection = _vp;

/** Segundo plano **/
var _plane2		= addChild(new MovieClip()) as MovieClip;
_plane2.graphics.beginFill(0x000000);
_plane2.graphics.drawRect(0, 0, 200, 100);
_plane2.graphics.endFill();	

_plane2.x		= (stage.stageWidth - _plane.width) * .5;
_plane2.y		= 140;
_plane2.rotationY 	=  -60;

_vp.projectionCenter 	= new Point(105, 285);
_plane2.transform.perspectiveProjection = _vp;

Que resulta em: 

img_3d_4

Sobre a relatividade do vanishing point, se você tiver um MovieClip com transformação 3D no root e outro dentro de um container, o ponto é o mesmo e sempre com relação ao stage. 

Na imagem abaixo existem 2 MovieClips, o mais claro está no root e o mais escuro está dentro de um container na posição 600, 350 e seu container foi alinhado para ficar lado a lado com o primeiro MovieClip (o mais claro). Perceba que mesmo o MovieClip filho estando na posição 600, 350 de seu container,  o que vale de fato para o Flash é onde no stage ele se encontra. 

img_3d_5

 

Categories: ActionScript, Work Tags: ,

Felicidade Interna Bruta – Proposta

May 2nd, 2009 No comments
Felicidade Interna Bruta - Proposta    

Felicidade Interna Bruta - Proposta

Categories: ActionScript, Work Tags: , ,

Puzzle em AS3

February 2nd, 2009 No comments

Um bom costume para programadores em geral, é buscar alguns desafios e tentar executá-los. Não necessariamente você precisa buscar algo extremamente complexo, só o fato de fazer algo já é um exercício e sempre positivo.

Há algumas semanas me pediram para criar um Puzzle, eu nunca havia criado um e fiquei imaginando como poderia para fazer isso. No caso existia a limitação do Flash Player, era necessário publicar no máximo, na versão 6.

Depois de entregue, resolvi portar para o AS3 e publicar aqui uma versão reduzida do código. Abaixo você pode vê-lo rodando.

The Flash plugin is required to view this object.

Como já havia um layout definido para as peças do puzzle, eu as aproveitei. Como o foco nesse caso não é a estrutura do Fla, vamos direto pro código.

 

package
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.DisplayObject;
import flash.display.Loader;
import flash.display.MovieClip;

import flash.geom.Point;
import flash.geom.Rectangle;
import flash.geom.Matrix;

import flash.events.MouseEvent;
import flash.events.Event;

import flash.net.URLRequest;

/**
* ...
* @author Bruno Ribeiro
* @link 	www.brunoribeiro.net
* @email 	contato@brunoribeiro.net
*/
public class Main extends MovieClip
{
private var _url			: URLRequest;
private var _loader			: Loader;

private var _bmp			: BitmapData;
private var _mcImg			: MovieClip;
private var _currentPiece 	: DisplayObject;

private var _item			: int;
private var _inPosition		: int;

public function Main()
{
_loadImage();
}

/**
* Carrega a imagem
*/
private function _loadImage() : void
{
_url	= new URLRequest("http://www.brunoribeiro.net/blog/img/imgBase.jpg");
_loader	= new Loader();
_mcImg	= addChildAt(new MovieClip(), 0) as MovieClip;

_loader.load(_url);

_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, _init, false, 0, true);
stage.addEventListener(MouseEvent.MOUSE_UP, _handlerRelease, false, 0, true);
}

/**
* Monta o quebra-cabeça
* @param	e
*/
private function _init ( e : Event ) : void
{
_mcImg.addChild(_loader.content) as MovieClip;
var i 			: int = 0;
var j 			: int;
var bmp_temp 	: BitmapData;
var mc 			: MovieClip;
var target 		: MovieClip;

/**
* Pega o bitmapdata da imagem base
*/
_bmp = new BitmapData(_mcImg.width, _mcImg.height, true);
_bmp.draw(_mcImg, new Matrix());

for(i; i < 5; i++)
{
for( j =0; j <6; j++)
{
_item++;

mc 		= getChildByName("mc_" + i + "" + j) as MovieClip;
target 	= mc.mcTarget as MovieClip;

/**
* Cropa o trecho da imagem que importa
* A mascara já estava definida na timeline que recebi
*/
bmp_temp = new BitmapData(mc.width, mc.height, true);
bmp_temp.copyPixels(_bmp, new Rectangle(mc.x, mc.y, mc.width, mc.height), new Point(0, 0));

/**
* Adiciona a imagem ao target
*/
target.addChild(new Bitmap(bmp_temp));

/**
* Guarda a posição inicial para usar depois no hit
*/
mc.posX 	= mc.x;
mc.posY 	= mc.y;

/**
* Adiciona Listeners para o drag'n drop
*/
mc.addEventListener(MouseEvent.MOUSE_DOWN, _handlerClick, false, 0, true);
mc.addEventListener(MouseEvent.MOUSE_UP , _handlerRelease, false, 0, true);
}
}

/**
* Ao final troca a profundidade da imagem base
* reduz o alpha
* reposiciona as peças
*/
_mcImg.alpha = .3;
swapChildren(_mcImg, MovieClip(getChildByName("mc_00")));
_posicionaAleatorio();
}

/**
* Quando o usuário solta a peça
* Para o drag e verifica o posicionamento,
* se estiver dentro da área aceitável para
* o hit, a peça assume a posição correta
*
* @param	e
*/
private function _handlerRelease(e:MouseEvent):void
{
/**
* Trata o releaseOutside
* caso o release não seja feito na peça
* eu removo o drag do objeto corrente
*/
var obj : MovieClip = e.currentTarget as MovieClip;
if (obj == null)
{
obj = _currentPiece as MovieClip;
}

obj.stopDrag();

/**
* Teste do hit
* Você pode aumentar/reduzir a sensibilidade
* modificando o valor 10
*/
if (obj.x >= (obj.posX - 10) && obj.x <= (obj.posX + 10))
{
if (obj.y >= (obj.posY - 10) && obj.y <= (obj.posY + 10))
{
obj.x = obj.posX;
obj.y = obj.posY;

obj.removeEventListener(MouseEvent.MOUSE_DOWN, _handlerClick, false);
obj.removeEventListener(MouseEvent.MOUSE_UP, _handlerRelease, false);

/**
* Adiciona 1 nos itens que estão em posicão
* e verifica se era a última peça
* em caso positivo, game over
*/
_inPosition++;
if(_inPosition == _item)
{
trace('game over');
}
}
}
}

/**
* No click, inicia o drag da peça
* @param	e
*/
private function _handlerClick(e:MouseEvent):void
{
MovieClip(e.currentTarget).startDrag(false, new Rectangle(0, 0, stage.stageWidth, stage.stageHeight));
_currentPiece  = e.currentTarget as DisplayObject;
}

/**
* joga as peças para a parte de baixo, onde você pode manipulá-las
* o posicionamento é aleatório
*/
private function _posicionaAleatorio () : void
{
var i : int = 0;
var j : int = 0;
for (i; i < 5; i++)
{
for (j = 0; j < 6; j++)
{
var mc : MovieClip = getChildByName("mc_" + i + "" + j) as MovieClip;
mc.x = randRange(0, (stage.stageWidth - mc.width));
mc.y = randRange(440, (stage.stageHeight - mc.height));
}
}
}

/**
* Gera número aleatório dentro de um ranger
* @param	min
* @param	max
* @return
*/
function randRange(min:Number, max:Number):Number
{
var randomNum:Number = Math.floor(Math.random() * (max - min + 1)) + min;
return randomNum;
}
}
}

Essa talvez seja a forma mais fácil de fazer o puzzle com as peças em formato curvilíneo.

[UPDATE]

Esse post deveria ter sido publicado há 4 meses, no entanto, mais uma vez o WP me enganou.

Categories: ActionScript Tags: ,