Archive for the ‘actionscript_3’ Category

Uso de Code Snippets en Flash CS5

Viernes, Mayo 14th, 2010

Entre las novedades de Flash CS5 está la nueva ventana de Code Snippets, que no es más que código listo para usar, esto es muy usual en muchos lenguajes de programación que ayuda a ganar tiempo reutilizando líneas de programación que necesitemos a lo largo de un proyecto. Esta versión inicial, solo está disponible para código utilizado en la línea de tiempo, no en archivos actionScript.

Para empezar crearemos un archivo nuevo en Flash CS5 y buscaremos en el menú Windows>Code Snippets o haremos click al ícono correspondiente, veremos:

Aquí podemos apreciar los códigos predeterminados que viene con Flash CS5 y como has visto, hay una gran variedad. Para el ejemplo inicial usaremos código de la carpeta Actions.

Si deseamos abrir una URL o dirección web, solo tendríamos que seleccionar en el escenario el botón que deseamos dispare el evento, seguido de Snippets y listo, veremos como en la ventana de acciones tendremos lo siguiente:

Otro ejemplo es el famoso Drag&Drop de los juegos, esto también viene aquí:

Conclusión hasta aquí, esto es una gran ayuda para los diseñadores que quieren un código simple y efectivo, además de fácil de usar. Ergo, los que nos dedicamos al código el 150% de nuestras vidas no podríamos estar contentos sólo con esto, para eso podemos crear nuestros propios Snippets. Para eso en la pestaña de la esquina damos click y seleccionado Create New Code Snippets.

Luego aparecerá una ventana para llenar el código que queramos, con título y toolTip, yo hice un for básico y quedó así:

En este caso no necesito de seleccionar un elemento del escenario para que funcione, así que sólo le hago click y en la ventana de acciones veremos:

De la misma forma podemos exportar o importar nuestros códigos para poder compartirlos sin problemas, o en su defecto, volver a la versión por defecto.

Por otro lado, podemos editar el XML que genera al crear los Code Snippets.

Ahí puedes darle grabar y regrescar :) espero les sea útil o por lo menos saber de su existencia.

Enviar comentario

Detectar un punto dentro de una figura, colisiones en AS3

Viernes, Abril 16th, 2010

Evaluar si un punto esta dentro de un poligono es una operacion basica, pero eso yo no lo sabia. Hasta que llega el momento en que es necesario. Perdí bastante tiempo investigando al respecto, asi que ahora comparto con ustedes el resultado, por si puede ahorrarle tiempo a alguien. No detallaré la explicacion, les dejo un link al ejemplo funcionando, el codigo fuente.


Código para detectar colisiones de un punto sobre un poligono

Código :

private function insidePolygon(pointList:Array, p:Point):Boolean
{
   var counter:int = 0;
   var i:int;
   var xinters:Number;
   var p1:PointTest;
   var p2:PointTest;
   var n:int = pointList.length;
      
   p1 = pointList[0];
   for (i = 1; i <= n; i++)
   {
      p2 = pointList[i % n];
      if (p.y > Math.min(p1.y, p2.y))
      {
         if (p.y <= Math.max(p1.y, p2.y))
         {
            if (p.x <= Math.max(p1.x, p2.x))
            {
               if (p1.y != p2.y) {
                  xinters = (p.y - p1.y) * (p2.x - p1.x) / (p2.y - p1.y) + p1.x;
                  if (p1.x == p2.x || p.x <= xinters)
                     counter++;
               }
            }
         }
      }
      p1 = p2;
   }
   if (counter % 2 == 0)
   {
      return(false);
   }
   else
   {
      return(true);
   }
}   

Descarga el ejemplo

Enviar comentario

Ejemplo Actionscript 3 - Fisica para 3D con JigLibFlash

Lunes, Abril 12th, 2010


Jiglibflash es un motor de fisica para 3D. Su sitio oficial es http://code.google.com/p/jiglibflash/
Para empezar voy a detallar un poco los conceptos para los que no están muy interiorizados con el tema. JigLibFlash es un motor de física 3D. Por lo tanto NO! es un motor de 3D. JigLib es solo la parte que simula la física dentro de una scena en 3D. Es por esto que primero que todo deben tener un motor de 3D, tal como Papervision3D, Away3D, Sandy, etc. Para este ejemplo voy a utilizar Papersivion3D que es el motor que vengo usando hace ya un tiempo.

Lo primero es configurar la parte 3D, en papervision3D se necesita un viewport, una cámara, un render engine y una scena. Para hacer esto rápidamente vamos a extender la clase principal de la clase BasicView que ya implementa todo este sistema para poder renderear en 3d. La idea de esto es no tener que explicar muchas cosas que son netamente de pv3d y ver directamente lo que a JigLib refiere.

Bueno nuestra clase debería verse asi. La función startRendering() hace que comience a renderear pv3d, esto hace que la función onRenderTick sea llamada en cada frame.

Código :

package
{
   import flash.events.Event;
   import org.papervision3d.view.BasicView;

   public class Main extends BasicView
   {
      public function Main()
      {
         super(0, 0, true);

         startRendering();
      }

      override protected function onRenderTick(event:Event = null):void
      {
         super.onRenderTick(event);
      }

   }

}

