Programando en AS3 desde Flash CS3 (II)
En el primer artÃculo de esta serie vimos que cuando escribimos código en el timeline o añadimos movieclips en el escenario éstos se acababan convirtiendo en parte de una clase.
Como esto sucede de manera transparente, quizá pensemos que no es necesario saber qué está pasando a nivel interno para utilizar AS3 desde Flash. Para los casos planteados en la primera parte esto se cumple, pero hay otros casos que ahora sà influyen en nuestra manera de trabajar.
Para ilustrar esta afirmación, vamos a centrarnos en uno de los casos más significativos: el por qué ha dejado de funcionar el parent en AS3.
El parent y el error 1119 en AS3
Utilicemos un ejemplo muy tonto para recrear este error. Tenemos dos animaciones en el escenario, cada una contenida en un movieclip, y queremos que al finalizar la primera ésta informe a la segunda para que se reproduzca. Algo asÃ:
Los nombres de los movieclips son bola_gris y bola_azul (que tiene un stop() en el primer frame para evitar que se reproduzca). Para darle esta funcionalidad a la pelÃcula nos metemos dentro de bola_gris y en el último frame de la animación añadimos el siguiente código:
-
stop();
-
parent.bola_azul.play(); //Ya no se utiliza más _parent
Algo tan simple, que llevamos toda la vida haciéndolo en anteriores versiones de flash, ahora en el compilador nos genera este crÃptico error:
1119: Access of possibly undefined property bola_azul through a reference with static type flash.display:DisplayObjectContainer.
Vamos con un poco de teorÃa que nos ayudará a entender qué está pasando.
Las clases dinámicas y las clases selladas
Una clase dinámica (dynamic class) es aquella que te permite añadir y modificar propiedades y métodos en tiempo de ejecución. Por el contrario, una clase sellada (sealed class) es aquella que sólo puede utilizar las propiedades y los métodos que se han definido en tiempo de compilación. Por ejemplo:
-
// MovieClip es una clase dinámica,
-
// no hay ningún problema en añadir 'propiedad1'
-
var mc:MovieClip = new MovieClip();
-
mc.propiedad1 = "texto";
-
-
// Sprite es una clase sellada, al intentar añadir
-
// 'propiedad1' el compilador nos dará un error
-
var sp:Sprite = new Sprite();
-
sp.propiedad1 = "texto";
Un paseo por AS2
La clase dinámica más representativa es Object, que sirve precisamente para crear nuestro propio objeto y añadirle funcionalidades. En AS2, que es una fiesta, todas las clases son dinámicas, y no es extraño sabiendo que Object es la base de todas las clases de AS2.
A lo mejor te estás preguntando si realmente esto es cierto, ya que algunas dan errores si le añadimos alguna propiedad. Cojamos la clase Point de AS2 para hacer la prueba, que además tiene el atributo intrinsic (se encuentra definida en el flash player, Point.as sólo especifica las propiedades, métodos y datos para poder realizar la comprobación de tipos en el momento de la compilación):
-
import flash.geom.Point;
-
var a:Point = new Point(1,2);
-
a.propiedad1 = "texto";
El compilador nos dice:
There is no property with the name 'propiedad1'.
Ahora vamos a hacer lo mismo pero engañando al compilador:
-
import flash.geom.Point;
-
var a:Point = new Point(1,2);
-
a[propiedad1] = "texto";
Además de dejarnos compilar, si probamos a hacer un trace(a[propiedad1]) nos devuelve "texto".
Como ya comenté al final del primer artÃculo, AS2 no deja de ser un envoltorio de AS1 que añade sintaxis para trabajar de una manera más orientada a objetos. Las clases que nos dan error, como Point, simplemente comprueban a la hora de compilar, pero en tiempo de ejecución todas son tipadas dinámicamente.
Volvamos de nuevo a AS3 y al parent
En AS3 es justo al revés, por defecto todas las clases son selladas, aunque se pueden utilizar como dinámicas añadiendo el atributo dynamic en la definición.
Si buscamos en la referencia de AS3 información sobre parent, vemos que es una propiedad de DisplayObject y que devuelve un DisplayObjectContainer. Cuando utilizamos la propiedad parent en bola_gris, lo único que sabe el compilador sobre el padre de bola_gris es que es del tipo DisplayObjectContainer, puede que sea un sprite o un movieclip (como realmente es el caso), pero el compilador no tiene manera de saberlo, lo único que nos puede garantizar es que se trata de un DisplayObjectContainer ya que bola_gris es un hijo. DisplayObjectContainer es una clase sellada, de ahà que genere error cuando intentamos añadir una propiedad que el compilador desconoce.
1119: Access of possibly undefined property bola_azul through a reference with static type flash.display:DisplayObjectContainer.
Efectivamente, bola_azul no es una propiedad que defina la clase DisplayObjectContainer. Conocida la causa, el error ya no es tan crÃptico...
Como movieclip es una clase dinámica que sà permite añadir propiedades, y como nosotros sà que podemos garantizar que el padre de bola_gris es un movieclip, podemos ayudar al compilador indicándoselo de la siguiente manera:
-
MovieClip(parent).bola_azul.play();
¡Ahora sà nos deja! Esto es lo que se conoce en programación como casting, que es proveer al compilador de información de un objeto cuando no puede determinarla correctamente. También se utiliza el casting para forzar la conversión entre tipos primitivos. Podemos utilizar el casting de dos maneras, en este caso idénticas:
-
MovieClip(this.parent.parent).mc.alpha = .5;
-
// o también
-
(this.parent.parent as MovieClip).mc.alpha = .5;
El casting no sólo es necesario con el parent, también será necesario si queremos utilizar el root o al cargar un swf con el objeto Loader, para indicarle al compilador qué tipo estamos cargando (un sprite o un movieclip, por ejemplo). En general, siempre que queramos recorrer la DisplayList de manera manual nos hará falta.
Desactivando el modo estricto
Me gustarÃa hacer hincapié en el hecho que no hay ningún problema con el código: existe un padre movieclip y un hijo movieclip, con lo que hacer el parent es correcto. El único problema es que el compilador no lo sabe y no nos deja avanzar.
Flash CS3 tiene por defecto activado lo que se conoce como Strict Mode. En modo estricto, los errores de tipo se resuelven tanto en modo de compilación como en modo de ejecución. Si queremos volver a la flexibilidad de AS2 en este sentido, podemos desmarca la opción, que se encuentra en Publish Settings > ActionScript Settings:

