Programando en AS3 desde Flash CS3 (I)

AS3 no es difícil, y si se tiene una buena base de AS2 (o de otros lenguajes como C# o Java) el cambio no es muy doloroso. Una persona con conocimientos de programación orientada a objetos que empiece en Flex Builder un “Proyecto ActionScript” (sólo código) no tendrá muchas dificultades (evidentemente tendrá que conocer la sintaxis). En cambio, esta misma persona comenzando con Flash, tendrá que familiarizarse con conceptos como timeline o movieclip y entender la relación con el lenguaje.

El problema es que, en esta nueva versión, el programa se ha tenido que adaptar a las características OOP del lenguaje, así que también ha habido cambios que los programadores flash de toda la vida tenemos que asimilar (es muy difícil deshacerse de las viejas prácticas, y más si llevas 4 o 5 versiones del programa).

En este primer artículo vamos a ver qué significan las acciones que realizamos en el IDE de Flash desde el punto de vista de actionscript.

El Document class

Una de las novedades de CS3 es el Document class. Se trata de la clase principal asociada a una película flash, o dicho de otra manera, el punto de arranque de la aplicación. Al declarar el Document class nos ahorramos tener que meter código en el fla.

Document Class

Main es la clase asociada que se encuentra en el paquete com.llops

Veamos el código de nuestra clase Main:

[as3]package com.llops
{
import flash.display.MovieClip;
public class Main extends MovieClip
{
function Main(){
}
}
}
[/as3]

Vemos como la clase está declarada con el modificador public. Esto es un requisito al estar vinculada al document class.

Si especificamos un Document class que no existe, el compilador crea una clase con dicho nombre, y si no declaramos ninguno, el compilador asigna uno de manera transparente. Así pues, todas las aplicaciones flash parten de una clase base.

La clase base debe extender de Sprite, pero si cuenta con código en algún frame o se quiere utilizar la línea de tiempo lo ha de hacer de MovieClip (realmente hay algún caso más, pero de momento nos podemos quedar con los dos principales).

Cualquier código que añadamos en un frame del timeline principal pasará a ser parte de nuestra clase. Por ejemplo, añadamos el siguiente script en el frame1 del fla:

[as3]var texto:String = “diez”;
function test():void{
var numero:int = 10;
trace(texto, numero);//Output: diez 10
}
test();
[/as3]

Al compilar el swf, la clase quedaría prácticamente de la siguiente manera:

[as3]package com.llops
{
import flash.display.MovieClip;
public class Main extends MovieClip
{
public var texto:String = “diez”;
function Main() {
test();
}
public function test():void {
var numero:int = 10;
trace(texto, numero);//Output: diez 10
}
}
}
[/as3]

Al igual que pasa con la clase, por estar declaradas en la línea de tiempo, tanto la variable como la función utilizarán el modificador public.

Llegados a este punto, hemos de quedarnos que una de las principales novedades es que, al compilar nuestra película, todo lo que hayamos hecho en el IDE se traduce a clases en AS3. Esto es válido tanto para código como para los movieclips, gráficos y botones que añadamos en el escenario.

Añadiendo movieclips manualmente al escenario

Si utilizamos flash como herramienta es porque queremos hacer uso de sus capacidades gráficas. Lo que en lenguajes como C++ llevaría horas en flash pueden ser unos pocos minutos.

Volvamos al punto en que no tenemos código en el fla y tenemos nuestra clase Main asociada al document class.

Creemos un movieclip en la biblioteca que tenga forma de cruz (MC Cruz). Arrastremos dos instancias en el escenario: una la dejaremos sin nombre de instancia y a la otra la llamaremos cruz_mc. Ahora añadamos las siguientes líneas en el constructor:

[as3]trace(getChildAt(0),getChildAt(0).name);
trace(getChildAt(1),getChildAt(1).name);
[/as3]

Al ejecutar la película, en el panel de output, veremos lo siguiente:

[object MovieClip] instance1
[object MovieClip] cruz_mc

En la película principal, existen dos objetos de la clase MovieClip (posiciones 0 y 1), con los nombres instance1 (asignado por el compilador) y cruz_mc (asignado por nosotros).

Sabiendo sus nombres no habría ningún problema en hacer lo siguiente

[as3]trace(getChildByName(“instance1”));
trace(getChildByName(“cruz_mc”));
[/as3]

devolviendo dos objetos del tipo MovieClip.
¿Pero qué pasa si probamos el siguiente código?:

[as3]trace(instance1);
trace(cruz_mc);
[/as3]

El compilador arroja el siguiente error

1120: Access of undefined property instance1

ya que no existe ninguna propiedad en la clase que responda a instance1. Aunque nos saltáramos los errores de compilación, en tiempo de ejecución, nos saldría:

Error #1065: No se ha definido la variable instance1.

Si comentamos la línea que genera error, veremos que no hay ningún problema con la segunda, y el trace de cruz_mc devuelve [object MovieClip].

Cualquier objeto que se añade manualmente al escenario se añade también a la DisplayList, por esa razón hemos podido acceder a las dos cruces mediante los métodos getChildAt y getChildByName, definidos en la clase DisplayObjectContainer y que nuestra clase hereda al extender MovieClip.

Sin embargo, al hacer trace de instance1 nos genera un error, ya que no existe realmente ninguna propiedad ni variable definida como tal, sólo es el name que utiliza internamente el compilador para manipularlo como objeto visual. Sin embargo, cruz_mc no devuelve error ya que sí existe como variable de la clase Main. Es más, si utilizamos el debugger de flash podemos encontrar un puntero en memoria reservado para cruz_mc, mientras que no hay rastro de instance1. ¿Por qué?

La razón por la que existe dicha variable es que al trabajar con AS3 en Flash CS3, el compilador provee dos mecanismos para acceder a movieclips que hayan sido creados en línea de tiempo y tengan nombre de instancia:

  1. Asigna el mismo nombre a una variable de la clase
  2. Declara dicha variable

Traducido a código, quedaría así:

[as3]package com.llops
{
import flash.display.MovieClip;
public class Main extends MovieClip
{
// Mecanismo 2:
// Declara una variable del mismo tipo (movieclip)
public var cruz_mc:MovieClip;
function Main()
{
// Mecanismo 1:
// Asigna el movieclip a la variable
// haciendo coincidir el nombre
cruz_mc = getChildByName(“cruz_mc”);
}
}
}
[/as3]

Aunque pueda parecer que el orden de los mecanismos sería más acertado al revés (mecanismo 1 crear variable y mecanismo 2 asignarla), lo he puesto así porque el mecanismo 1 se cumple siempre, mientras que el segundo depende de una opción que tenemos activada por defecto: Automatically declare stage instances.
Esta opción se encuentra en Publish Settings > ActionScript Settings

ActionScript 3.0 Settings

Si desmarcamos esta casilla y probamos a compilar obtenemos el siguiente error:

Error #1056: No se puede crear la propiedad cruz_mc en com.llops.Main.

Para que no haya problemas, debemos declarar manualmente el movieclip como variable de clase, sin olvidarnos que ha de ser pública:

[as3]public var cruz_mc:MovieClip;
[/as3]

Una vez hecho, el compilador mirará la variable, y al coincidir el nombre de instancia del movieclip con la variable, la asignará (mecanismo 1).

Si tenemos la opción marcada y además probamos a declarar la variable, el compilador nos dirá

1151: A conflict exists with definition cruz_mc in namespace internal.

debido a que ya existe.

Esto no sólo pasa con los MovieClips, sino con cualquier objeto al que le podamos dar un nombre de instancia en el escenario, como campos de texto (declarar como TextField) o botones (declarar como SimpleButton)

A priori, parece una gran utilidad que Flash CS3 declare por nosotros las variables, y más si tenemos muchísimos objetos en el escenario, pero esta solución acaba generando un código más difícil de seguir, ya que leyendo el código no sabemos de dónde salen las variables. Además, si se utiliza un editor externo como FlashDevelop o Flex Builder, marca errores o no te da las opciones de autocompletado debido a que no están declaradas.

En la práctica, esta opción me ha dado muchos más problemas que ventajas, así que recomiendo desactivar el check siempre. Al fin y al cabo, esta es una de las mejores prácticas de los lenguajes OOP, tener que declarar todo para suministrar la máxima información posible al compilador.

Resumiendo

AS2, aunque nos da una sintaxis más cercana a OOP, no deja de ser un envoltorio que acaba compilando a actionscript1. Con la llegada de AS3 tenemos realmente un lenguaje orientado a objetos, y el compilador de flash ha tenido que adaptarse. Por ello, cualquier cosa que hagamos en el IDE de Flash tiene su correspondiente transformación a AS3. Todo (código en frames, movieclips en el escenario, etc) acaba compilándose en clases.

El Document class nos proporciona una manera fácil de asociar nuestro fla con la clase principal. Sino declaramos uno, el programa lo hará de manera transparente.

Por otro lado, el compilador nos provee de mecanismos para asignar nuestros objetos en pantalla a variables de clase.

De esta manera, si una persona sin conocimientos OOP elige un proyecto AS3 en Flash, aunque sólo utilice clips de película en el escenario, animaciones e instrucciones sencillas tipo stop(), gracias a las nuevas funcionalidades del compilador, tendrá un verdadero programa orientado a objetos, aunque ni siquiera lo sepa.

Información del artículo

Post publicado el 01 de December de 2007 a las 20:00 por llops

Categorias: Artículos

Etiquetas: , , , ,

Comparte

5 trackbacks

18 comentarios

  • Es decir, los que – como yo – programábamos orientado a objetos sin saberlo, a partir de ahora nos vamos a tener que enterar de todo para seguir con nuestro trabajo. Uffff, no quiero parecer perezoso, pero….lo de declarar cada clip y todo…dan ganas de quedarse en Flash 8….arrrggss.

  • Dependiendo del perfil, es normal que no se quiera pasar a un lenguaje tan “serio” como es as3, pero es que tampoco es necesario que todo el mundo dé el salto. As2 y as1 tienen cuerda para rato, y para un porcentaje altísimo de webs cumplen sobradamente.

    Así que si te sientes más cómodo a la vieja usanza, no pasa nada porque sigas por ahí ;)

  • LLops estas aclaraciones son fantasticas, pero me quedó colgado el tema del checkbox “Automatically declare stage instances”.
    A ver si entendi? al destildar esta opcion, el compilador ya no instancia automaticamente los objetos que estan en el escenario?
    O sea cada vez que haga un addChild tengo que darle un .name a cada objeto? aunque no los utilice a traves del nombre de instancia?

    Gracias y saludos

  • No exactamente.
    El .name no hay que modificarlo (es más, es una mala práctica). Accede por el nombre de la variable, y si, como dices, no utilizas el nombre de instancia, puedes hacerlo por su posición numérica. Ejemplo: getChildAt(1)

    Lo que comentaba sólo sirve para los objetos que hemos añadido manualmente al escenario y les hemos dado un nombre. Si cumple estos dos requisitos hay dos posibilidades:
    – Check tildado: el compilador declara la variable con el mismo nombre que tu le has dado.
    – Check no tildado: el compilador no hace nada, entonces tú en tu clase debes crear la variable con el nombre haciendo que coincida. Sino te dará un error, ya que existe un objeto en el escenario pero no en la clase. El compilador tiene que saber que existe este objeto.

    Espero que haya quedado claro. Un saludo!

  • Muy buen artículo me ha despejado algunas dudas, ahora voy por el segundo.
    Espero que hayan muchos mas acerca AS3, te explicas muy bien :D
    Saludos

  • Has ganado un nuevo lector con éste POST. ;)
    Me suscribo al RSS!!

    Un saludo.

  • Eisen

    Creo que me pasare amenudo por aquí. Felicidades

  • Hola LLops, hace poco que yo tambien he dado el salto, y tal como todos dicen, es genial y horrible al mismo tiempo :p
    A mi lo que mas me preocupa es todo lo relacionado con como trabajar a la vieja usanza, y por ejemplo una de las cosas que no acabo de comprender es el tema de la variable root.

    Esto me tiene loco, pero caso aparte, en el ejemplo que indicas más arriba, pones el caso de que los MovieClips que defines en tu clase, ya están en el escenario.
    ¿Como tratarías a un mc, si por ejemplo está en el fotograma 5?

    Saludos!

  • Hola Timnhe,
    por lo que he ido viendo no eres el único que planteas estas dudas. Estoy pensando en escribir un cuarto artículo enfocado en casos prácticos…

    De todas formas, y en cuanto a tu pregunta específica, no hay que hacer nada especial si tienes un mc definido en un fotograma que no sea el primero. Sólo asegúrate de declarar la variable que coincida con el nombre que le des en el escenario, y el Flash Player, cuando alcance dicho fotograma, asignará el mc a dicha variable y ya la podrás manipular.

  • Negro

    ¿Cómo acceder en AS3 a variables de movieclips diferentes?
    Supongamos que tenemos dos movieclips en el escenario, instanciados, respectivamente, con el nombre de cuadro y bola. Resulta que bola es, además, un contenedor de otro movieclip de nombre bolita. Algo como esto:
    [cuadro] [bola–>bolita]

    En el fotograma 1 del movieclip bolita tengo el siguiente código:
    [as3] var miString:String = “Hola”;[/as3]

    Mi pregunta es, ¿cómo acceder, desde el movieclip cuadro, a la variable “miString” que está en bolita?

    En AS2, esto se resolvía más o menos así:
    [as3] var miOtroString:String = this._parent.bola.bolita.miString;[/as3]

    En AS3, ¿cómo sería?

  • Básicamente es lo mismo, solo que hay que hacer un casting de “parent” para que el compilador no te dé un error:
    [as3]var miOtroString:String = MovieClip(parent).bola.bolita.miString;
    trace(miOtroString);[/as3]

    Mírate el segundo artículo de esta serie que precisamente se explica esto.

  • brujilla88

    Enhorabuena LLops!!!!!
    Se agradece encontrar explicaciones tan claras!!!! me han encantado tus articulos y la verdad es que me han servido de mucha ayuda!!
    (Espero que sigas escribiendo!! =P jeje)
    Un saludo!

  • Gracias! Y prometo volver algún día :)

  • claudio

    hola necesito su ayuda soy nuevo en as3 y estoy tratando de cargar un clip externo en un contenedor pero a la vez que el botón que llama al clip descargue el clip externo que estaba antes en el contenedor este es código que estaba usando.

    [as3] //Boton Contacto

    function ircontacto(event:MouseEvent):void

    {
    var contenedor = new Loader();
    contenedor.load(new URLRequest(“index3.swf”));
    addChild(contenedor);
    }

    function clicked(event:MouseEvent):void {
    root.contenedor.unload();
    root.removeChild(contenedor);
    }

    BTNS.btn_c.addEventListener(MouseEvent.CLICK, ircontacto);
    BTNS.btn_c.addEventListener(MouseEvent.CLICK, clicked); [/as3]

    la primera vez que cargo el botón me funciona pero cuando lo presionó por segunda vez
    me carga encima si eliminar el anterior y me sale este error.

    ArgumentError: Error #2025: El objeto DisplayObject proporcionado debe ser un elemento secundario del llamador.
    at flash.display::DisplayObjectContainer/removeChild()
    at index_fla::MainTimeline/clicked()

    saludos

  • pablo

    Muchas gracias!, esta información me ha sido de mucha utilidad.

  • muchas gracias a todos ustdes por dedicar un rato de su tiempo para colocar en linea estos magnificos articulos son la guia y la esperanza para que gente como yo puedamos seguir adelante de este grandioso y fantastico mundo de la programacion Multimedia,, muchas gracias a todos que contribuyes en la existencia del sitio….

  • Hola, me han pasado los enlaces de tu web porque hacía muchas preguntas en una lista de correo sobre todo esto que estás contando.

    Ostras!!!, me has abierto los ojos por fin en muchas cosas, y las personas que te han comunicado sus dudas justamente han preguntado cosas que yo hacía tiempo que no entendía.

    Muchas gracias por todo!

    Te seguiré en la web, ahora voy a seguir leyendo los demás artículos.

    Saludos!!!

  • Lorena

    alguna vez te respondieorn como solucionar ese problema q tenias con el boton???