#013 Flash [Q] Tips: swfobject y respeta los estándares con flash

Este tip es un poco doble, en realidad el objetivo principal es el de lograr crear código para un objeto flash que valide correctamente los estándares correspondientes, y de paso hablaros de un imprescindible en todos aquellos que trabajamos con flash como es swfobject.

La manera "tradicional" de generar un HTML con un flash incrustado, y que incluso es la que se mantiene en la versión CS4 de la suite de adobe es la siguiente:

HTML:
  1. <script language="JavaScript" type="text/javascript">
  2.     AC_FL_RunContent(
  3.         'codebase', 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=10,0,0,0',
  4.         'width', '300',
  5.         'height', '300',
  6.         'src', 'test',
  7.         'quality', 'high',
  8.         'pluginspage', 'http://www.adobe.com/go/getflashplayer',
  9.         'align', 'middle',
  10.         'play', 'true',
  11.         'loop', 'true',
  12.         'scale', 'showall',
  13.         'wmode', 'window',
  14.         'devicefont', 'false',
  15.         'id', 'test',
  16.         'bgcolor', '#993399',
  17.         'name', 'test',
  18.         'menu', 'true',
  19.         'allowFullScreen', 'false',
  20.         'allowScriptAccess','sameDomain',
  21.         'movie', 'test',
  22.         'salign', ''
  23.         ); //end AC code
  24. </script>
  25.     <object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=10,0,0,0" width="300" height="300" id="test" align="middle">
  26.     <param name="allowScriptAccess" value="sameDomain" />
  27.     <param name="allowFullScreen" value="false" />
  28.     <param name="movie" value="test.swf" />
  29.     <param name="quality" value="high" />
  30.     <param name="bgcolor" value="#993399" />   
  31.     <embed src="test.swf" quality="high" bgcolor="#993399" width="300" height="300" name="test" align="middle" allowScriptAccess="sameDomain" allowFullScreen="false" type="application/x-shockwave-flash" pluginspage="http://www.adobe.com/go/getflashplayer" />
  32.     </object>
  33. </noscript>

Hemos obviado el código javascript que ha generado también en dicho HTML. Pues bien, este código que ha generado el IDE de flash NO valida los estándares web que debería (esto no es nada nuevo, de hecho la solución que vamos a comentar tiene ya sus años, pero me jugaría bastante a que muchos de los que estáis leyendo esto, no os habéis preocupado demasiado de la validación de estándares de los objetos flash), y por tanto si en nuestras webs XHTML y CSS deseamos que sea una realidad el tema de la validación, deberemos tirar de recursos más elaborados.
Read more

#012 ActionScript [Q] Tips: precargas AS3 en Internet Explorer

Imagino que unos cuantos de vosotros habéis topado previamente con el bug que se da en Internet Explorer cuando hacemos una precarga empleando los eventos Event.COMPLETE y ProgressEvent.PROGRESS de AS3. El bug en cuestión aparece cuando tenemos una película cacheada y volvemos a ella, para reproducirlo solamente tenéis que cargar la película y una vez cargada, pulsar F5 en vuestro navegador IE, o Ctrl + F5. Cabe destacar que esto solo ocurre con la película principal, y no las que se cargan internamente en ella.

Veréis como la precarga se queda en pantalla por los siglos de los siglos, y es que no se disparan correctamente los eventos antes citados. La solución más simple para el problema, es controlar este hecho, y qué mejor manera que viendo antes de preparar los eventos, si resulta que ya tenemos cargada por completo la película.

Imaginemos que tenemos la siguiente estructura clásica para el preloader:

Actionscript:
  1. function cargando(ev:ProgressEvent):void
  2. {
  3.     var porcentaje:Number = Math.floor( (ev.bytesLoaded*100)/ev.bytesTotal );
  4.         trace ('cargado... '+porcentaje);
  5. }
  6.  
  7. function cargaCompleta(ev:Event):void
  8. {
  9.       trace('Listo!');
  10. }
  11.  
  12. this.loaderInfo.addEventListener(ProgressEvent.PROGRESS, cargando);
  13. this.loaderInfo.addEventListener(Event.COMPLETE, cargaCompleta);