Con esa base ya podemos comenzar a integrar lo necesario para simular la física. JibLibFlash trae unas classes plugin para interactuar con cada motor 3d especifico. Dentro de la librería van a encontrar una clase que se llama Papervision3DPhysics, esta clase encapsula todo lo necesario para que JigLib funcione, ademas de brindarnos algunas funciones para crear objetos de manera sencilla.

Continuando con el ejemplo, vamos agregar una instancia de esta clase.

Código :

package
{
   import flash.events.Event;
   import jiglib.plugin.papervision3d.Papervision3DPhysics;
   import org.papervision3d.view.BasicView;

   public class Main extends BasicView
   {
      private var _physics:Papervision3DPhysics;

      public function Main()
      {
         super(0, 0, true);

         initPhysics();
         startRendering();
      }

      private function initPhysics():void
      {
         _physics = new Papervision3DPhysics(scene, 7);
      }

      override protected function onRenderTick(event:Event = null):void
      {
         _physics.step();
         super.onRenderTick(event);
      }
   }
}

De acá solo dos lineas a destacar), la creación de la instancia recibe en el constructor la scena(Scene3d de pv3d) y la velocidad, la velocidad es una constante para toda la librería. Y la otra linea es fundamental _physics.step(); que debe hacerse en cada frame para ir actualizando todo, es por esto que esta dentro de la función onRenderTick y antes del super() para que primero actualice todos los valores relacionados a la física y luego renderee los objetos.

Con esas pocas lineas tenemos lo necesario para el ejemplo. Ahora solo resta agregar objetos a la scena, para esto la clase Papervision3DPhysics tiene algunas funciones para hacer esto de manera sencilla.

Crear Suelo

Código :

private function createGround():void
{
   var mat:WireframeMaterial = new WireframeMaterial(0xCCCCCC);
   var ground:RigidBody = _physics.createGround(mat, 1000, 0);
}

Crear Cubos

Código :

private function createBox():void
{
   var materials:MaterialsList = new MaterialsList();
   materials.addMaterial(new WireframeMaterial(0xFF4444), "all");
   var box:RigidBody;
   for (var i:int = 1; i < 5; i++) {
      box = _physics.createCube(materials, 100, 100, 100, 3, 3, 3);
      box.y = 300 * i;
   }
}

Crear Esferas

Código :

private function createSphere():void
{
   var ball:RigidBody;
   for (var i:int = 1; i < 4; i++) {
      ball = _physics.createSphere(new WireframeMaterial(0xFF44FF), 50);
      ball.z = -200;
      ball.y = 300 * i;
   }
}

Estas son las 3 posibilidades que nos ofrece la clase Papervision3DPhysics. También es posible crear los objetos de manera mas abstracta pero no voy a tocar ese tema. Así concluyo con este tip, espero que a alguien le sea de ayuda.

VER EJEMPLO
DESCARGAR ARCHIVOS DEL TUTORIAL

Enviar comentario

Enviar y recibir datos UDP con Adobe AIR 2.0

Miércoles, Marzo 3rd, 2010

En este tip, aprenderemos a enviar información a través de UDP (Universal Datagram Protocol) que es una nueva característica de Adobe AIR 2.0 que nos permitirá enviar y recibir datos, que al ser UDP no garantiza la recepción o entrega, ya que sus cabeceras no llevan el control de datos haciendo ligero los envíos. Al ser así, se puede usar esta nueva característica para aplicaciones con baja latencia y donde la perdida de datos sea indiferente. Por ejemplo puedes utilizar esto con aplicaciones en tiempo real o juegos multiplayer, ejemplos o utilidades pueden haber miles, depende mucho del análisis que hagas.

Para este ejemplo, como ya saben, necesitan tener Flash Builder o eclipse con el SDK de AIR 2.0. De la misma forma puedes ver los anteriores tips que escribí para que te sientas familiarizado con Adobe AIR.

Usaremos la clase DatagramSocket y para eso crearemos una instancia de esta clase. Asimismo, tendremos una variable con la dirección IP que usaremos para la conexión. En este ejemplo usaré la dirección local de mi computador, puedes poner IP de máquinas en tu red y usar el ejemplo en más de un computador.

Código :

private var $__datagramSocket:DatagramSocket;
private var $__IP:String = "127.0.0.1";

Cuando la aplicación se inicie crearemos el constructor de la clase DatagramSocket, agregando un escuchador que permita detectar cuando un mensaje fue recibido:

Código :

$__datagramSocket = new DatagramSocket();
$__datagramSocket.addEventListener( DatagramSocketDataEvent.DATA, dataReceived, false, 0, true );

Adicional a esto el método bind() nos permite establecer la conexión entre el puerto que usaremos y la dirección IP que servirá para dicha conexión. El método receive() es quien nos permite iniciar la escucha de los datos enviados.

Código :

$__datagramSocket.bind( 55555, $__IP );
$__datagramSocket.receive();

El método que usaremos para escuchar cuando los datos lleguen es dataReceived:

Código :

private function dataReceived( event:DatagramSocketDataEvent ):void{
   campo.text = campo.text + "nOtro dice: " + event.data.toString();
}

Para este tip, crearemos un ejemplo básico de chat enviando texto y mostrando la información de otro usuario. Para eso crearemos la siguiente interfaz:

Código :

<s:Label text="Chat:" width="200"  fontWeight="bold"/>
<s:TextArea width="200" height="200" id="campo" text="...INICIA CHAT..." 
         verticalAlign="bottom" editable="false"/>
