Archive for the ‘ AS3 ’ Category

Video full screen en flash

La semana pasada tuve un par de trabajos en los que requeria utilizar un video de flash como fondo y arriba de eso un sitio html puro. Asi que la idea de este mini tutorial es mostrar lo facil que es hacer que el video en flash tome el 100 porciento de la pantalla y se redimencione cuando se cambia el tamano de la pantalla.

1
2
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;

Con la primer linea especificamos que el tamano de la aplicacion flash tiene que se fija y que se mantiene fija incluso si cambia el tamano del explorador.
La segunda linea especifica que el escenario este alineado en la esquina superior izquierda.

1
2
3
var _netCon :NetConnection = null;
var _netStr :NetStream = null;
var _video :Video = null;

NetConnection es un objecto que podemos describir como un tubo entre el cliente y el servidor.

La clase Video muestra un video en la aplicacion sin incrustarlo en el swf. Digamos lo reproduce en un contenedor mediante streaming.

1
2
3
4
5
function SetupNetConnection() {
 _netCon = new NetConnection();
 _netCon.addEventListener(NetStatusEvent.NET_STATUS, NetStatus, false, 0, true);
 _netCon.connect(null);
}

Bueno, yahemso creado la conexion y agredado un listener que monitorea el estado de la conexion. el argumento null significa que no estamos conectando a un Flash media server sino que hacemos streaming de un archivo que reside en un servidor normal.

Ahora vamos a crear el stream que vamos a usar par ver el video mediante el objeto NetConnection y vamos a escuchar su estado mediante listener de ese mismo objeto.

1
2
3
4
5
6
7
8
9
10
11
12
function SetupNetStream() {
 var $customClient:Object = new Object();
$customClient.onMetaData = onMetaData;
_netStr = new NetStream(_netCon);
 _netStr.client = $customClient;
_netStr.addEventListener(NetStatusEvent.NET_STATUS, NetStatus, false, 0, true);
_video = new Video();
 _video.attachNetStream(_netStr);
 _video.smoothing = false;
 addChild(_video);
_netStr.play("video.flv");
 }

La funcion onMetaData va ser llamada tan pronto como el objeto NetStream obtenga informacion del archivo FLV.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 
function onMetaData($info:Object):void {
 
}
 
function NetStatus($e:NetStatusEvent) {
 
switch ($e.info.code)   {
 
case "NetConnection.Connect.Success":
SetupNetStream();
break;
 
case "NetStream.Play.Stop":
_netStr.seek(0);
 }
}
 
 
 
function ResizeAndPosition($e:Event):void
{
_video.width = stage.stageWidth;
_video.height = stage.stageHeight;
}
 
stage.addEventListener(Event.RESIZE, ResizeAndPosition, false, 0, true);
 
ResizeAndPosition(null); 
 
SetupNetConnection();

Y el HTML que contrendria el player sería el siguiente:

1
2
3
4
<!--
*{ margin:0; padding:0; }
-->
<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="100%" height="100%" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="src" value="source.swf" /><embed type="application/x-shockwave-flash" width="100%" height="100%" src="source.swf"></embed></object>

Detectar dirección y rotación

Ayer estuvimos discutiendo con Eduardo un poco sobre su tutorial para detectar la dirección y la rotación en Flash. Su comienzo esta muy bien pero analizamos que tenía un par de fallas. Además él también nombró que le gustaría animar el traslado del avion para que no sea tan brusco, a esto lo realizaremos usando una clase para tweeners.

La primera en realidad no es una falla, sino más bien el deseo que el avión gire hacia la dirección de traslado, lo cual trae un nuevo problema que es hacia donde gira. Por defecto si en Flash sólo se usa rotación el giro que efectúa es en sentido horario, por lo cual a veces esto puede ser muy raro cuando es más rápido girar hacia el otro lado. Hay varias formas de detectar ésto y la que discutíamos es simplemente detectar el angulo de rotación actual restarle 360 y listo. Pero mientras discutiamos con Eduardo que formula utilizar encontré un propiedad/plugin dentro de la clase Tweenmax que no sólo te hace la rotación al ángulo deseado sino que también detecta hacia donde es el giro más corto.

1
TweenMax.to(avion_mc, 0.5, {shortRotation:{rotation:270}});

Con shortRotation nos evitamos tener que hacer el calculo nosotros y decide hacer el giro en sentido horario o antihorario según cual sea más corto