Muchos optan por evitar el problema haciendo un preloader convencional con un Event.ENTER_FRAME, no obstante no es necesario, y aquí os dejamos el Tip de este viernes que nos permite la limpieza y eficiencia de la aproximación por eventos en vez de un enterFrame, sin tener que asumir el malfuncionamiento en Internet Explorer 6 y 7.

Si simplemente tenemos en cuenta comprobar inicialmente si la película está cargada por completo, algo tan sencillo como esto:

Actionscript:
  1. if (this.loaderInfo.bytesLoaded/this.loaderInfo.bytesTotal == 1)
  2. {
  3.      trace('ya está cargado por completo');
  4. }

Por tanto nos quedaría algo así:

Actionscript:
  1. function cargando(ev:ProgressEvent):void
  2. {
  3.     var porcentaje:Number = Math.floor( (ev.bytesLoaded*100)/ev.bytesTotal );
  4.         trace ('cargado... '+porcentaje);
  5. }
  6.  
  7. function cargaCompleta(ev:Event):void
  8. {
  9.       trace('Listo!');
  10. }
  11.  
  12. if (this.loaderInfo.bytesLoaded/this.loaderInfo.bytesTotal == 1)
  13. {
  14. // ya está cargado
  15. cargaCompleta(null);
  16. }
  17. else
  18. {
  19. this.loaderInfo.addEventListener(ProgressEvent.PROGRESS, cargando);
  20. this.loaderInfo.addEventListener(Event.COMPLETE, cargaCompleta);
  21. }

#011 ActionScript [Q] Tips: controla tus eventos

Todos los que tenemos más fresco AS2 (en mi caso por Flash Lite) tenemos que esforzarnos para mantener los eventos controlados en AS3. En AS2 cuando eliminabas un elemento del escenario, o de un clip, dejaba de responder a los eventos a los que estaba suscrito, y en AS3 esto no es así. Una buena manera de poder llevar un control del estilo de AS2 (que cuando borremos un elemento de la DisplayList deje de escuchar eventos, y de que los recupere cuando deseamos es encerrar estas llamadas, las de addEventListener y removeEventListener en dos métodos y suscribir éstos a los eventos ADDED y REMOVED).

Algo así:

Actionscript:
  1. package 
  2. {
  3.     import flash.events.Event;
  4.     import flash.display.Sprite;
  5.  
  6.     public class QTip11 extends Sprite
  7.     {
  8.         public function QTip11 ()
  9.         {
  10.             addEventListener(Event.ADDED, crearListeners);
  11.             removeEventListener(Event.REMOVED, eliminarListeners);
  12.         }
  13.        
  14.         private function crearListeners(ev:Event):void
  15.         {
  16.             // Aqui creamos nuestros listeners
  17.             addEventListener(Event.ENTER_FRAME, saludar);
  18.         }
  19.  
  20.         private function eliminarListeners(ev:Event):void
  21.         {
  22.             // Aqui eliminamos nuestros listeners
  23.             removeEventListener(Event.ENTER_FRAME, saludar);
  24.         }
  25.        
  26.         private function saludar(ev:Event):void
  27.         {
  28.             trace('hola!')
  29.         }
  30.     }
  31. }

De esta manera cuando hacemos un addChild del elemento se crea el listener, y simplemente con hacer un removeChild, se limpiaría.

Personalmente no lo uso porque no le veo que sea aplicable en unos cuantos casos, y además tengo muy grabado un método dispose que es donde voy poniendo mis removeEventListener según los creo en todos los sitios que me de la gana, y en cualquier tipo de clase, no solo en las que pueden formar parte de la DisplayList (es cuestión de hacer el hábito), pero es una manera curiosa de recordar el pasado en AS2.

#010 ActionScript [Q] Tips: recorte irregular de bitmaps con suavizado

Este tip es en realidad una presentación del método copyChannel de la clase BitmapData, pero al menos lo presentamos con una utilidad práctica. Imagina que te piden recortar dinámicamente unas zonas de una imagen pero con formas complejas, e incluso con suavizado en el corte...