Una vez ignorada la comprobación de tipos en compilación, en runtime el código del principio no generará ningún error:
-
// Con Estrict Mode desactivado el código no falla
-
parent.bola_azul.play();
Evidentemente, es aconsejable no desactivar este modo, ya que nos provee de un mecanismo para detectar fallas en nuestro código, y al obligarnos a tipificar las variables y objetos aumenta el rendimiento del programa. Cuanta más información tenga el compilador, mejor.
Utilizando eventos para comunicarse
Siendo puristas, utilizando código tipo
-
Movieclip(parent.parent).miVariableInit = true;
-
Object(parent.parent.parent).miObjeto.hazEstaAccion();
estamos rompiendo uno de los principios básicos de la OOP: la encapsulación. Este código genera dependencias de ruta y en programas muy grandes puede llegar a ser muy difÃcil de mantener.
Para ello podrÃamos utilizar el nuevo modelo de eventos de AS3, dispachando eventos a llegar un punto concreto de la aplicación que otros objetos podrán escuchar para actuar en consecuencia.
Nota: no voy a profundizar en el modelo de eventos porque se podrÃa alargar bastante, y el artÃculo ya está quedando algo extenso. De momentos nos basta con saber que podemos utilizar otra opción más.
Al final, ¿qué manera es la mejor?
Nunca hay una manera necesariamente mejor, siempre hay que buscar un equilibrio entre el nivel del desarrollador y los requisitos. Yo distinguirÃa entre tres tipos de situaciones:
- Un programador de cualquier nivel trabajando con Flash CS3 deberÃa intentar siempre "castear" la información.
- Si el proyecto es sencillo y el peso del programa debe correr a cargo de un diseñador/animador, podemos considerar desactivar el Strict Mode. La flexibilidad de flash es lo que ha hecho grande a este programa, tampoco hay que penalizar ahora a los que no programan.
- Si es un proyecto grande y corre a cargo de programadores experimentados, en muchas situaciones puede ser conveniente crearse un modelo de eventos en vez de recorrer manualmente la DisplayList. Aunque al principio es más costoso, los beneficios en mantenimiento lo compensan sobradamente.
Resumiendo
Las clases en AS3, por defecto, son selladas. Con el modificador dynamic podemos cambiar esto.
Flash CS3 utiliza por defecto un modo estricto que comprueba las variables tanto en tiempo de compilación como en tiempo de ejecución. Se puede desactivar pero no es recomendable.
Con este nuevo modo, para poder recorrer la DisplayList manualmente como lo venÃamos haciendo hasta ahora, debemos hacer un cast de los objetos, asà evitaremos los errores de compilación.
El hecho de que un objeto esté "casteado", no implica que sea correcto. Al hacer un casting le decimos al compilador que nosotros asumimos el tipo del objeto. Sino lo hacemos correctamente, obtendremos un error en tiempo de ejecución.
Post publicado el 01 de December de 2007 a las 22:01 por llops
Categorias: ArtÃculos
Etiquetas: as3, casting, Error #1119, flash cs3, parent
¿Quieres seguir los comentarios de esta entrada? RSS 2.0

