AS3 - método unloadAndStop();

Hasta la versión 9 de FP, contábamos con el método unload() de la clase Loader para proceder a la descarga de aquellos contenidos que eran cargados por medio del método load() de dicha clase. Ahora bien, el problema surgía cuando se generaba la descarga de una película y:

Si contabas con audio o video, estos continuaban con su reproducción.

Continuaban abiertas aquellas conexiones que no han sido cerradas (netConnection, netStream, localConnection, etc)

Continuaban consumiendo recursos todos aquellos procesos de los cuales prescindimos al descargar la película (listeners que, sería razonable, sean eliminados al descargar la película)

Si bien existen motivos para que esto sea así, indudablemente es una molestia. A pesar de que la optimización de recursos es parte de nuestro desempeño, tratar de eliminar absolutamente todas aquellas referencias innecesarias que están haciendo que el Garbage Collector no las tenga en cuenta, es una actividad por demás engorrosa, molesta y llena de inconvenientes durante el proceso.

Por suerte, desde Flash Player 10, contamos con una solución. Solución parcial y aún con varios ajustes por hacer, pero solución al fin:

El método unloadAndStop();

Por medio del mismo no sólo se procede a la descarga de la película swf, sino que se intenta anular aquellos contenidos secundarios del mismo y detener la ejecución de comandos de dicho archivo, por lo tanto:

Se detienen aquellos sonidos que se estén ejecutando.

Se eliminan los listeners que hayan sido añadidos al escenario.

Se eliminan los eventos enterFrame, frameConstructed, exitFrame, activate y deactivate.

Se detienen los temporizadores.

Se eliminan las instancias de cámara (Camera).

Se eliminan las instancias del mic (Microphone).

Se detienen los clips de película.

En vistas a la optimización de recursos, definitivamente es mucho más ventajoso que el método unload(), y evita en gran parte aquellos malabares que debíamos hacer antes de eliminar una película. De todos modos, si bien este es el camino, considero que aún queda mucho por hacer al respecto; sería mucho más productivo nuestro tiempo, y por ende, más interesantes nuestros desarrollos, si el proceso para mantener optmizadas nuestras películas fuese más transparente de lo que actualmente es. Esperemos se mejore día a día en esta cuestión y encontremos nuevas soluciones en versiones posteriores de FP. Si bien queda mucho por hacer, por suerte, el método unloadAndStop() es un buen indicio de estar yendo por el buen camino…

AS3 - SoundMixer.computeSpectrum();

Les dejo esta pequeña clase donde se hace uso del método computeSpectrum() de la clase SoundMixer en modo FFT (Fast Fourier Transform). Por medio del método computeSpectrum() se puede tomar la onda de un sonido que se está reproduciendo., y lluego almacenarla dentro de un ByteArray. Teniendo acceso al mismo, podemos generar representaciones visuales de dichas ondas. Este es un sencillo ejemplo que desarrollé a modo de clase para que sea personalizable, escalable y reutilizable; verán al descargar los archivos que no es de gran complejidad, y lo más interesante es la sencillez de su implementación; modificando algunos parámetros, podemos lograr distintos gráficos, que con un poco de ingenio e imaginación, se pueden adaptar a cualquier proyecto.

click aca para descargar los archivos!

(eliminé el MP3 del .rar para facilitar la descarga. Para que puedas ver el ejemplo en funcionamiento, mové un mp3 a la carpeta sound, y renombrarlo como song.mp3)

index.fla:

Hay cuatro bloques de código:

En primer lugar, importamos la clase:

import com.FrequencyVisualization;

Luego cargamos de manera externa un sonido:

var soundReq=new URLRequest(”sound/song.mp3″);
var typeSound = new Sound();
typeSound.load(soundReq);
typeSound.play(0);