<s:Label text="Enviar:" width="200"  fontWeight="bold"/>
<s:TextInput id="txtInput" width="200"
          click="{txtInput.text = ''}"
          keyDown="send(event)"
          text="Escribe aqu’ y presiona enter" />

Como ven en el código, al presionar una tecla llamará al método send, nosotros validaremos que sea con ENTER:

Código :

private function send( e:KeyboardEvent = null ):void
{
   if( e.keyCode == Keyboard.ENTER ){
      var data:ByteArray = new ByteArray();
      data.writeUTFBytes(txtInput.text);

      $__datagramSocket.send( data, 0, 0, $__IP, 55554);

      campo.text = campo.text + "nTu dices: " + txtInput.text;
      txtInput.text = "";
   }
}

Es necesario aclarar que los puertos donde se conectarán deben estar libres y no siendo utilizados incluso por varias de esta misma app, además de tener permisos de seguridad. Aquí te dejo el código completo de la app que hice, es sólo un demo pero creo que sirve como base para que puedas crear cosas impresionantes.

Código :

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
                  xmlns:s="library://ns.adobe.com/flex/spark"
                  xmlns:mx="library://ns.adobe.com/flex/mx"
                  creationComplete="init()"
                   width="236" height="300">
   <s:layout>
      <s:VerticalLayout horizontalAlign="center" paddingTop="10"/>
   </s:layout>

   
   <fx:Script>
      <![CDATA[
         
         private var $__datagramSocket:DatagramSocket;
         private var $__IP:String = "127.0.0.1";
         
         private function init():void{
            
            $__datagramSocket = new DatagramSocket();
            $__datagramSocket.addEventListener( DatagramSocketDataEvent.DATA, dataReceived, false, 0, true );
            $__datagramSocket.bind( 55555, $__IP );
            $__datagramSocket.receive();
         }
         
         private function dataReceived( event:DatagramSocketDataEvent ):void{
            campo.text = campo.text + "nOtro dice: " + event.data.toString();
         }
         
         private function send( e:KeyboardEvent = null ):void
         {
            if( e.keyCode == Keyboard.ENTER ){
               var data:ByteArray = new ByteArray();
               data.writeUTFBytes(txtInput.text);
               
               $__datagramSocket.send( data, 0, 0, $__IP, 55554);
               
               campo.text = campo.text + "nTu dices: " + txtInput.text;
               txtInput.text = "";
            }
         }
         
      ]]>
   </fx:Script>
   
   <s:Label text="Chat:" width="200"  fontWeight="bold"/>
   <s:TextArea width="200" height="200" id="campo" text="...INICIA CHAT..." 
            verticalAlign="bottom" editable="false"/>
   <s:Label text="Enviar:" width="200"  fontWeight="bold"/>
   <s:TextInput id="txtInput" width="200"
             click="{txtInput.text = ''}"
             keyDown="send(event)"
             text="Escribe aqu’ y presiona enter" />
   
</s:WindowedApplication>

Puedes descargar el demo aquí

Enviar comentario

Acceder a dispositivos de almacenamiento en AIR 2.0

Viernes, Febrero 26th, 2010

Este es uno de los tips de Adobe AIR 2.0 que más me agradó preparar, porque en realidad tenía la necesidad, en un proyecto, de acceder a dispositivos de almacenamientos para leer, editar y grabar información. La clase StorageVolume nos permite leer todos los archivos existentes en nuestro dispositivo de almacenamiento, reconociendo los permisos de los archivos, si son de sistema o no, etc. Por otro lado podemos crear y eliminar directorios, así como también archivos: moviendo, copiando, etc. Recuerda que debes tener Adobe AIR 2.0 configurado en tu Flash Builder o Eclipse

Entonces para este tip, haremos una básica aplicación que permita reconocer cuando se insertó o removió un dispositivo de almacenamiento. Empezaremos creando la interfaz:

Código :

<s:Label id="msg" width="100%" y="20" text="inserta un USB drive" 
          verticalAlign="top" textAlign="center"
          color="#110E91" fontWeight="bold"/>
<mx:Box id="boxContent" width="90%" height="126" x="20"  y="40"/>

Ahora crearemos nuestros listener que estén pendientes de cuando el dispositivo sea agregado o retirado, para eso usaremos una función que será ejecutada al iniciar la aplicación:

Código :

private function init():void{
   StorageVolumeInfo.storageVolumeInfo.addEventListener(StorageVolumeChangeEvent.STORAGE_VOLUME_MOUNT, mount, false, 0, true);
   StorageVolumeInfo.storageVolumeInfo.addEventListener(StorageVolumeChangeEvent.STORAGE_VOLUME_UNMOUNT, unMount, false, 0, true);
}

Y escribimos ahora las funciones que nos avisará en el campo de texto:

Código :

private function mount(e:StorageVolumeChangeEvent):void{
   var myDrive:StorageVolume = e.storageVolume;
   msg.text = "Se conectó: "+ myDrive.name + "  Size: "+Math.round( (myDrive.rootDirectory.spaceAvailable /1073741824) *100)/100 +" Gb";
}
         
private function unMount(e:StorageVolumeChangeEvent):void{
   msg.text = "Se removió: "+ e.rootDirectory.nativePath;
}

Si conectamos un dispositivo:

Si retiramos el dispositivo:

Vemos que nuestro evento StorageVolumeChangeEvent nos avisa cuando un dispositivo fue agregado o removido, este a su vez, nos envía información importante como por ejemplo el nombre, el espacio disponible, que tipo es ("FAT", "NTFS", "HFS" o "UFS"), etc. Pero lo más importante es poder acceder a los archivos que contiene.

Reconocer los archivos

En realidad hasta aquí es el tip de acceso a dispositivos de almacenamiento, pero decidí ampliarlo un poco más reconociendo los archivos que contiene, para eso usaremos la propiedad rootDirectory y recorreremos el dispositivo usando el método getDirectoryListing().

Usaré una función que nos haga el trabajo de reconocer los directorios (carpetas) y archivos para poder guardarlos en un arreglo y usarlo después:

Código :

private var $__arrFile:Array = new Array();

private function readDrive( files:File ):void{
   var arr:Array = files.getDirectoryListing();
   for each (var f:File in arr){
      if (f.isHidden == false){
         if (f.isDirectory){
            trace("Directorio", f.name);
         }else{
            trace("archivo", f.name );
            $__arrFile.push(f);
         }
      }
   }
}

Listo!!!, tenemos guardado en el arreglo todos los archivos que podemos acceder.

¿Y ahora?

Ya tenemos los archivos del dispositivo y podemos basarnos en el anterior tip que hice de Abrir archivos con Adobe AIR 2.0, creando una lista y abriendo con la aplicación por defecto cada file.

Nos valdremos de un componente creado en Flex para poder colocar el nombre del archivo y su id del array. Lo llamaremos MyBox.mxml.

Código :

<?xml version="1.0" encoding="utf-8"?>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
       xmlns:s="library://ns.adobe.com/flex/spark"
       xmlns:mx="library://ns.adobe.com/flex/mx"
       creationComplete="init()"
       width="200" height="20">
   <s:Label x="10" y="5" width="180" height="15"
          id="campo" buttonMode="true"/>
   
   <fx:Script>
      <![CDATA[
         public var idBox:int;
         
         private function init():void{
            this.addEventListener(MouseEvent.MOUSE_OVER, mouseEvent, false, 0, true);
            this.addEventListener(MouseEvent.MOUSE_OUT, mouseEvent, false, 0, true);
         }
         
         public function setLabel(myText:String):void{
            if(myText.length>=20)
               myText = myText.substr(0,15)+"..."+myText.substr(myText.length-4,4);
            campo.text = myText
         }
         
         private function mouseEvent(e:MouseEvent):void{
            if(e.type == MouseEvent.MOUSE_OVER)
               this.alpha = 0.2;
            else
               this.alpha = 1;
         }
      ]]>
   </fx:Script>
   
</s:Group>

Volvemos a nuestra aplicación y creamos una función que utilice el componente MyBox y haga la lista:

Código :

private function createList():void{
   for (var i:int = 0; i< $__arrFile.length; i++) {
      var box:MyBox = new MyBox();
      box.setLabel( $__arrFile[i].name );
      box.y = 30*i;
      box.idBox = i;
      box.addEventListener(MouseEvent.CLICK, go, false, 0, true);
      boxContent.addElement(box);
   }
}

He creado un listener de Mouse que llama al evento go, que abrirá el archivo con su aplicación por defecto:

Código :

private function go(e:MouseEvent):void{
   var tmp:File = ($__arrFile[e.currentTarget.idBox] as File);
   tmp.openWithDefaultApplication();
}

Y con eso tenemos ya nuestra aplicación funcionando, reconociendo los archivos de tu dispositivo de almacenamiento y al dar click abrir el archivo.

Ingresamos un dispositivo:

Hacemos click a un elemento de la lista, por ejemplo al SWF:

Eso es todo, quería hacer los thumb pero creo que ya salía un poco del tip, pero haré otro con eso :P Aquí les dejo el código completo:

Código :

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
                  xmlns:s="library://ns.adobe.com/flex/spark"
                  xmlns:mx="library://ns.adobe.com/flex/mx"
                  creationComplete="init()"
                  width="300" height="200">

   <fx:Script>
      <![CDATA[
         
         private var $__arrFile:Array = new Array();
         
         private function init():void{
            StorageVolumeInfo.storageVolumeInfo.addEventListener(StorageVolumeChangeEvent.STORAGE_VOLUME_MOUNT, mount, false, 0, true);
            StorageVolumeInfo.storageVolumeInfo.addEventListener(StorageVolumeChangeEvent.STORAGE_VOLUME_UNMOUNT, unMount, false, 0, true);
         }
      
         private function mount(e:StorageVolumeChangeEvent):void{
            var myDrive:StorageVolume = e.storageVolume;
            msg.text = "Se conectó: "+ myDrive.name + "  Size: "+Math.round( (myDrive.rootDirectory.spaceAvailable /1073741824) *100)/100 +" Gb";
            readDrive( myDrive.rootDirectory );
         }
         
         private function unMount(e:StorageVolumeChangeEvent):void{
            msg.text = "Se removió: "+ e.rootDirectory.nativePath;
         }
         
         private function readDrive( files:File ):void{
            var arr:Array = files.getDirectoryListing();
            for each (var f:File in arr){
               if (f.isHidden == false){
                  if (f.isDirectory){
                     trace("Directorio", f.name);
                  }else{
                     trace("archivo", f.name );
                     $__arrFile.push(f);
                  }
               }
            }
            createList();
         }
         
         private function createList():void{
            for (var i:int = 0; i< $__arrFile.length; i++) {
               var box:MyBox = new MyBox();
               box.setLabel( $__arrFile[i].name );
               box.y = 30*i;
               box.idBox = i;
               box.addEventListener(MouseEvent.CLICK, go, false, 0, true);
               boxContent.addElement(box);
            }
         }
         
         private function go(e:MouseEvent):void{
            var tmp:File = ($__arrFile[e.currentTarget.idBox] as File);
            tmp.openWithDefaultApplication();
         }
      ]]>
   </fx:Script>
   
   <s:Label id="msg" width="100%" y="20" text="inserta un USB drive" 
          verticalAlign="top" textAlign="center"
          color="#110E91" fontWeight="bold"/>
   <mx:Box id="boxContent" width="90%" height="126" x="20"  y="40"/>
   