Se nos puede ocurrir nada más plantearlo si la forma es regular, emplear una fórmula para saber si un punto se encuentra dentro o fuera (y quedarnos solamente con los interiores), pero y si la forma no es regular? y si el corte no ha de ser brusco, sino con un equivalente al "feather" de photoshop?

La técnica es fácil si la forma es conocida, creamos una imagen con la plantilla de corte en un programa gráfico, por ejemplo fireworks, con el suavizado que deseamos. De esa plantilla solamente nos importa la forma y transparencia, con lo que puede tener perfectamente un color sólido en los pixels que son opacos al 100%. Esta plantilla supongamos que tiene un área de 100 x 100 px (todas las imágenes son rectangulares a nivel de pixel, pero en su interior tiene la forma deseada con las transparencias deseadas).

Esa imagen en PNG nos va a servir como patrón de transparencia para el corte mediante la clase BitmapData. Imaginemos que tenemos una imagen como BitmapData en la variable origen y queremos sacar ese patrón centrado en la posición (200,200) pues bien (en mi caso la imagen de la biblioteca que actúa como plantilla mide 100x100 y tiene forma de estrella con suavizado, vinculada para AS como "starTemplate"):

Actionscript:
  1. import flash.display.Bitmap;
  2. import flash.display.BitmapData;
  3. import flash.display.BitmapDataChannel;
  4. import flash.geom.Point;
  5. import flash.geom.Rectangle;
  6.  
  7. var origen:BitmapData;
  8. var origen_bm:Bitmap;
  9. var copia:BitmapData;
  10. var copia_bm:Bitmap;
  11.  
  12. var rect:Rectangle = new Rectangle(0, 0, 100, 100);
  13. var pt:Point = new Point(0, 0);
  14.  
  15. origen = new starTemplate(0,0)
  16. copia = new BitmapData(100, 100, true, 0xFFFFCC00);
  17. copia.copyChannel(origen, rect, pt, BitmapDataChannel.ALPHA, BitmapDataChannel.ALPHA);
  18.  
  19. origen_bm = new Bitmap(origen)
  20. copia_bm = new Bitmap(copia);
  21.  
  22. origen_bm.x = 0;
  23. origen_bm.y = 0;
  24.  
  25. copia_bm.x = 200;
  26. copia_bm.y = 200;
  27.  
  28. addChild(origen_bm);
  29. addChild(copia_bm);

El resultado es una copia extraída de la imagen original con el mismo patrón que la plantilla que hemos usado.

#009 ActionScript [Q] Tips: controla tu foco en AS3

Ya sábado y sin poner el tip correspondiente... una semana complicada creedme...

En AS2 disponíamos de la clase Selection con sus métodos getFocus y setFocus que nos permitían controlar el cambio de Foco o elegir a quién queríamos dárselo, en AS3 se simplifica el proceso con la propiedad focus de stage (aplicable sobre cualquier InteractiveObject), y por otro lado tenemos la clase FocusManager para todos los componentes que implementan la IFocusManagerComponent.

Si lo que queremos es simplemente respetar un orden, podemos trabajar sobre los tabIndex de los elementos en pantalla (sean elementos normales o componentes, y que se mantiene desde AS2), de tal manera que empezando en 1 y dando sucesivos valores, tengamos el orden deseado. Con esto controlamos la transición de uno a otro mediante tabulador.

Para los que huyen del código, otra manera de darles el orden de tabulación es con el desconocido panel Accesibilidad de Flash que se encuentra en Window > Other Panels > Accesibility, donde cuando selecionamos un elemento podemos asignarle un tabIndex manualmente. El resultado es el mismo que el trabajo por código con tabIndex.

Flash, Control de Foco en AS3

Para preparar el foco en el elemento que desamos inicialmente (por ejemplo el primer campo del formulario) simplemente tenemos que hacer:

Actionscript:
  1. stage.focus = nombreElemento;

Simple, ¿no?, bastante mejor que en AS2.