A continuación, creamos un objeto al cual le vamos a asignar una serie de propiedades, y que usaremos para enviarle a la clase. Las propiedades de dicho objeto se van a tener en cuenta dentro de la clase a la hora de dibujar (y redibujar) los contenidos del espectro de sonidos. Se le pueden agregar unos cuantos parámetros más, pero con estos poquitos a mi me alcanzó (al menos hasta ahora) para poder aplicarlo prácticamente a cualquier desarrollo sin tener que hacer grandes modificaciones: Los parámetros a enviar son el color de las barras del espectro (barFill), la cantidad de barras (barsNumber), el ancho de las mismas y su separación (barWidth y barsSeparation) y por último, un valor alpha (barAlpha). Más abajo hay algunas imágenes para ver como combinando distintos valores para estas propiedades, podemos obtener resultados considerablemente distintos.

var visObj:Object = new Object();
visObj.barFill = 0xff0066;
visObj.barsNumber=10;
visObj.barWidth = 2;
visObj.barsSeparation = 2;
visObj.barAlpha = 0;

Para concluir, creamos una instancia de la clase FrequencyVisualization, y le pasamos como parámetro el objeto que acabamos de crear:

var eVis:FrequencyVisualization=new FrequencyVisualization(visObj);
eVis.x=250;
eVis.y=stage.stageHeight-30;
stage.addChild(eVis);

Eso es todo :) Los programadores tienen con qué entretenerse dentro de la clase FrequencyVisualization, y quienes no tengan interés en entender códigos ni enredarse en su lógica, tienen un modo sencillo e intuitivo para que en cuatro pasos puedan contar con su ecualizador…

Algunas alternativas:

Modificando los distintos valores de las propiedades que asignamos al objeto que enviamos como parámetro a la clase, obtenemos diversos resultados:

var visObj:Object = new Object();
visObj.barFill = 0xff0066;
visObj.barsNumber=10;
visObj.barWidth = 2;
visObj.barsSeparation = 2;
visObj.barAlpha = 0;

alt11.png

var visObj:Object = new Object();
visObj.barFill = 0xff0066;
visObj.barsNumber=50;
visObj.barWidth = 2;
visObj.barsSeparation = 1;
visObj.barAlpha = 1;

alt22.png

var visObj:Object = new Object();
visObj.barFill = 0×00ff00;
visObj.barsNumber=10;
visObj.barWidth = 2;
visObj.barsSeparation = 2;
visObj.barAlpha = 1;

alt31.png

var visObj:Object = new Object();
visObj.barFill = 0×000000;
visObj.barsNumber=5;
visObj.barWidth = 1;
visObj.barsSeparation = 3;
visObj.barAlpha = 1;

alt41.png

var visObj:Object = new Object();
visObj.barFill = 0xFF9900;
visObj.barsNumber=10;
visObj.barWidth = 10;
visObj.barsSeparation = 2;
visObj.barAlpha = 1;

alt51.png

var visObj:Object = new Object();
visObj.barFill = 0×339999;
visObj.barsNumber=10;
visObj.barWidth = 10;
visObj.barsSeparation = 2;
visObj.barAlpha = 0.2;

alt61.png

NOTA: Al trabajar sobre esta clase, establecí el modo FFT (Fast Fourier Transform) debido al tipo de espectro de sonido que debía representar. El método FFT nos devuelve datos del espectro de frecuencias en lugar de datos de forma de onda. En breve voy a escribir un post con clases y ejemplos de representaciones visuales de datos de forma de onda, en lugar de espectros de frecuencia…veremos que se pueden lograr otras animaciones realmente interesantes.

Saludos!

AS3: Event Listeners y WeakReference (referencia débil)

Si bien en el capítulo dos del libro Flash Extremo desarrollé este tema con mayor profundidad, considero que vale la pena hacer una mención al mismo en el blog para comprender su funcionamiento y aportar un modo de adoptar una buena práctica a la comunidad de desarrolladores:

La sintaxis por medio de la cual agregamos eventos, es la siguiente:

 addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown)

 Al método addEventListener le indicamos en primer lugar el tipo de evento (MouseEvent.MOUSE_DOWN), y la función que se va a ejecutar en respuesta a dicho evento;  en nuestro caso, la función onMouseDown.

Pero existen tres parámetros más, los cuales son de carácter opcional:

 //addEventListener(evento, listener, useCapture, priority, weakReference)
addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown, false, 0, false)

 El último de estos parámetros es el que nos interesa. Su valor por defecto es false.  Al modificar este ultimo parámetro y definirlo como true, estamos indicando que dicho evento sea tenido en cuenta por el garbage collector  (o recolector de basura) al realizar su rutina.

 Ahora bien, ¿Qué es el garbage collector? El garbage collector, como su nombre lo indica, es un recolector de basura; es un proceso que se ejecuta detrás de escena dentro de una película swf, y se encarga de liberar memoria, eliminando aquellos objetos que ya no están siendo utilizados por la aplicación.

Para que el garbage collector “elimine” la referencia a aquellos eventos que ya no estamos utilizando, debemos asignar  la referencia débil al declararlos. De aquí, el por qué del true del último parámetro:

 addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown, false, 0, true)

 De este modo, la próxima vez que el Garbage Collector recorra nuestra película, se va a encargar de eliminar la referencia de dicho evento y liberará espacio en memoria.

 Esto es simplemente una buena práctica; acostumbrarse a escribir la sintaxis completa de un evento y asignar en true el parámetro weakReference, nos puede ayudar a eliminar problemas de memoria con nuestras aplicaciones. Se trata de un buen hábito fácil de incorporar y que en verdad es de utilidad en nuestros desarrollos.

 NOTA 1: no hay ninguna forma de hacer que el garbage collector se ejecute; AS3 no provee sintaxis para ello. Cada determinado tiempo, este recorre la aplicación detrás de escena liberando memoria y eliminando aquellos listeners que han sido asignados para que el garbage collector los recoja.

 NOTA 2: utilizar la referencia débil, NO es un reemplazo al método removeEventListener() ni mucho menos. Por el contrario, es más bien un complemento a este, o más bien, puede resultar de utilidad en caso de que olvidemos eliminar listeners.

 Saludos! :)

AS3 SharedObjects

sharedobject-header1.png

SharedObjects (también conocidos como SO u Objetos Compartidos en español) son las Cookies de Flash. Las mismas nos permiten almacenar información limitada de datos en el equipo de un usuario, o en un servidor. Veremos que si bien pocas veces hacemos uso de ellas, son de una enorme utilidad y repercuten de manera positiva en la experiencia de usuario (por más de que a nivel conciente no lo perciban).

Flash utilisa los SO de manera local y de manera remota. En este post abarcaremos la manera local de trabajar con ellas.

Esta posibilidad de almacenar info en el sistema del usuario, pone a nuestra disposición una enorme gama de posibles soluciones que si bien no siempre son determinantes para el funcionamiento de un desarrollo, indudablemente mejoran la experiencia:

¿Alguna vez notaste que el reproductor de videos de Youtube conserva siempre el último volumen que seteaste, por más de que cierres el sitio y vuelvas?

Al igual que Youtube, muchos players hacen esto, y la manera de lograrlo es justamente por medio del uso de SharedObjects. La pregunta anterior me llena de curiosidad. La hago con bastante frecuencia, y salvo pocos desarrolladores, la mayoría no sabe que la web de videos hace eso con el volumen. Quizas a muchos les parezca un dato menor, o incluso imperceptible; a nivel consciente no estamos pendiente del volumen, pero brindar estas pequeñas soluciones, indudablemente mejoran la experiencia de navegación y la interacción con las aplicaciones; nos facilitan su manejo y por sobre todas las cosas, muchas veces logran optimizar nuestros tiempos y focalizarlo en lo que realmente nos interesa.