Ahora el otro problema es que cuando movemos el mouse no lo hacemos en un movimiento perfecto hacia arriba o abajo o hacia los laterales, en realidad siempre existen una componente hacia arriba, abajo o laterales . una especie de ruido.
Para solucionar este problema empecé por detectar manualmente en donde se encuentra el mouse y hacia donde se mueve. Luego hago los cambios de giro solamente cuando el movimiento es 100% hacia los costados o 100% hacia arriba o abajo. De esta forma se evita que haya pequeño intentos de cambiar el gira cuando en realidad es sólo ruido.

El código completo es el siguiente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import com.greensock.*;
import com.greensock.easing.*;
 
function Start()
{
stage.addEventListener(MouseEvent.MOUSE_MOVE, CheckDirection);
}
 
Start();
 
var prevX = 0;
var prevY = 0;
var curX = 0;
var curY = 0;
var dirX:String = "";
var dirY:String = "";
 
function CheckDirection(e:MouseEvent)
{
var dirHorizontal:String = obtenerDireccionHorizontal();
var dirVertical:String = obtenerDireccionVertical();
trace("movimiento en X : " + dirHorizontal + ", movimiento en Y : " + dirVertical);
TweenMax.to(avion_mc, 1, { x:mouseX,y:mouseY});
hacerGiro(dirHorizontal,dirVertical);
e.updateAfterEvent();
}
 
function hacerGiro(dirHorizontal,dirVertical)
{
if (dirHorizontal == 'derecha' && dirVertical == 'none')
{
TweenMax.to(avion_mc, 0.5, {shortRotation:{rotation:90}});
}
else if (dirHorizontal=='izquierda' && dirVertical == 'none')
{
TweenMax.to(avion_mc, 0.5, {shortRotation:{rotation:270}});
}
if (dirVertical == 'arriba' && dirHorizontal == 'none')
{
TweenMax.to(avion_mc, 0.5, {shortRotation:{rotation:0}});
}
else if (dirVertical=='abajo' && dirHorizontal == 'none')
{
TweenMax.to(avion_mc, 0.5, {shortRotation:{rotation:180}});
}
}
 
function obtenerDireccionHorizontal():String
{
 
prevX = curX;
curX = stage.mouseX;
 
if (prevX > curX)
{
dirX = "izquierda";
}
else if (prevX < curX)
{
dirX = "derecha";
}
else
{
dirX = "none";
}
return dirX;
}
 
function obtenerDireccionVertical():String
{
prevY = curY;
curY = stage.mouseY;
if (prevY > curY)
{
dirY = "arriba";
}
else if (prevY < curY)
{
dirY = "abajo";
}
else
{
dirY = "none";
}
return dirY;
}

Para que les funcione tienen que bajar la clase tweenMax para AS3 desde: http://www.tweenmax.com

Acá el ejemplo funcionando:

Esto requiero Flash player 9

noten que cambié la resolución a la misma resolución del iPhone, el próximo post será como portar esto a una aplicación de iPhone.

Detectar dirección con ActionScrip 2

Si lo que intentan es detectar hacia que dirección va el cursor del mouse utilizando ActionScript2, les recomiendo utilizar un método que poco conocía que es nativo de Flash, su nombre es “watch“. Esta función analizar una variable y devuelve dos valores uno nuevo “newVal” y otro viejo “oldVal“,  lo cual nos facilita el trabajo si tenemos que desarrollar una pelicula que detecte si el mouse va hacia la derecha o hacia izquierda, arriba o abajo, este método es muy interesante ya que nos permitiría saber si los valores en x e y se incrementan o disminuye lo cual con un simple if podríamos saber hacia donde se dirige el cursor. Esta función también puede servir para activar alertas, cuando una variable cambia, se analiza con watch y cuando se cumple una condición se activa una alarma, se ejecuta una función o simplemente se activa una animación.

Esto también se puede hacer con listeners, pero es mas complejo ya que hay que armar la función que permite comparar el valor viejo con el valor nuevo de la variable mientras cambia. No les aconsejo utilizar onEnterFrame ya que consume muchos recursos.

Ejempo:

Esto requiero Flash player 9

Codigo:

Mouse.hide();
posX = function (dx, oldVal, newVal) {
    if (oldValnewVal) {
        trace("Izquierda");
        avion_mc._rotation = -90;
    }
    return newVal;
};
posY = function (dy, oldVal, newVal) {
    if (oldValnewVal) {
        trace("rriba");
        avion_mc._rotation = 360;
    }
    return newVal;
};
 