Si trabajaramos sobre componentes, sin duda sería mucho más interesante emplear el mencionado FocusManager ya que nos permite tener un control mucho más detallado sobre los focos, relativos incluso al componente que lo emplea, eventos derivados del foco, conocimiento sobre el siguiente elemento a tomar el foco desde la perspectiva del componente actual, etc.

#008 ActionScript [Q] Tips: sincronizar FPS

Controla y sincroniza FPS entre diferentes películas

En el útlimo proyecto en el que nos hemos visto embarcados, hemos sufrido muy de cerca 2 características de flash que no son especialmente agradables: no te puedes fiar de los FPS para darle velocidad a un movieclip, y no te puedes fiar de un intervalo, Timer, o como lo quieras llamar para darle velocidad a un clip.

La física ayuda, si un coche va a 40Km/h de forma constante, y avanza recto durante 1 hora, sabes que estará 40 kilómetros desde el punto de medición. Pero en flash lo normal no es actuar así, sino que en un ENTER_FRAME o en un intervalo, le vamos incrementando la posición.

El efecto resultante es que si la ejecución del ENTER_FRAME o del intervalo varía dependiendo del equipo, en cada equipo el coche irá a diferente velocidad. Hasta aquí, siempre que estemos hablando de animaciones de un solo usuario, es un efecto bastante "intrascendente" (lo entrecomillo porque hay casos en los que podría ser perfectamente trascendente), pero por ejemplo en un juego multijugador en el que en el lado del cliente se hace simulación de adversarios y precálculo, la cosa cambia y puede llevar al traste todo el trabajo. Read more

#007 ActionScript [Q] Tips: recibir valores por flashvars en AS3

El de esta semana es corto, pero necesario ya que es un cambio notable frente al método habitual que estaba establecido para AS2 (donde nos creaba automáticamente una variable con ese nombre en la raiz del documento). Cuando a un SWF le pasamos variables inicialmente por flashvars o por parámetros en la URL, podemos acceder a los mismos de la siguiente manera:

Actionscript:
  1. var valor:String = root.loaderInfo.parameters.nombreVariable;

donde nombreVariable es el nombre del parámetro que le pasamos al SWF externamente por flashvars, ya sea desde el OBJECT, EMBED, etc. Hay que tener en cuenta que como todo lo que se recibe externamente por estos métodos, son cadenas de texto a menos que les hagamos la correspondiente conversión.

#006 ActionScript [Q] Tips: contains()

Este tip es muy directo ya que simplemente comentaré uno de los métodos que obtienen todos las clases que extienden de DisplayObjectContainer, ya sean propias o las consabidas Stage, Sprite, Loader y MovieClip.

En realidad lo interesante de esta función es que no solamente funciona para descendientes directos en la jerarquia de la Display List, sino que busca el resultado en todos los descendientes. Veamos un ejemplo:

Actionscript:
  1. var abuelito:Sprite = new Sprite();
  2. var padre:Sprite = new Sprite();
  3. var nieto:Sprite = new Sprite();
  4. var unoQuePasabaPorAlli:Sprite = new Sprite();
  5.  
  6. padre.addChild(nieto);
  7. abuelito.addChild(padre);
  8. addChild(abuelito);
  9. addChild(unoQuePasabaPorAlli);
  10.  
  11. trace(abuelito.contains(padre)); // true
  12. trace(abuelito.contains(nieto)); // true
  13. trace(abuelito.contains(unoQuePasabaPorAlli)); // false

Como vemos aunque pasemos como parámetro un elemento de la Display List que no es un descendiente directo del elemento sobre el que buscamos, el resultado es igualmente válido, con lo que esta función nos permite conocer a cualquier nivel si un elemento de la Display List contiene a otro elemento de la misma.

Hay que tener en cuenta que quien llama a contains tiene que ser un objeto de una clase que herede en algún nivel de DisplayObjectContainer, pero el objeto que buscamos en su interior no tiene por qué serlo (por ejemplo un campo de texto). Además aunque en el ejemplo haya añadido abuelito a la DisplayList, contains funciona aunque el contenedor no forme parte de ella (y por tanto ninguno de sus descendientes), con lo que aunque hay usado Display List no es necesariamente estricto (lo siento, me surge llamarlo así aunque los elementos no estén en pantalla).