Pero el alcance de los SO es mucho más potente y les podemos dar los más diversos usos; cuando comiencen a pensar en posibles soluciones, seguramente le vengan a la cabeza muchísimas ideas y posibilidades. Sí, prácticamente todas ellas, son válidas.

Veamos como usarlas en Flash:

En primer lugar, debemos declarar una instancia de la clase SharedObject:

mySharedObject = SharedObject.getLocal(”as3hispano”);

Por medio del método getLocal() indicamos el nombre que llevará nuestro SO y el cual utilizaremos tanto para leer como para guardar valores.

Cómo almacenar valores:

Una vez que contamos con nuestra instancia, a la propiedad data de la misma, podemos asignarle los atributos que queremos almacenar y luego leer. Suponiendo que queramos almacenar un valor numerico, lo hacemos del siguiente modo:

mySharedObject.data.volumeSO = 0.7;

La clase SharedObject cuenta con el método flush, por medio del cual podemos dar la orden de que se grabe el valor inediatamente. En caso de no utilizar el método flush, el SO se guardará cuando se finalice la sesión (cuando se cierre el SWF o cuando se utilicen los métodos close() o clear() de la clase SharedObject):

var flushIt:String = mySharedObject.flush();

Cómo leer valores:

También accedemos a los valores almacenados por medio de la propiedad data. Lógicamente, debemos haber declarado una instancia de la clase SharedObject:

var value:Number = mySharedObject.data.volumeSO;
trace(value);

En caso de que no exista el atributo que estamos tratando de leer del equipo del usuario, nos devolverá null.

La clase SharedObject cuenta con varios métodos, propiedades y eventos que ayudan a trabajar con ellos gran flexibilidad. Su uso es realmente sencillo e intuitivo, su implementación es cuestión de pocos minutos y el aporte que hacen a la experiencia de navegación es realmente significativo.
Por otro lado, al implementar cookies con PHP, tenemos hasta 4Kb para almacenar información. Los Objetos Compartidos de Flash nos proveen de 100 kb por defecto (pudiéndose alternar entre otros valores; 1mb, 10mb, ilimitado, 10 kb y ninguno).

panel

Podemos configurar estos parámetros desde http://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager03.html

El uso de los SO puede ser de lo más variado. Aquí les dejo un pequeño ejemplo implementando el slider genérico que se utilizó en un post anterior.

AS3 Slider


slider

¡He aquí el primer post!

Hace algún tiempo tengo hecho este pequeño slider genérico. Me parece un buen ejemplo como primer post, no precisamente por su funcionalidad, sino por su desarrollo. Si lo que buscan es un tutorial de como desarrollar un slider, definitivamente este no es el caso. Google nos puede arrojar infinidad de Sliders hechos en Flash, con easing, sin easing, para texto, para MovieClip, etc, etc. Incluso, descargando el archivo encontrarán la clase MySlider dentro del paquete com.utils y encontrarán la clase bastante documentada.

Lo que si me resulta interesante y es lo que quiero compartir, es el modo en el cual está desarrollado. Cuando uno se acerca al mundo ActionScript 3.0 generalmente encuentra como dos de sus grandes ventajas la escalabilidad que nos propone la plataforma y la optimización de recursos, y eeeeso si que es dificil encontrarlo en google..o mejor dicho, muchas veces es complejo comprender y adaptar esta lógica como modalidad de trabajo.
Quienes estén en tema ya lo sabrán, y quienes comiencen a adentrarse pronto lo irán viendo, hay varias formas de optimizar nuestras clases y de comunicarnos con ellas. Esta es tan sólo una de esas maneras. Al momento de desarrollar el slider, tenia en mente que:

- Debía ser reutilizable.
- Debía gestarse dentro del código todo el desarrollo de los contenidos (sprites, movieclips) del slider, para no depender de archivos dentro de la biblioteca.
- Debía tener un grado de personalización.