</s:WindowedApplication>

Pueden descargar la aplicación aquí.

Enviar comentario

Control de errores globales en Adobe AIR 2.0

Miércoles, Febrero 24th, 2010

En muchas ocasiones cuando trabajamos con aplicaciones pueden aparecer errores no controlados o inesperados, que muchas veces podemos controlar, pero otras fueron realmente imprevistos. Para eso la nueva versión de Adobe AIR implementa un controlador de errores globales (usando AIR 2.0 y FlashPlayer 10.1), con lo cual NO QUIERE DECIR que, nosotros, los desarrolladores no prestemos importancia al control de errores, sino que será una previsión en caso de no entender porque existió un error desconocido. Por ejemplo, podemos usar la clase UncaughtErrorEvent para detectar un error imprevisto y este ser enviado vía email o al servidor para que nosotros lo solucionemos.

Para empezar, como en los demás tips que escribí, usaremos Flash Builder y el SDK de AIR 2.0.

Primero crearemos la interfaz, un botón que obligue al error y un textArea que nos muestre los mensajes:

Código :

<s:Button id="btn" label="Disparar Error"
           click="viewError(event)"
           horizontalCenter="0" top="10"/>
<s:TextArea  id="txtResp"
           horizontalCenter="0" top="40" width="80%" height="160"
           verticalAlign="top" textAlign="left" color="#FF0000"/>

Ahora utilizaremos la clase UncaughtErrorEvent que nos permite controlar los errores globales.

Código :

loaderInfo.uncaughtErrorEvents.addEventListener(UncaughtErrorEvent.UNCAUGHT_ERROR, captureError );

Cabe resaltar que podemos controlar errores del propio main de la aplicación, así como otros generados desde swf externos utilizando:

  • LoaderInfo.uncaughtErrorEvents
  • Loader.uncaughtErrorEvents

Estos deben ser escuchados desde el SWF principal ;)

Siguiendo con el ejemplo, nuestro botón llamará a una función que nos genere el error:

Código :

private function viewError(e:Event):void{
   var foo:String = null;
   trace(foo.length);
}

Este error será escuchado por el evento UncaughtErrorEvent y ejecutará nuestra función captureError:

Código :

private function captureError(e:UncaughtErrorEvent):void{
   txtResp.text = "CaptureError";
   if (e.error is Error){
      var error:Error = e.error as Error;
      txtResp.text +=   "nnError ID: " + error.errorID +
                        "nnError Name: " + error.name +
                        "nnError Message:n" + error.message
   }else{
      var errorEvent:ErrorEvent = e.error as ErrorEvent;
      txtResp.text += "n" + errorEvent.errorID
   }
}

Es una gran ventaja el uso de esta clase, ya que nos permite no sólo poder conocer, vía email por ejemplo, de algún error inesperado, sino que podemos decidir si la aplicación puede o no continuar, ya que muchas veces estos errores impiden el flujo normal de la aplicación.

El código completo está aquí:

Código :

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
                  xmlns:s="library://ns.adobe.com/flex/spark"
                  xmlns:mx="library://ns.adobe.com/flex/mx"
                  applicationComplete="init()"
                  width="200" height="230">
   
   <fx:Script>
      <![CDATA[
      
         private function init():void{
            loaderInfo.uncaughtErrorEvents.addEventListener(UncaughtErrorEvent.UNCAUGHT_ERROR, captureError );
         }
         
         private function captureError(e:UncaughtErrorEvent):void{
            txtResp.text = "CaptureError";
            if (e.error is Error){
               var error:Error = e.error as Error;
               txtResp.text +=   "nnError ID: " + error.errorID +
                           "nnError Name: " + error.name +
                           "nnError Message:n" + error.message
            }else{
               var errorEvent:ErrorEvent = e.error as ErrorEvent;
               txtResp.text += "n" + errorEvent.errorID
            }
         }
         
         private function viewError(e:Event):void{
            var foo:String = null;
            trace(foo.length);
         }
         
      ]]>
   </fx:Script>
   
   
   <s:Button id="btn" label="Disparar Error"
           click="viewError(event)"
           horizontalCenter="0" top="10"/>
   <s:TextArea  id="txtResp"
           horizontalCenter="0" top="40" width="80%" height="160"
           verticalAlign="top" textAlign="left" color="#FF0000"/>
   
</s:WindowedApplication>

Puedes descargar aquí el ejemplo.

Enviar comentario

Accede a las DNS desde Adobe AIR 2

Martes, Febrero 23rd, 2010

