3rd party players - Clases aS2

Escrito el 30/05/2004 por Xavi Beumala

Como hacía bastantes días que no posteaba nada pues hoy tocan dos tazas ;-)

Con Sixto llevamos un mes o así trabajando juntos en un proyecto bastante interesante que entre otros aspectos tiene que ser capaz de acceder al sistema de archivos local. El proyecto es un programa para generar y guardar animaciones en linea de tiempo (como un mini Flash).

La aplicación está se ejecutará como standAlone así que decidimos usar un player extendido. En nuestro caso optamos por SWFStudio, no por nada en concreto, sinó porque es el producto del que teníamos licencia. En cualquier caso casi todos funcionan de una forma muy parecida y se basan en la comunicación externa mediante FSCommand.

El tema es que los fscommands son instrucciones asíncronas y que cuando esperas que te devuelvan un valor no dan más que dolores de cabeza.

Por ejemplo, la función que permite salvar a un texto en el HD es FileSys2.WriteToFileUTF16 pero si queremos una ventana emergente de sistema que nos permita escoger un archivo usamos FileSys2.FileSave. FileSave devuelve, de forma asíncrona, el archivo y su ruta en el que queremos almacenar el contenido. SWFStudio permite definir la propiedad en la que se va a almacenar dicho valor, creo que ScreenWeaver ya tiene esas variables preasignadas.

La variable que recibe esos datos asíncronos no puede estar en cualquier sitio ni definida de cualquier manera sinó que tiene que referenciarse a partir de _level0. Esto es así por la arquitectura del player ya que desde fuera del player sólo es accesible el _level0, los demás niveles así como _global son mapeos internos que hace el player.

Una de las soluciones para solventar el asincronismo hubiera sido utilizar getters/setters a través de alguna clase, pero el problema/inconveniente es que era un tostón referenciar esas propiedades con ruta absoluta desde _level0.

Otro 'inconveniente' que tienen estos players es que el uso en clases de los fscommands deja bastante que desear, así que optamos por hacer clases que actuaran como wrappers de esos fscommands. El siguiente problema que nos encontramos es que teníamos que escribir muchas clases y no teníamos ni tiempo ni ganas ;-).

La solución ha sido crear una única clase SWFStudio.Wrapper que se encarga de solventar el tema del asincronismo mediante el uso de Object.watch y de transcribir todos los fscommands de tal forma que sean accesibles con una sintaxis AS2 más agradable.

Pongo a continuación el código del Wrapper y link para que os descarguéis un .fla de ejemplo, un .exe para que veáis el funcionamiento, un .spf (proyecto de swfStudio) y la clase SmartCallback (utilizada por Wrapper).

Os lo podéis descargar aquí.

Y aquí va el código:

   1:import com.code4net.system.SmartCallback;
   2:
   3:class com.code4net.SWFStudio.Wrapper {
   4:   private static var callBack:SmartCallback;
   5:   private static var returnObj:Object = _level0.SWFStudioReturnObj = new Object();
   6:   private static var returnStr:String = new String("_level0.SWFStudioReturnObj."); 
   7:   
   8:   private static function watchProp(prop:String):String {
   9:      returnObj.watch(prop,onResult);
  10:      return (returnStr + prop);
  11:   }
  12:   
  13:   private static function unwatchProp(prop:String,value:String):Void {
  14:      returnObj.unwatch(prop);
  15:      setPropertieValue(prop,value);
  16:   }
  17:   
  18:   private static function setPropertieValue(prop:String,value:String) {
  19:      returnObj[prop] = value;
  20:   }
  21:   
  22:   private static function onResult(prop,oldValue,newValue) {
  23:      unwatchProp(prop,newValue);
  24:      callBack.run(newValue);
  25:   }
  26:   
  27:   public static function executeFSCommand(fs:String,param:Array,c:SmartCallback) {
  28:      var returnStr:String;
  29:      var i:Number;
  30:      var len:Number;
  31:      
  32:      callBack = c;
  33:      
  34:      var p = fs.split(".");
  35:      p = p[p.length - 1];
  36:      
  37:      returnStr = watchProp(p);
  38:      
  39:      fscommand("ARG",returnStr);
  40:      
  41:      len = param.length;
  42:      
  43:      for (i = 0; i < len; i++)
  44:         fscommand("ARG",param[i]);
  45:      
  46:      fscommand(fs,"");
  47:   }
  48:}

La forma de usarlo, >descargaros el .zip para un ejemplo más completo, seria algo así (en el .fla):

   1:open_btn.onPress = function() {
   2:   myArr = new Array();
   3:   myArr.push("Abrir jugada");
   4:   myArr.push("c:\\");
   5:   myArr.push("FutMotion Design File|*.fmd||");
   6:   
   7:   var c = new SmartCallback(this._parent,this._parent.onOpenFileChoosed);
   8:   Wrapper.executeFSCommand("FileSys2.fileOpen",myArr,c);
   9:}

Donde lo único que indicamos es el fscommand a utilizar (lo pasamos como primer parámetro a Wrapper.executeFSCommand, como segundo parámetro pasamos todos los parámetros que espera ese FSCommand (como un objeto) y por último pasamos un SmartCallback, que nos indica el método a ejecutar cuando se recupere el sincronismo y el ámbito en el que se va a ejecutar.