1 - Para que sea reutilizable, se creó una clase para el mismo. Se puede usar/modificar, etc, se encuentra dentro de la carpeta com.utils y se llama MySlider.
2 - Para no emplear elementos dentro de la biblioteca e indexarlos a la clase, se dibujaron los contenidos de dicho slider por medio de la API de dibujo de Flash. No es este nuestro tema, pero ya le dedicaremos algún post :)
3 - Para obtener un grado,(mínimo, pero grado al fin), se pensó en la estructura del código y en el funcionamiento que esperábamos por parte del slider; este debe deslizar un cabezal, en base a las medidas establecer un valor, y luego devolverlo a la clase que lo está empleando. Esto es lo que en verdad nos interesa en este post :) y esta es la pequeña solución que yo hallé. Existen otras, desde luego:

En primer lugar, crear un objeto y asignarle todas las propiedades que queremos para nuestro slider; su largo, ancho, color, valor minimo, valor maximo, posición inicial del cabezal, el radio del boton, un valor entre 0 y 1 para el easing.

sliderDataObject = new Object();
sliderDataObject.width = 200;
sliderDataObject.height = 0.25;
sliderDataObject.color = 0xcccccc;
sliderDataObject.min = -0;
sliderDataObject.count = 200;
sliderDataObject.position = 100;
sliderDataObject.buttonRadio = 4;
sliderDataObject.sliderEasying = 0.6;

Una vez definido el objeto y sus propiedades, lo asignámos como parámetro al declarar la clase:

mySlider = new MySlider(sliderDataObject);
mySlider.addEventListener(MySlider.RETURN_VALUE, returnValue);
mySlider.x = 340;
mySlider.y = 80;
addChild(mySlider);

Eso es todo :) de este modo, cada vez que queramos usar el slider, definimos de antemano un objeto con todos sus parámetros, y lo enviamos a la clase. Esta usará dichos parámetros para generar el slider.
Conociéndos y manejandos, lo adaptamos a nuestras necesitas y dotamos a nuestro slider de las propiedades que queramos

De todos modos, el mejor modo de entenderlo, es prestando atención al código de la clase MySlider y al código de la clase MainClass y entender de qué manera se comunican. Por último, en la medida que el slider genere valores, se los devolverá a la clase principal. Para lograr esto, en primer lugar asignamos un evento a nuestra clase:

mySlider.addEventListener(MySlider.RETURN_VALUE, returnValue);

y también su respectiva función:

private function returnValue(event:Event):void{
trace(mySlider.actualPosition);
}

Ese es todo el código que necesitamos en nuestra clase principal para obtener un slider funcional. El modo en el que la clase MySlider evalúa la posición del cabezal y se la devuelve a nuestra clase principal (o el código que tengamos en el frame de la IDE) lo encontrarán justamente dentro de la clase MySlider, en la última línea de la siguiente función:

private function onMove(event:Event):void{
var total:Number = sliderWidth;
var parcial:Number = ball.x;
var percent:Number = Math.round(sliderMin + (parcial * (sliderCount-sliderMin))/total);
actualPosition = percent;
dispatchEvent(new Event(RETURN_VALUE));
}

Puede que resulte complejo comprender el modo en el cual se comunican las clases, pero una vez que se logra incorporar esta mecánica, nuestros desarrollos van a tener mucha más fluidez, mayor optimización, mayor personalización y escalabilidad. Por tan solo 7 Kb. contamos con un slider que cumple con todas estas funcionalidades, podemos dotar de las características que queramos, y por sobre todas las cosas, en caso de querer aplicar algún cambio a la clase MySlider, solamente debemos modificar esa única clase y no cada proyecto en el que la hayamos utilizado.

espero que sea de ayuda y a modo de consejo, lo siguiente; el mejor modo de comprender esta lógica es mirando el código de las clases, poniendo especial énfasis en cómo van y como vuelven las variables de una clase a otra.

Saludos! :)

descargar archivos aqui.