11 comentarios
#1 Comet!
Aunque cambiarÃa la nomenclatura de los movieclips para evitar confusión (bola_gris por bolagris_mc) está muy bien explicado, sobre todo el casting.
Espero que sigas con esta serie.
Dec 3, 2007
#2 LLops
Hola Comet, la verdad es que siempre utilizo la nomenclatura "_mc", pero aquà mira...
Creo que aún escribiré algún artÃculo más de esta serie ;)
Un saludo!
Dec 4, 2007
#3 j.mat
La verdad es que está bien explicado, pero no acabo de entender cómo es posible que el compilador no sepa que estás utilizando un movieclip y tengas que decÃrselo con el casting...
Dec 10, 2007
#4 LLops
El compilador lo único que hace es evaluar código, no es consciente si tú has cogido un objeto y lo has convertido en MovieClip mediante F8 o lo has convertido en Sprite a través de una instrucción. Sólo puede asegurarnos que pertenece a la clase DisplayObjectContainer por tener contenido.
Además, en as3 es posible reparentar cualquier objeto en la DisplayList (sin tener que destruirlo y crearlo de nuevo, sólo moviéndolo). ¿Qué pasarÃa si limitara los objetos directamente a MovieClip? No se podrÃa reparentar un Sprite, por ejemplo, ya que generarÃa error.
Dec 11, 2007
#5 Alrevez
:D muchas gracias por estos articulos son de mucha ayuda, estaré esperando los próximos muy atento!
Feb 3, 2008
#6 Billy Rippe
No te imaginas lo que luche con este error, llevaba dos dias sin saber que pasaba y estaba muy perdido... no sabia por donde abordarlo... fue tanta la frustracion que cuando sali de la oficina los ojos se me aguaron...
cuando mande la pelicula y funciono... logre respirar cosa que no habia hecho desde ayer por la manana... no se como sobrevivi... Mil gracias
Feb 7, 2008
#7 Juan
Felicidades Llops. De verdad.
Gracias por el tiempo dedicado a escribir.
Feb 15, 2008
#8 Juan
Estaré atento a un futuro artÃculo sobre el modelo de eventos de AS3.
Saludos! ;)
Feb 15, 2008
#9 Eliseo
Sólo como comentario a variables de la pelÃcula principal desde una clase.
Si tenemos algo como
NO va a funcionar, si lo que queremos es añadir "Pelotas" con algo como
Debido a que la Pelota se crea cuando hacemos el new y todavÃa no tiene padre. Aunque sà funcionará si no estamos añadiendo dinámicamente los Objetos.
Para evitar esto, debemos usar el evento ADDED_TO_STAGE
NOTA:Gracias por estos aportes que has hecho
Apr 17, 2008
#10 LLops
Hola Eliseo, tienes toda la razón.
Escribà sobre el tema (pero enfocado a la inicialización de eventos) en este artÃculo:
http://llops.com/blog/2008/02/18/accediendo-al-stage-antes-de-tiempo/
Un saludo!
Apr 17, 2008
#11 k_pqW
No m... Jajaja, wow! ke alegria... llevaba tres dias (literal) tratando de solucionar ese error. Uffff... ¡¡Te amooooo!!!
Jun 4, 2008
¡Deja un comentario!