Entre las novedades de Adobe AIR 2.0 está la posibilidad de obtener el registros de recursos DNS (Domain Name System) gracias a su nueva API DNSResolver, que cuando obtiene los datos solicitados nos dispara un evento DNSResolverEvent. Incluso ahora puedes obtener información de un host IPv4 (32-bits) y IPv6 (64-bits). Aunque existen varios tipos de registros DNS, Adobe AIR implementa sólo 5:

  • ARecord: Clase que devuelve información de 32-bits de la dirección IPv4.
  • AAAARecord: Clase que devuelve información de 64-bits de la dirección IPv6.
  • MXRecord: Clase que proporciona información acerca de un nombre de dominio apuntando a una lista de intercambio de correo (MX).
  • PTRRecord: Se le conoce como "registro inverso", funciona a la inversa del registro A, traduce IP a dominio.
  • SRVRecord: Permite indicar los servicios que ofrece el dominio.

Como ya explicamos en el tip anterior, debemos usar Flash Builder(FB) o eclipse (con el SDK de flex), sumado a esto tenemos que tener el SDK de AIR 2.0.

Entonces, crearemos una instancia de la clase DNSResolver y un listener que nos permita detectar cuando la información llegue a nuestra aplicación, asimismo usaremos un evento ErrorEvent que nos avise en caso ocurra algún problema.

Código :

private var $__dns:DNSResolver;
         
private function init():void{
   $__dns = new DNSResolver();
   $__dns.addEventListener(DNSResolverEvent.LOOKUP, look, false, 0, true);
   $__dns.addEventListener(ErrorEvent.ERROR, error, false, 0, true);
}

Para poder hacer funcionar el DNSResolver usamos:

Código :

$__dns.lookup( "www.google.com" , ARecord );

Eso nos dará como respuesta la ip, por lo menos a la que yo accedo: 74.125.159.106. Dicha información es capturada desde nuestro método look

Código :

private function look (e:DNSResolverEvent):void{
   var records:Array = new Array();
   records = e.resourceRecords;
   //
   txtResp.text = records[0].address;
}

Con esto ya puedes acceder a la IP del dominio que desees, como el resto de respuestas DNS son casi iguales, las implementé en el código y creo que no es necesario explicar, ya que es muy parecido.

Código :

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
                  xmlns:s="library://ns.adobe.com/flex/spark"
                  xmlns:mx="library://ns.adobe.com/flex/mx"
                  creationComplete="init()"
                  width="300" height="290">
   <s:layout>
      <s:VerticalLayout/>
   </s:layout>
   
   
   <fx:Script>
      <![CDATA[
         import flash.net.dns.AAAARecord;
         import flash.net.dns.ARecord;
         import flash.net.dns.DNSResolver;
         import flash.net.dns.MXRecord;
         import flash.net.dns.PTRRecord;
         import flash.net.dns.SRVRecord;
         
         private var $__dns:DNSResolver;
         
         private function init():void{
            $__dns = new DNSResolver();
            $__dns.addEventListener(DNSResolverEvent.LOOKUP, look, false, 0, true);
            $__dns.addEventListener(ErrorEvent.ERROR, error, false, 0, true);
         }
         
         private function look (e:DNSResolverEvent):void{
            var records:Array = new Array();
            records = e.resourceRecords;
            //
            if (records[0] is ARecord)
               txtResp.text = "Addr: " + records[0].address;
            
            else if (records[0] is PTRRecord)
               txtResp.text = "PTR: " + records[0].ptrdName;
            
            else if (records[0] is MXRecord){
               txtResp.text = "Exchange: " + records[0].exchange;
               txtResp.text += "nPreference: " +records[0].preference;
            }
            else if (records[0] is SRVRecord)
            {
               var priority:String = "Priority: " + records[0].priority;
               var weight:String = "Weight: " + records[0].weight;
               var port:String = "Port: " + records[0].port;
               var target:String = "Target: " + records[0].target;
               
               txtResp.text += priority + "n" + weight + "n" + port + "n" + target;
            }
         }
         
         private function error(e:ErrorEvent):void{
            txtResp.text = "ERROR: "+e;
         }
         
         private function go():void{
            var type:String = cbType.selectedItem.label;
            switch(type)
            {
               case "ARecord":
                  $__dns.lookup(campo.text, ARecord);
                  break;
               case "AAAARecord":
                  $__dns.lookup(campo.text, AAAARecord);
                  break;      
               case "MXRecord":
                  $__dns.lookup(campo.text, MXRecord);
                  break;
               case "PTRRecord":
                  $__dns.lookup(campo.text, PTRRecord);
                  break;
               case "SRVRecord":
                  $__dns.lookup(campo.text, SRVRecord);
                  break;
            }
         }
         
      ]]>
   </fx:Script>
   
   <mx:HBox horizontalCenter="0"  paddingTop="10" width="300" horizontalAlign="center">   
      <s:Label text="Consultar:" paddingTop="5"/>
      <s:TextInput id="campo" width="200"/>
   </mx:HBox>
   
   <mx:HBox paddingLeft="10" width="300" horizontalAlign="center">
      <mx:ComboBox editable="false" id="cbType">
         <fx:Array>
            <fx:Object label="ARecord" />
            <fx:Object label="AAAARecord" />
            <fx:Object label="MXRecord" />
            <fx:Object label="PTRRecord" />
            <fx:Object label="SRVRecord" />
         </fx:Array>
      </mx:ComboBox>
      <s:Button id="btn" click="go()" label="Ver información"/>
      
   </mx:HBox>
   
   <mx:Box paddingLeft="10" width="300" horizontalAlign="center">
      <s:TextArea id="txtResp" width="90%" height="200" />
   </mx:Box>
   