this.watch("dirx",posX);
this.watch("diry",posY);
 
this.onMouseMove = function() {
    avion_mc._x = _xmouse;
    avion_mc._y = _ymouse;
    dirx = _xmouse;
    diry = _ymouse;
 
};

Para los que estan trabajando con As3, el método watch no existe mas, por lo cual les dejo una solución AQUI

Clase:

package
{
   import flash.events.Event;
   import flash.events.EventDispatcher;
   public class Model extends EventDispatcher
   {
       public static const VALUE_CHANGED:String = 'value_changed';
       private var _number:Number = Number;
       public function Model():void
       {
           trace('The model was instantiated.');
       }
       public function set number(newNb:Number):void
       {
          _number=newNb;
          this.dispatchEvent(new Event(Model.VALUE_CHANGED));
       }
       public function get number():Number
      {
          return _number;
 
      }
   }
}

Modo de uso:

var objectToWatch:Model = new Model();
objectToWatch.addEventListener(Model.VALUE_CHANGED, onValuedChanged);
 
function onValuedChanged(e:Event) {
   //do what you need here
}

Espero que les sea útil, la próxima me gustaría completar la pelicula de arriba con algo de trigonometría para simular 100% la dirección.

Un sonido luego de otro

El año pasado hice un trabajo donde se necesitaba que se reproducieran unas imágenes y al mismo tiempo se escuchara una voz en voz describiendo la imagen.
El tema que eran varia galerías que eran cambiadas dinámicamente por lo que se requería que ésta pseudo película se generara en tiempo de ejecución.
El tema estaba en precargar todas las imágenes y todas los sonidos para que no haya pausas entre imagen e imagen.
Precargar la imágenes es relativamente facil ya que podes cargarlas usando un loadClip ya que son guardadas automáticamente en el caché.
El tema son los sonidos, como asegurarse que los sonidos son precargados de forma que no haya pausas. Hay un par de formas de hacerlo la que me resultó más práctica a mi fue:

La forma normal sería, manual y estática sería:

import flash.media.Sound;
import flash.media.SoundChannel;
 
var mySoundOne:Sound = new SoundOne();
var mySoundTwo:Sound = new SoundTwo();
var mySoundThree:Sound = new SoundThree();
 
var mySoundChannel:SoundChannel = mySoundOne.play();
mySoundChannel.addEventListener(Event.SOUND_COMPLETE, sound_1_Complete);
 
var mySoundChannel2:SoundChannel;
var mySoundChannel3:SoundChannel;
 
function sound_1_Complete(event:Event):void {
    trace("one complete");
    mySoundChannel2 = mySoundTwo.play();
    mySoundChannel2.addEventListener(Event.SOUND_COMPLETE, sound_2_Complete);
}
 
function sound_2_Complete(event:Event):void {
    trace("two complete");
    mySoundChannel3 = mySoundThree.play();
    mySoundChannel3.addEventListener(Event.SOUND_COMPLETE, sound_3_Complete);
}
 
function sound_3_Complete(event:Event):void {
    trace("three complete");
}

Hasta acá todo fácil, lo que fue una novedad para mi es que es posible meter objetos dentro de arrays, por lo que cree un array con sonidos (objetos) adentro y fui cargando un sonido después del otro, de forma que era automatizado, dinámico y que podía ser cambiado en tiempo de ejecución sin problemas.

var sounds:Array = [new SoundOne(), new SoundTwo(), new SoundThree()];
 
var channels:Array;
 
channels[0] = Sound(sounds[0]).play();
 
SoundChannel(channel[0]).addEventListener(Event.SOUND_COMPLETE, playNext);
 
function playNext(e:Event):void
 
{
 
var index:Number = channels.indexOf(e.currentTarget);
 
trace("played sound " + (index + 1));
 
if(index &lt; sounds.lenth - 1)
 
{
 
index++;
 
channels[index] = Sound(sounds[index]).play();
 
SoundChannel(channels[index]).addEventListener(Event.SOUND_COMPLETE, playNext);
 
}
 
}
sounds.push(new SoundFour()); // sólo habría que asegurarse de llamar a esto antes que el sonido cuatro termine de reproducirse