#005 ActionScript [Q] Tips: Singleton en AS3

Para los que trabajábamos con clases en AS2, no era raro emplear un Singleton para alguna de ellas, con le objetivo de tener una clase general para toda la aplicación con la capacidad de acceder a ella desde cualquier punto de manera limpia. Con AS2 podíamos declarar constructores privados y dejar un código tal que así:

Singleton AS2

Actionscript:
  1. class Ejemplo
  2. {
  3.     private static var _instancia:Ejemplo;
  4.  
  5.     private function Ejemplo () { }
  6.  
  7.     public static function getInstancia():Ejemplo
  8.     {
  9.         if (_instancia == null)
  10.         {
  11.             _instancia = new Ejemplo();
  12.         }
  13.         return _instancia;
  14.     }
  15. }

Con esas líneas de código lográbamos que la clase solamente se pudiera instanciar una vez, y mediante Ejemplo.getInstancia(), podíamos tener la referencia a ella en cualquier punto de la aplicación. Genial.

Con AS3, no podemos declarar constructores privados, con lo que este modelo de Singleton nos deja de servir, por suerte hay alguna característica nueva en AS3 que nos permite mantener nuestros Singletons sin tener que cambiar demasiado la filosofía:

Singleton AS3

Actionscript:
  1. package
  2. {
  3.     class Ejemplo
  4.     {
  5.         private static var _instancia:Ejemplo;
  6.  
  7.         public function Ejemplo(enforcer:SingletonEnforcer) {}
  8.  
  9.         public static var getInstancia():Ejemplo
  10.         {
  11.             if (_instancia == null)
  12.             {
  13.                 _instancia = new Ejemplo(new SingletonEnforcer());
  14.             }
  15.             return _instancia;
  16.         }
  17.     }
  18. }
  19.  
  20. class SingletonEnforcer { }

No he traducido el SingletonEnforcer porque no encontraba una traducción que me gustara más que el inglés, y además es que yo lo uso así, por lo que me suena muy raro ponerlo de otra manera, de hecho en vez de _instancia para la propiedad privada, le enchufo _instance, y lo mismo con le nombre del método estático, pero vamos que como el blog en castellano, hay que castellanizar lo más que se pueda... XD

Este tip viene de la mano de un libro que pasó por mis manos hace tiempo, pero que es de muy recomendable lectura: Advanced ActionScript 3 Design Patterns.

#004 ActionScript [Q] Tips: reemplazar elementos de un array

Muchas veces veo como para realizar determinadas operaciones con arrays la gente emplea operaciones de intercambio, recorrido, etc. y no analiza a fondo las posibilidades que nos dan a veces los métodos de la clase Array.

En esta ocasión lo que veremos es cómo realizar inserciones en una posición dada, o intercambios de elementos. Para ello el método splice de la clase Array nos da unas cuantas posibilidades, ya que nos permite eliminar, añadir elementos a partir de una posición dada, intercambiar un elemento existente por otro nuevo, o incluso eliminar un grupo y poner en su lugar otro.

Para mostrar las posibilidades ponemos aqui un poquito de código (que es válido tanto para AS2 como para AS3):

Actionscript:
  1. var test_arr:Array = new Array("uno","XXX","YYY","cuatro","cinco");
  2. trace("ARRAY INICIAL: "+test_arr);
  3. // eliminar 2 elementos que no interesan
  4. test_arr.splice(1,2);
  5. trace("CONTENIDO ARRAY TEST: "+test_arr);
  6. // añadir 2 elementos
  7. test_arr.splice(1, 0, "DOSX", "TRESX");
  8. trace("CONTENIDO ARRAY TEST: "+test_arr);
  9. // intercambiar o lo que es lo mismo eliminar + añadir
  10. test_arr.splice(1, 2, "dos", "tres");
  11. trace("CONTENIDO ARRAY TEST: "+test_arr);

Como podéis ver con una simple línea podemos lograr varias operaciones que de usar el clásico pop, push, etc se complicarían bastante.

Next Page →