</s:WindowedApplication>

Puedes descargar la aplicación aquí.

Enviar comentario

Abrir archivos desde Adobe AIR 2.0

Lunes, Febrero 22nd, 2010

-
Cuando Adobe decidió escuchar a los principales desarrolladores o agencias sobre que les gustaría implementar en la nueva versión de Adobe AIR, muchos de ellos querían abrir archivos externos logrando con esto un gran abanico de posibilidades. Con la nueva versión de Adobe AIR 2.0 se puede seleccionar un archivo y abrirlo con su aplicación por defecto, si este archivo no tiene asignado una aplicación con cual poder abrir, mostrará un error. Por otro lado, no puedes acceder a este archivo para manipularlo ya que te saldrá un mensaje de Seguridad (por lo menos no con File, lo veremos en otro tip).

Como ya explicamos en el tip anterior, debemos usar Flash Builder(FB) o eclipse (con el SDK de flex), sumado a esto tenemos que tener el SDK de AIR 2.0.

Vamos a crear un boton en FB para que nos dispare una función:

Código :

<s:Button id="btn" label="Open File" click="openNewFile()" />

La función nos abrirá el browser para poder seleccionar el archivo que deseamos:

Código :

private var $__file:File;
         
private function openNewFile():void{
   $__file = new File();
   $__file.addEventListener(Event.SELECT, fileSelected, false, 0, true);
   $__file.browseForOpen("Buscar archivo a abrir!!");
   //con esto también podemos poner un título a la ventana que abrirá
}

Nuestro evento Event.SELECT será ejecutado cuando ya tengamos aceptado el archivo que seleccionamos.

Código :

private function fileSelected(e:Event):void{
   try {
      //aquí la magia
      $__file.openWithDefaultApplication();
   } catch(error:Error) {
      trace("Problemas con el archivo a abrir");
   }
}

Y listo, con esto podemos probar y ver que logramos abrir un .PSD en Photoshop o un .DOC en Word, siempre y cuando estas apicaciones sean "por defecto".

Aquí el código completo

Código :

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
                  xmlns:s="library://ns.adobe.com/flex/spark"
                  xmlns:mx="library://ns.adobe.com/flex/mx" width="356" height="183">
   
   <fx:Script>
      <![CDATA[
         
         private var $__file:File;
         
         private function openNewFile():void{
            $__file = new File();
            $__file.addEventListener(Event.SELECT, fileSelected, false, 0, true);
            $__file.browseForOpen("Buscar archivo a abrir!!");
         }
         
         private function fileSelected(e:Event):void{
            try {
               $__file.openWithDefaultApplication();
            } catch(error:Error) {
               trace("Problemas con el archivo a abrir");
            }
         }
         
      ]]>
   </fx:Script>
   
   
   <s:Button id="btn" label="Open File" click="openNewFile()" horizontalCenter="0" verticalCenter="0"/>
   
   
</s:WindowedApplication>

Descarga la aplicación aquí

Enviar comentario

Multitouch con Adobe AIR 2, Flash Lite 4 y Flash Player 10.1

Lunes, Febrero 22nd, 2010

-
Con las novedades del Flash Player 10.1, Flash Lite 4 y AIR 2.0 existe una que a los usuarios de iphone o macbook les debe ser muy familiar, el multitouch. En este tip enseñaremos como utilizar la clase TransformGestureEvent que nos permite zoom y rotar elementos. Para eso necesitamos Flash Builder con el SDK de AIR 2.0 que ya pueden descargar del sitio Adobe Labs. Cuando Flash CS5 sea liberado, también podrán usarlo para sus aplicaciones.

Una vez configurado el SDK de AIR 2.0, creamos un proyecto FLEX del tipo Desktop (Adobe AIR) y lo primero que haremos es cargar una imagen que usaremos de ejemplo:

Código :

var l:Loader = new Loader();
l.load(new URLRequest("logo.png"));
l.x = l.y = -100;
$__img1 = new Image();
$__img1.addChild(l);
this.addElement($__img1);
$__img1.x = $__img1.y = 200;

Con eso agregamos un elemento a nuestro stage de la aplicación, y ahora pasamos a agregar un evento para que detecte la rotación, usaremos el evento TransformGestureEvent del tipo GESTURE_ROTATE

Código :

this.addEventListener(TransformGestureEvent.GESTURE_ROTATE, _rotation, false, 0, true);

Este evento se dispará cuando se detecte los dos dedos sobre el stage y hagas el movimiento de rotación

Código :

private function _rotation(e:TransformGestureEvent):void{
$__img1.rotation += e.rotation;
}

Ahora, si queremos usar el zoom o escalar los elementos abriendo o cerrando los dedos sobre el stage usamos GESTURE_ZOOM del evento TransformGestureEvent.

Código :

this.addEventListener(TransformGestureEvent.GESTURE_ZOOM, _zoom, false, 0, true);

Y creamos su función:

Código :

private function _zoom(e:TransformGestureEvent):void
{
   if (e.scaleX > 1)
   {
      $__img1.scaleX += e.scaleX / 100;
      $__img1.scaleY += e.scaleY / 100;
   }
   else
   {
      $__img1.scaleX -= e.scaleX / 100;
      $__img1.scaleY -= e.scaleY / 100;
   }
}

