terça-feira, 23 de março de 2010

Criando menu 3d no flash

Olá a todos. Veremos aqui como criar um menu circular em 3D personalizável. Utilizaremos alguns truques de matemática para simular a rotação em profundidade. Nada complicado. Mesmo quem não é fera em assuntos de cálculo conseguirá acompanhar o tutorial normalmente e projetar o menu como explicado.
Existem muitos menus na web com efeitos similares a esse, como por exemplo o site:
http://www.square-enix.co.jp/dvd/ff7ac/
[na parte de trailers]
Essa URL foi submetida por um internauta ansioso em saber como se criava tal efeito. Em 3 passos seguintes, será mostrado como fazer algo similar.
Agenda (passos):
01. Introdução (esta página)
02. Criando o ambiente em Flash
03. Mecânica circular
04. Criando o ActionScript
2º Passo: Criando o ambiente em Flash
2.1. Abra um novo arquivo com tamanho de projeto: 400 x 500
2.2. Crie botões para cada item de menu:
Veja que apenas coloquei um retângulo vermelho transparente no estado OVER do botão para dar efeito de destaque na foto. Para esse exemplo, criei 5 botões, embora você possa criar quantos quiser. O ActionScript se adapta ao número de botões.
2.3. Converta cada botão em um clipe de filme: selecione cada botão e aperte F8 para convertê-lo em um clipe de filme. Observe o ponto de registro:
2.4. Nomeie cada clipe recém criado no painel de propriedades
Nesse exemplo as instâncias receberam os nomes:
- embaixada
- goleiro
- disputa
- bola
- meiao
3º Passo: Mecânica Circular
Para criarmos o efeito ilusório em 3D de que o menu está girando e entrando em profundidade, iremos calcular as posições, transparências e tamanhos para cada botão do menu (encapsulado no respectivo clipe de filme). Podemos utilizar, da trigonometria, as funções para sabermos as posições X e Y em uma circunferência baseadas em um ângulo qualquer.
Para calcular as posições x e y do menu 1 por exemplo, temos:
x = cos * raio
y = sen * raio
Nesse caso, o Y realmente corresponderá a altura, entretanto o X não corresponderá a posição horizontal do menu, visto que na horizontal, todos os menus estarão na mesma posição. O que muda, para cada menu, é sua altura (Y) e a profundidade (mais perto do observador ou mais distante). Nada nos impede em converter o X calculado em Z (profundidade), é apenas uma outra forma de enxergar a fórmula.
Então, utilizaremos o X da equação para calcular o tamanho do menu (quanto menor, mais distante) e sua transparência (quanto mais transparente, mais distante).
É importante observar que cada botão de menu terá seu próprio ângulo, caso contrário, todos os botões estariam girando juntos na mesma posição.
Para podermos personalizar o menu, são criadas variáveis para regular toda a roda, como: valor do raio, transparência do item mais distante, transparência do item mais próximo, tamanho do item mais distante, tamanho do item mais próximo etc.
Para o giro, contamos com o deslocamento do mouse para cima e para baixo. Entretanto existe uma área de segurança no centro em que o mouse não rodará os menus para o usuário poder operar no botão com mais tranqüilidade.
Podemos agora olhar o código em ActionScript.
4º Passo: Criando o ActionScript
4.1. O seguinte trecho de código é colocado no primeiro quadro da linha de tempo principal
4.2. Para controlar a animação é utilizado o disparo freqüente do evento onEnterFrame da linha de tempo principal.
/*******************************************/
// variavies de configuracao
/*******************************************/
// guardar as instancias a serem rotacionadas em um vetor
var clips = Array("goleiro", "meiao", "disputa", "bola", "embaixada");
var raio = 150;  // raio de rotacao
var aceleracao = 0.05; // aceleracao do mouse para o giro
var alphaMinimo = 20; // transparencia do botao de menu mais distante
var alphaMaximo = 70; // transparencia do botao de menu mais proximo
var escalaMinima = 50; // tamanho do botao de menu mais distante
var escalaMaxima = 100; // tamanho do botao de menu mais distante
var mouseSeguro = 100; // pixels em torno do centro nos quais o
// mouse nao gira o menu

       
/*******************************************/
// Variaveis calculadas
/*******************************************/
// variacao da transparencia
var difAlpha = alphaMaximo - alphaMinimo;
// variacao do tamanho
var difEscala = escalaMaxima - escalaMinima;

// posicao central do menu em X e Y
var xIni = Stage.width / 2;
var yIni = Stage.height / 2;

var dobroRaio = raio * 2;
var conversao = Math.PI / 180;
// fator de conversao de angulo para radiano
var difAngular = 360 / clips.length;
// diferenca angular entre os itens de menu

var angulo = 0;  // angulo inicial da roda como um todo



/*******************************************/
// funcoes
/*******************************************/

// funcao para determinar as posicoes X e Y
// de um menu em funcao do angulo e do raio
function posCircular(angulo, raio)
{
 var pos = new Object();
 var rad = angulo * conversao;
 pos.x = Math.sin(rad) * raio;
 pos.y = Math.cos(rad) * raio;
 
 return pos;
}

// funcao para ser chamada na mesma frequencia da animacao
// e que eh responsavel por girar o menu
this.onEnterFrame = function  () {
 // calculamos se o mouse esta fora da area central
 // e com que velocidade o menu ira girar
 velocidade = (_root._ymouse - yIni)
 if (Math.abs(velocidade) <= mouseSeguro)
  velocidade = 0;
 else
  velocidade *= aceleracao;
 
 // giramos o menu todo
 angulo += velocidade;
 
 // reposicionamos cada item do menu
 for (i = 0; i < clips.length; i++)
 {
  // criar alias para o clipe de filme atual
  var ptr = _root[clips[i]];
  
  // alterar posicao horizontal do menu
  ptr._x = xIni;
  
  // calcular a diferenca angular desse menu
  // em relacao a origem da roda
  ptr.difAngular = difAngular * i;
  
  // buscar as posicoes X (profundidade) e Y (altura) do menu
  var pos = posCircular(angulo + ptr.difAngular, raio);
  ptr._y = yIni + pos.y;
  
  // calcular percentual de afastamento do menu
  // para alterar seu tamanho e transparencia
  var perc = (pos.x + raio) / dobroRaio;
  ptr._alpha = perc * difAlpha + alphaMinimo;
  ptr._xscale = ptr._yscale = perc * difEscala + escalaMinima;
  
  // colocar o menu acima dos que estao mais afastados
  ptr.swapDepths(pos.x + dobroRaio);
 }
}

 

por: Thiago dos Santos Prado

Nenhum comentário:

Postar um comentário