Animando huesos con AS3 (bones y actionscript 3)

Éste tutorial es para dar una idea básica de lo que se puede hacer con los huesos y la cinemática inversa. Lo interesante es poder mover éstos huesos por código y así reaccionar en runtime de acuerdo a posición del mouse, ingreso del teclado o como abarca éste tutorial a la música.
Ejemplo final:

Esto requiero Flash player 9

Lo primero es elegir un objeto que querramos animar, en mi caso la mascota de Homestar Runner, que lo peuden bajar de brandsoftheworld. Luego tenemos que convertir en movieclips cada sección de nuestro objeto, por ejemplo: la cabeza, el tronco, la pierna derecha, la pierna izquierda.
Luego elegimos la herramienta “bones” (x) y empezamos a unir nuestros objetos.

Luego seleccionamos el frame que contiene nuestros moviclips unidos por los huesos que creamos y veremos que en el panel propiedades aparece el nombre del esqueleto que acabamos de crear. Ahí podemos darle un nuevo nombre a todo nuestro esqueleto, yo voy a utilizar el que me tocó por defecto.

Es importante que seleccionar el frame y no el moviclip ya que si seleccionamos un moviclip accedemos a las propiedades del hueso en sí pero no del esqueleto completo.

También es importante cambiar y el Type de authotime a runtime, lo que hace que los huesos se van a animen en tiempo de ejecución en vez de ser animados con tween o cuadro por cuadro dentro de Flash. Luego de tener el nombre del esqueleto si pasamos a seleccionar los huesos que queremos mover y le damos nombres, también en ésta parte podemos ajustar los ángulos que vamos a permitir que se mueva y varias otras propiedades, yo no cambié nada pero los resultados pueden variar.

Por último la parte del código.
Básicamente lo que tenemos que hacer es registrar el esqueleto y luego ligar a éste esqueleto los huesos que a su vez tienen dos puntos por lo cual tenemos que decir cual de dichos puntos queremos mover y lo podemos hacer en cualquier eje: x,y o z. El registro del esqueleto se hace una vez, y luego tenemos decidir cuantos huesos se van a mover.
En este caso lo que voy a hacer es cargar un sonido, analizar su espectro y mover el pie izquierdo con lo que haya en el canal izquierdo de la música y luego lo mismo con el derecho.

var tree:IKArmature = IKManager.getArmatureByName("Armature_5");
var right_leg:IKBone = tree.getBoneByName("ikBoneName9");
var left_leg:IKBone = tree.getBoneByName("ikBoneName10");
var cabeza:IKBone = tree.getBoneByName("ikNode_6");
 
// tailJoint mueve e punto del hueso, si queremos mover la cabeza del hueso debemos usar headJoint
 
//para la pierna derecha
var rtJ:IKJoint = right_leg.tailJoint;
var rposT: Point=rtJ.position;
var rikMover:IKMover = new IKMover(rtJ, rposT);
 
//para la pierna izquiera
var ltJ:IKJoint = left_leg.tailJoint;
var lposT: Point=ltJ.position;
var likMover:IKMover = new IKMover(ltJ,lposT);
 
// cargo un sonido para analizar su espectro y mover los huesos según éste.
var s:Sound = new Sound();
s.load(new URLRequest("http://digilabs.com.ar/wp-content/uploads/2010/06/loop.mp3"));
var sc:SoundChannel;
sc = s.play(0, 1000);
 
this.addEventListener(Event.ENTER_FRAME, aMoverLosHuesos);
 
function aMoverLosHuesos(eventArgs:Event)
{
	rposT.x=110+(sc.rightPeak* - 20); //110 es donde esta el punto en reposo
        //y 20 son la cantidad de pixeles que quiero que se mueva que es multiplicado por algo entre 0 y 1.
	lposT.x=50+(sc.leftPeak* + 30);
	rikMover.moveTo(rposT);
	likMover.moveTo(lposT);
}

Lo único que le agregué a mi ejemplo final fue un botón de start/stop para no volver loco a los que visiten digilabs
Como ejercicio estaría bueno agregar un hueso desde el cuello a la punta de la cabeza ya animar la cabeza también. Para ésto hace falta agregar un movieclip transparente en la punta de la cabeza de lo contrario no sería imposible “tirar un nuevo hueso”. Otra cosa seria analizar bien el espectro del sonido cargado y usar los bajos para mover ciertas partes y los altos para otras.