Aquí es necesario un IF porque siempre está detectando que el zoom actual es 1 cada vez que interactuas, entonces si juntas los dedos al momento de querer hacer ZoomIN, irá de 1.0, 0.9, 0.8 así sucesivamente.

La aplicación final quedaría así:

Código :

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
                  xmlns:s="library://ns.adobe.com/flex/spark"
                  xmlns:mx="library://ns.adobe.com/flex/mx"
                  creationComplete="init()"
                  width="320"
                  height="400">

   <fx:Script>
      <![CDATA[
         import mx.controls.Image;
         private var $__img1:Image;

         //
         private function init():void
         {
            var l:Loader=new Loader();
            l.load(new URLRequest("logo.png"));
            l.x=l.y=-100;
            $__img1=new Image();
            $__img1.addChild(l);
            this.addElement($__img1);
            $__img1.x=$__img1.y=200;
            //
            $__img1.addEventListener(MouseEvent.MOUSE_DOWN, activeMove, false, 0, true);
            $__img1.addEventListener(MouseEvent.MOUSE_UP, activeMove, false, 0, true);
            this.addEventListener(TransformGestureEvent.GESTURE_ROTATE, _rotation, false, 0, true);
            this.addEventListener(TransformGestureEvent.GESTURE_ZOOM, _zoom, false, 0, true);
         }

         private function _rotation(e:TransformGestureEvent):void
         {
            $__img1.rotation+=e.rotation;
         }

         private function _zoom(e:TransformGestureEvent):void
         {
            if (e.scaleX > 1)
            {
               $__img1.scaleX+=e.scaleX / 100;
               $__img1.scaleY+=e.scaleY / 100;
            }
            else
            {
               $__img1.scaleX-=e.scaleX / 100;
               $__img1.scaleY-=e.scaleY / 100;
            }
         }

         private function activeMove(e:MouseEvent):void
         {
            if (e.type == MouseEvent.MOUSE_DOWN)
               $__img1.startDrag();
            else if (e.type == MouseEvent.MOUSE_UP)
               $__img1.stopDrag();
            else
               throw new Error("upsss!!!");
         }
      ]]>
   </fx:Script>
</s:WindowedApplication>

Puedes descargar el ejemplo aquí, necesitas tener el runtime de AIR 2

Enviar comentario

Por qué abandoné Actionscript 2 y amo Actionscript 3

Lunes, Febrero 22nd, 2010

-
Soy de las personas que odian el cambio, nunca me he sentido conforme con cambiar nada de mi vida, menos las cosas que me hacen feliz y me dan mucho dinero. Ergo cambiar de AS2 a AS3, era según mi definición innecesario. Podría crear lo mismo en AS2, no había razón.

Los años pasaron y AS3 empezó a sonar demasiado fuerte para mi gusto, el foro de AS3 era más movido que el de AS2. Decidí aprender AS3, para ver que onda. Nada más, no cambiaría, solo verlo.

El doloroso arranque

Comencé como todos, desde www.google.com y www.cristalab.com. Leí y leí como loco antes de ponerme con mi primera línea, molesté a Freddie, Gerson y algunos más en el foro para sacarme dudas existenciales. El puto AS3 me cambiaba todo, modelo de eventos, forma de programar, cargar, etc. Maldita sea! Creí que sería insufrible. Un botón ahora era:


Del tutorial básico de botones y eventos en Actionscript 3 de Cristalab.

Luego la cosa se complicaba en el terreno de la programación orientada a objetos en AS3, DocumentClass, etc. Estuve 3 días mirando a mi alrededor toda esta información, hasta que decidí hacer un proyecto por mi mismo.

El primer proyecto en Actionscript 3: Wow!

Simplemente wow, no lo podía creer. En segundos tenía montado mi escenario, estaba todo ordenado. Comencemos a hablar del maravilloso modelo de carga. Este loadMovie con esteroides. Ahora si tenía mucha lógica cargar cosas en Flash, es un sueño. Todo bajo un mismo modelo, prolijo, sin problemas de niveles. Simplemente cargo, trato la info según lo cargado y lo añado al DisplayObject. Easy!

Luego me encontré con el Document Class, que maravilloso. Nada de código en el primer keyframe o idioteces. Ahora puedo tener el código no esencial bien prolijo en mi Document Class. Eso hace que sea coherente usar clases.

¡Y ni hablar de la comunicación entre clases! El modelo de eventos es genial, un poco de entusiasmo en la programación y tienes un método fácil de comunicar eventos sin usar demasiados recursos.

AS3 mejoró mi manejo de proyectos

Además del orden implícito en todo esto, empiezas a obligatoriamente encapsular todo, mantener todo muy ordenado. Eso lleva a reutilizar como perros. Cada Clase que crean les ayuda luego, no más líos con ese mismo problema a futuro. Uno termina siendo casi fanático, teniendo su carpeta de clases para proyectos, llena de maravillosas cosas que podemos hacer solo haciendo new algo();

En definitiva, realmente chicos, les recomiendo abandonen AS2, conozcan AS3 y no podrán dar una vuelta atrás. Desarrollarán más eficiente, serán más practico para ustedes y más reutilizable. Solo anímense y verán!

Enviar comentario