Inicio

Diciembre 26, 2005

Cómo convertirse en programador independiente en 1068 días

Gus Mueller, el hombre detrás de Flying Meat, uno de los desarrolladores independientes de aplicaciones para Mac OSX más respetados, cuenta su historia en un post en el que desarrolla siete conceptos que considera básicos para llegar a alcancar el sueño de poder trabajar para uno mismo.

Una buena lectura para estas fechas, en las que se formulan tantos buenos propósitos.

Siete reglas para ser un programador efectivo

Phillip Chu da las que entiende son las siete reglas principales para ser un programador efectivo. Habrá que ponerlo en la lisa de buenos propósitos para año nuevo...

Seven habits of highly effective programmers

Generación Mac

El próximo jueves 19 de enero, como presentación oficial del portal generacionmac.com, especializado en el diseño y desarrollo de aplicaciones bajo plataformas Mac, se celebrará en Madrid el evento “Generación Mac: el futuro de la creación” con el mecenazgo de la Escuela Superior de Negocios y Estudios Internacionales – ESNE.

Este evento, dirigido a cualquier usuario Mac novel o profesional, es de carácter abierto y gratuito y tendrá lugar en las instalaciones de ESNE Madrid de 18h a 21h.

Debido a que el número de plazas es limitado, es necesaria inscripción previa a través del teléfono 91 555 25 28 o en el correo electrónico madrid@esne.edu, indicando sus datos personales y de contacto.

Los sufridos asistentes se tendrán que tragar un ladrillo de una hora titulado "¿Tienes media hora libre? desarrolla una aplicación con Core Data", a cargo de su seguro servidor. No digan que no estaban avisados.

Más información, en ESNE

Diciembre 14, 2005

Ya queda menos para FlashLite 2

Cada día que pasa es un día menos para la salida de FlashLite 2.0. Mosaic, la revista del Graduado Multimedia de la UOC se ha querido adelantar al feliz alumbramiento con un artículo en el que se repasa el estado actual de FlashLite, sus perspectivas de futuro, y se compara con los otros dos pesos pesados de la movilidad: C++ y J2ME.

¿La conclusión final?: va a ser necesario empezar a tomar en serio a FlashLite.

Flash Lite: estado actual y perspectivas de futuro

Noviembre 26, 2005

CÛmo escribir cÛdigo imposible de mantener...

...y asegurarse un trabajo de por vida. Un link de hace bastante tiempo, que habÌa perdido, y que acabo de reencontrar:

How to write unmaintenable code

Noviembre 23, 2005

[Cocoa] Manejo de memoria y excepciones

Objective-C, como cualquier programador iniciado en el mismo sabe, es un lenguaje que, a diferencia de java o actionscript, no tiene recolector de basura, no maneja la memoria por sí mismo, sino que es responsabilidad del programador el liberar los recursos que haya utilizado con anterioridad.

El manejo de memoria no es especialmente complicado, aunque sí requiere atención y un toque de rigurosidad por parte del programador. Eso no evita, que haya situaciones en las que sea fácil producir leaks de memoria, al no preveer alguna situación especial en el programa, como por ejemplo, al lanzar una excepción.

Bien, pues sirvan los dos párrafos anteriores como introducción a este post de Chris Hanson titulado Cocoa memory management & exceptions

Noviembre 03, 2005

Ya en su quiosco

Sí, design-nation sale al quiosco. En el número de noviembre de MacWorld España, aparece publicado un artículo escrito por éste su seguro servidor. Se trata de el Primer Contacto con el Macromedia Studio 8.

Pese a ese artículo, la revista, como siempre, está llena de contenidos interesantes, como una revisión de los servicios .Mac, un informe sobre qué Mac o que iPod elegir (aunque eso es fácil: todos) o un artículo sobre cómo evitar los problemas con iMove HD.

Lo dicho, en el MacWorld de Noviembre.

Noviembre 01, 2005

Poster de patrones de diseño

A estas alturas seguro que has oído hablar (como mínimo) de la serie Head First, en concreto de Head First Design Patterns que probablemente sea la mejor introducción para entender los patrones de diseño.

La semana pasada, cuando estaba buscando otras cosas en amazon, me encontré con esto: Head First Design Patterns Poster.

designPatternsPoster.jpg

Como su propio nombre indica, es un poster (bastante grande, por cierto) que contiene los gráficos (extraídos del libro), no los diagramas UML de los patrones, sino los gráficos de los ejemplos del libro, así como el número de la página en la que aparece ese patrón tanto en el Gang of Four como en el Head First Design Patterns.

Resume de forma visual 18 patrones, y ahora mismo luce enfrente de mis ojos clavado en la pared...

(Por cierto, ninguno de los enlaces es patrocinado, y por tanto NO me llevo comisión).

Octubre 18, 2005

Por cierto...

El Studio 8 de Macromedia ya est· disponible en castellano. Y sÌ, hay licencia para profesores y estudiantes por 85Ä m·s IVA.

Macromedia EspaÒa

Y el patrón era...

Ayer preguntaba por el nombre de un patrón.

El patrón era el Strategy.

Octubre 17, 2005

Un ejemplo del patrÛn... °adivÌnalo!

EDITADO: El patrÛn es el Strategy. Por tanto, el tÌtulo del post deberÌa ser "Un ejemplo el patrÛn Strategy en actionscript"

El Profesor Dispar ha estado disfrutando de unas merecidas vacaciones tras conquistar el mundo (sÌ, desde la ˙ltima vez que tuvimos noticias de Èl, ha conseguido llevar a buen puerto sus malÈficos planes).

Pero el dÌa a dÌa de dominar el mundo le est· matando de aburrimiento. El Profesor Dispar echa de menos los viejos tiempos, cuando nadie le comprendÌa, cuando podÌa odiar a todos los lÌderes del mundo porque le ignoraban... Ahora pasa la mayor parte del dÌa haciendo papeleo, y aÒora los dÌas en los que se podÌa dar una vuelta por los campamentos de sus tropas y confraternizar con ellos, contar chistes, tomar unas cervecitas...

AsÌ que, en un arranque de genio (malvado, claro), ha decidido que, para matar el aburrimiento, quiere ver un desfile cada dÌa. Mejor dicho, un desfile diferente cada dÌa. Un dÌa le pedir· a su Mariscal que le prepare un desfile con los chicos de la compaÒÌa B, otro dÌa querr· que desfilen los soldados cuyo nombre contenga una P... ahhh, los genios del mal...

Continuar leyendo "Un ejemplo del patrÛn... °adivÌnalo!" »

Septiembre 20, 2005

Código fuente de los ejemplos de Flash 8

Acabamos de actualizar los posts de los tres ejemplos de flash 8 que publicamos en su día, añadiendo el código fuente de los mismos:

[Flash 8] Blur filter

[Flash 8] Glow filter

[Flash 8] El sol y su sombra

Septiembre 15, 2005

Sobre las novedades de Flash 8

Estaba escribiendo un comentario a este post de Carlos Rovira, pero como me estaba quedando demasiado largo, he preferido hacer un post aparte.

Está habiendo cierta sensación de "no es para tanto" en un sector de la "comunidad" en relación con la nueva versión de flash.

No sé, no es nada que no se supiera. Siempre se ha dicho desde Macromedia que éste iba a ser un release "para diseñadores" ( aunque probablemente no fuera esas las palabras exactas ).

No hay nuevo set de componentes, cierto. Pero de entre las novedades que sí hay, quisiera resaltar tres que creo eran fundamentales:

  • El cacheo a bitmap: por el empujón que le pega a la performance de cualquier juego. No es lo mismo que el player tenga que recalcular la posición tamaño, contorno, etc de 100 elementos vectoriales en cada frame, a que sólo tenga que colocar 100 bitmaps en pantalla. Una diferencia fundamental cuando cada vez se desarrollan juegos en flash más complejos, y cuando estamos intentando expandir el flash a otras plataformas más limitadas en cuanto a performance que un PC ( móviles, por ejemplo ).
  • El slice9. Otra mejora muy importante. Cuando se están desarrollando aplicaciones sin componentes, que es algo que por mil razones diferentes todos tenemos que hacer muchas veces, es fundamental el poder escalar los elementos de interfaz de forma sencilla. Imaginemos, por ejemplo, un tooltip con las esquinas redondeadas a mostrar cuando se hace rollover de un elemento de pantalla. Hasta ahora era el desarrollador el que tenía que partir el gráfico en 9 piezas, e implementar un mecanismo para que se dibujara de forma apropiada dependiendo de las dimensiones que se le pasaran. Ahora ya no hay que hacer todo eso.
  • Carga dinámica de png, y manejo de movieclips con fondos bitmap. Otra de las cosas por las que el flash no terminaba de despegar en muchos entornos. El no poder cargar png de forma dinámica era, en muchas ocasiones, un problema, sobre todo dada la facilidad para generarlos desde cualquier aplicación java en servidor. Pero ahora no sólo se pueden cargar esos elementos de forma dinámica, sino que se pueden utilizar como fondos o rellenos de movieclips. ¿Ventajas?. Pues seguro que cada uno es capaz de encontrar una ventaja diferente.

Hay más cosas, por supuesto. Los filtros aplicables a movieclips, la subida de archivos...

Para ser un release orientado a los creativos, se han implementado muchas cosas de las que también nos vamos a beneficiar los desarrolladores. Y esto es flash, se trata de hacer las cosas bonitas, muy muy bonitas...

No hay set de componentes nuevo. En mi opinión, porque necesitan una reescritura desde cero, algo que ahora no se podía asumir. Todo llegará.

Septiembre 14, 2005

Para no volverse loco

Si se programa en varios lenguajes, va a llegar un momento en el que las distintas sintaxis se van a cruzar.

Syntax across languages es un proyecto de sourceforge que pretende documentar cÛmo se hacen las cosas en distintos lenguajes. Por ejemplo, cÛmo se declara una funciÛn o un bloque if.. else o un bucle en java, C, C#, C++, Perl,....

En todo caso, aunque sÛlo sea por satisfacer la curiosidad de ver cÛmo hacen las cosas "los otros", no viene mal echarle un vistazo.

Via __resolve

Agosto 10, 2005

[Flash 8] El sol y su sombra

Arrastra el sol alrededor de la tierra y ver·s cÛmo la sombra que Èsta proyecta cambia. Necesitar·s la flash player 8 public beta




Para este ejemplo, he utilizado algunas de las nuevas clases de flash 8, como los filtros glow, dropshadow y bevel, asÌ como alguna de las nuevas clases para c·lculos geomÈtricos.

ACTUALIZACI”N 20/9/05: Descarga el cÛdigo fuente

Agosto 08, 2005

[Flash 8] Glow filter




Haz click en el fondo

Es necesario el flash player 8:
http://www.macromedia.com/software/flashplayer/public_beta/

ACTUALIZACI”N 20/9/05: Descarga el cÛdigo fuente

[Flash 8] Blur filter





Haz click en el fondo

ACTUALIZACI”N 20/9/05: Descarga el cÛdigo fuente

Anuncio oficial de la nueva versiÛn de Flash

Ya se ha anunciado la nueva versiÛn de flash, que se va a llamar Flash 8. TambiÈn se ha anunciado Dreamweaver 8, y Macromedia Studio 8.

Como la noticia estar· dando la vuelta a los blogs durante todo el dÌa, probablemente lo mejor sea ir directamente al MXNA y leer todos los posts sobre el tema.

En todo caso, lo m·s parecido a un anuncio oficial puede ser esto:

Studio 8 - It's official

Agosto 05, 2005

El fotograma en blanco y mis noches de insomnio.

Si recuerdan, aquÌ ,les explicaba el motor para el desarrollo de aventuras gr·ficas en Flash. Bien,entre aventuras, reediciones, traducciones, ..ya he perdido la cuenta del n˙mero de cdroms que han salido, todos sin problemas. ø Todos ?. No. El otro dÌa, un cdrom, empezÛ a dar problemas. Por requerimientos del proyecto, debe funcionar en un pentium II a 300Mhz. Termino de exportar el cdrom en mi m·quina ( Pentium IV ) y funciona perfÈctamente, pero al llevarlo a las m·quinas de testing ( Pentium II con W98, Pentium con Linex, Mac G3 ),fallaba en todas. Bueno, no es que fallase, es que iba muy muy lento. ø cu·l es el problema ? ø porquÈ si todos los cdroms funcionan bien, este da problemas ?.
Comienza la fase de an·lisis del problema, y se descarta problemas de la programaciÛn ( todos los cdroms llevan el mismo cÛdigo ) .
Como el cliente ha pedido unos cambios en unas animaciones, empiezo a pensar que uno de estos cambios en la animaciÛn de inicio o en la de fin del juego, hacen que algo falle. ASÌ pues, empiezo a probarlo sin una de las animaciones, sin la otra, sin ninguna de las dos, rehaciendo todo el fla desde cero, etc... ( Bien, hay que explicar, que cada prueba supone, exportar el fla, crear un instalador con zinc estudio, generar en una imagen ISO un disco hÌbrido pc/mac, sacarlo a disco fÌsico, ....en total cada cambio unos 45 minutos mÌnimo hasta poder probar en las m·quinas de testing ) y nada que no funciona.

Es entonces cuando me doy cuenta que nada m·s arrancar el cdrom, la primera pantalla que aparece, es la de login, y que al introducir tus datos, parece que incluso le cuesta aparecer en pantalla, es decir, escribo una "e" y como que pasan unos milisegundos hasta que aparece en pantalla. Lo justo para que parezca algo raro. AsÌ pues, se me ocurre que el problema puede estar en un swf que se carga nada m·s arrancar el cdrom con la configuraciÛn de los men˙s, los textos que se deben mostrar en todo el cdrom etc..( este swf se genera a partir de todos los xml con los que se desarrolla el juego ) . AsÌ pues le abro,y ........ el *+«?ø{ swf tenÌa dos frames, dos puÒeteros frames, el primer frame en el que se declaraban las 300 variables( de tipo XML ) de configuraciÛn y textos del cdrom , y un segundo fotograma vacÌo. Lo que hacÌa que se estuviesen definiendo esas 300 variables ( aproximadamente ) 6 veces por segundo, y claro, el juego se tostaba.

En fÌn, tras averiguar la causa del problema sÛlo se me ocurrÌa acordarme de la madre del F5, del fotograma de los...
AsÌ que la moraleja es...Tener cuidado con los fotogramas vacÌos, que uno sÛlo puede hacer que vuestras 8000 lÌneas de cÛdigo no sirvan para nada.

Agosto 04, 2005

Un ejemplo del patrÛn memento ( la versiÛn actionscript )

Conquistar el mundo no es f·cil. Nada f·cil. Yo lo sÈ, t˙ lo sabes, incluso el Profesor Dispar lo sabe.

El Profesor se siente preparado para llevar a cabo su malvado plan. Tiene el conocimiento teÛricos, tiene los conocimientos pr·cticos, tiene un plan, tiene hasta unas gafas de sol nuevas, pero °hay tantos detalles que pulir antes de lanzarse a la conquista del mundo!.

En episodios anteriores, hemos visto cÛmo el Profesor ha implementado el patrÛn prototype ( para crear su ejÈrcito de clones -°anda, acabo de caer!- ), el patrÛn extensiÛn objects ( para asignarles sus roles ), el patrÛn command ( para asignarles las Ûrdenes ), y el patrÛn observer ( para implementar el sistema de comunicaciones ). Parece que el Profesor Dispar ha estado bastante ocupado implementando patrones, pero ha sido suficiente?. NO!! ( muhahahahahahhaha ).

Continuar leyendo "Un ejemplo del patrÛn memento ( la versiÛn actionscript )" »

Junio 17, 2005

No te repitas, y encapsula lo que pueda cambiar

No te repitas. En cuanto escribes el mismo cÛdigo m·s de una vez, est·s empezando a meterte en problemas

AquÌ tienes un ejemplo.

Estoy trabajando en una aplicaciÛn en la que voy a utilizar los componentes de UI. Es una aplicaciÛn Modelo-Vista-Controlador, por lo que la vista estar· totalmente desacoplada de la lÛgica de la aplicaciÛn

La aplicaciÛn va a tener m·s de una vista ( hay varias "pantallas" diferentes en las que tengo que mostrar los datos de diferentes formas ), por lo que he decidido que lo mejor ser· escribir una clase diferente para cada una de esas vistas.

Por tanto, cada vista attachear· un movieclip, que es el que contiene realmente la "pantalla" con los elementos interactivos ( botones, datagrid, etc ). Todas esas vistas extienden de una clase que implementa cierta funcionalidad com˙n ( emisiÛn de eventos y alguna cosilla m·s ). Por tanto, no extender·n de movieclip ( aparte de por razones un poco m·s abstractas, aunque Èste no es el momento para discutir eso ). A lo que vamos.

Adem·s, resulta ( todo son facilidades ) que por ahora no tengo los gr·ficos definitivos ( vamos, que me lo estoy pintando yo ). A˙n m·s, si al final el presupuesto da para ello, tendrÈ que desarrollar mis propios componentes.

Bien, pues una vez puestos en antecedentes, imagina que arranca la aplicaciÛn. Lo primero con lo que se va a encontrar el usuario es con una pantalla de login

encapsulate.jpg

Como puedes ver en la captura, a) m·s me vale que me vaya bien en esto de la programaciÛn, por que lo que es en la parte gr·fica...; b) la pantalla contiene un componente ( el botÛn ).

La clase que maneja esa pantalla ser·:

import mx.utils.Delegate; class LoginView { private var timeline : MovieClip; private var loginScreen: MovieClip; function LoginView( tl: MovieClip ) { this.timeline = tl; } public function init( ) { this.loginScreen = this.timeline.attachMovie( "LoginScreen", "LoginScreen", this.timeline.getNextHighestDepth( ), { _x: 0, _y: 0 } ); this.loginScreen.loginBtn.label= "Go!"; this.loginScreen.loginBtn.addEventListener( "click", Delegate.create( this, click ) ); } private function click( ) { trace( "click" ); } }

Y cuando quiera que aparezca, harÈ algo como:

var loginView: LoginView = new LoginView( this ); loginView.init( );

Y el botÛn no va a funcionar. Ni siquiera va a mostrar el texto que le he asignado. Tras unos minutos de buscar en google, un poco de sentido com˙n, y un poco menos de conocimiento de la plataforma, he llegado a la conclusiÛn de que el botÛn no se inicializa a tiempo, y que tal vez deberÌa dejar pasar un frame para asignar el texto y el click.

import mx.utils.Delegate; class View { private var timeline : MovieClip; private var loginScreen: MovieClip; function View( tl: MovieClip ) { this.timeline = tl; } public function init( ) { this.loginScreen = this.timeline.attachMovie( "LoginScreen", "LoginScreen", this.timeline.getNextHighestDepth( ), { _x: 0, _y: 0 } ); var theView: View = this; this.loginScreen.onEnterFrame = function( ) { theView.initButton( ); delete this.onEnterFrame; } } private function initButton( ) { this.loginScreen.loginBtn.label= "Go!"; this.loginScreen.loginBtn.addEventListener( "click", Delegate.create( this, click ) ); } private function click( ) { trace( "click" ); } }

Y funciona. Pero esta soluciÛn no huele demasiado bien ( y no sÛlo por el truqui del scope ). Voy a tener que hacer bastantes pantallas ( alrededor de una docena ), asÌ que voy a tener que repetir ese cÛdigo en todas ellas. Desde luego, podrÌa subclasificar, pasar ese cÛdigo a una clase base, pero no voy a tener el mismo n˙mero de botones en todas las pantallas, luego tampoco tendrÌa mucho sentido subclasificar para luegosobreescribir, y adem·s, sÛlo podrÌa utilizar ese cÛdigo en subclases de la clase base que creara, con lo cual no iba a tener demasiada flexibilidad, que digamos. Y adem·s, mis vistas ya extienden de otra clase base.

E incluso puede ser peor, porque es probable que tenga que cambiar esos componentes por unos mÌos ( o no, que a˙n no lo sÈ ). AsÌ que es m·s que probable que ese cÛdigo tenga que cambiar en un futuro no muy lejano

AsÌ pues, estoy repitiendo cÛdigo, y adem·s, es probable que ese cÛdigo tenga que cambiarlo en breve. øCÛmo lo puedo resolver?. Pues encapsulando ese cÛdigo dentro de su propia clase.

Para empezar, usarÈ un callback que ya he utilizado m·s veces:

class Callback { private var callbackObjVal: Object; private var callbackMethodVal: String; public function Callback( objParam: Object, methodParam: String ) { this.callbackObjVal = objParam; this.callbackMethodVal = methodParam; } public function fire( parameter: Object ): Object { return this.callbackObjVal[ this.callbackMethodVal ]( parameter ); } }

La clase encargada de manejar el botÛn ser·:

class ButtonHandler { public static function initButton( mc: MovieClip, callback: Callback ) { var cb: Callback = callback; mc.onEnterFrame = function( ) { cb.fire( ); delete this.onEnterFrame; } } }

Y la utilizarÈ de la siguiente forma:

import mx.utils.Delegate; class View { private var timeline : MovieClip; private var loginScreen: MovieClip; function View( tl: MovieClip ) { this.timeline = tl; } public function init( ) { this.loginScreen = this.timeline.attachMovie( "LoginScreen", "LoginScreen", this.timeline.getNextHighestDepth( ), { _x: 0, _y: 0 } ); ButtonHandler.initButton( this.loginScreen, new Callback( this, "initButton" ) ); } private function initButton( ) { this.loginScreen.loginBtn.label= "Go!"; this.loginScreen.loginBtn.addEventListener( "click", Delegate.create( this, click ) ); } private function click( ) { trace( "click" ); } }

øUna soluciÛn excesivamente compleja?. Puede, pero es la que m·s me ha satisfecho, porque es la que aporta m·s flexibilidad. Si tengo que cambiar la forma en la que manejo los botones, sÛlo tengo que cambiar la implementaciÛn de un mÈtodo en una clase. Estoy programando pensando en el interfaz, y no en la implementaciÛn.

Junio 02, 2005

Un ejemplo el patrÛn observer (la versiÛn actionScript)

Est· desencadenado. El primer ataque ha sido lanzado. El profesor Dispar ha dado las Ûrdenes a sus huestes para dominar el mundo. En post anteriores hemos visto como el profesor Dispar ha conseguido clonar cualquier animal ( con gran predilecciÛn por ovejas y vacas ) utilizando un patrÛn prototype, ha conseguido darlas un rol din·micamente con el patrÛn extension objects, y ha repartido las Ûrdenes con un patrÛn command.

Pero como ya sabemos, el profesor Dispar est· loco, pero no es idiota. Sabe, que algo puede salir mal, que un pequeÒo detalle puede truncar sus planes de dominar el mundo. Y tambiÈn sabe que una retirada a tiempo es una victoria.

Continuar leyendo "Un ejemplo el patrÛn observer (la versiÛn actionScript)" »

Abril 26, 2005

Un ejemplo del patron Command

Todo est· preparado. Las ovejas y las vacas han sido clonadas y sus roles han sido asignados. Es el momento perfecto para que el Profesor Dispar lance su ataque final. °°°°°Ha llegado el momento de conquistar el mundo!!!!

øPero cÛmo dar· el Profesor Dispar a sus tropas la orden de atacar?

Continuar leyendo "Un ejemplo del patron Command" »

Abril 06, 2005

Un ejemplo del patrÛn Extension Objects

øRecuerdas al Professor Dispar?. øRecuerdas sus malvados planes para dominar el mundo?.

Hoy veremos cÛmo el patrÛn Extension Objects ( o "cÛmo cambiar el interfaz que implementa una clase en tiempo de ejecuciÛn" ) ha ayudado al Profesor Dispar. Pero no va a ser una tarea f·cil, porque este patrÛn es muy complejo, pero øquiÈn dijo que ser un genio del mal fuera f·cil?.


Continuar leyendo "Un ejemplo del patrÛn Extension Objects" »

Marzo 29, 2005

Un ejemplo del PatrÛn Prototype

El Profesor Dispar es un cientÌfico espaÒol que est· planeando dominar el mundo. øQuieres conocer los problemas con los que se ha encontrado, y cÛmo los ha resuelto implementando el patrÛn prototype?

Continuar leyendo "Un ejemplo del PatrÛn Prototype" »

Marzo 28, 2005

Motor para aventuras gr·ficas en AS 2 y XML

Desde finales de Diciembre y hasta finales de febrero, he estado desarrollando un motor para la creaciÛn de aventuras gr·ficas, realizado Ìntegramente con ActionScript 2.0 .
Por requerimientos del cliente, las aventuras gr·ficas debÌan ser completamente ( tanto los objetos que aparecen en pantalla como la lÛgica del juego ) configurables desde archivos XML. Adem·s, otros requerimientos eran la utilizaciÛn de diferentes perspectivas visuales en las escenas ( la aventura gr·fica no podÌa estar completamente realizada en una sola perspectiva, tÌpicamente isomÈtrica ) y adem·s debÌa simular un "efecto de 3d" en las escenas en que fuese necesario.

Es decir, un motor en el que se carga la lÛgica de cada escena de un archivo xml, en el que debe funcionar la escena independientemente de que sea una perspectiva frontal, lateral, una habitaciÛn de dos pisos etc..., y en la que habÌa que desarrollar un sistema que permitiese al personaje pasar por delante y/o detr·s de los objetos que aparecen en pantalla ( por ejemplo una mesa en el medio de una habitaciÛn ) en funciÛn de su posiciÛn ( que claro, depende de la perspectiva ). Evidentemente, el motor se desarrollÛ antes que muchos diseÒos de escenas, por lo que debÌa ser lo suficientemente flexible como para permitir que en pantalla hubiese de 0 a n objetos, que cada uno de estos objetos pudiese estar en cualquier coordenada de pantalla ( objetos en primer plano, objetos a media distancia, objetos en lÌnea del horizonte ) y que el personaje pudiese interactuar con ellos correctamente.

Continuar leyendo "Motor para aventuras gr·ficas en AS 2 y XML" »

Febrero 14, 2005

Un caso en el que no se deberÌa heredar de movieclip

Sabemos que se puede asignar una clase AS2 a cualquier movieclip que se encuentre en la librerÌa. Si esa clase extiende movieclip, cuando se atachea ( menudo palabro ) el clip se materializa una instancia de esa clase. Pero ni siquiera hace falta hacer el attachmovie. Con colocar el clip en el stage en tiempo de diseÒo es suficiente, la instancia de la clase se materializar· cuando el cabezal llegue a ese frame. Esto puede facilitar el trabajo cuando se est· creando una interfaz de usuario, no hay m·s que colocar el movieclip en el stage y *magia*, se tiene una instancia de la clase asociada.

Imaginemos que hay que crear un interfaz parecido a Èste:

the interface

Continuar leyendo "Un caso en el que no se deberÌa heredar de movieclip" »

Diciembre 14, 2004

°Participa en el concurso de aplicaciones para FlashLite!

Probablemente ya lo hayas oÌdo ( mejor dicho, leÌdo ), pero Macromedia ha convocado un concurso para decidir cu·l es la mejor aplicaciÛn para FlashLite. °Y hay buenos premios!

Los detalles sobre el concurso est·n aquÌ:

http://www.macromedia.com/mobile/special/contest/

Obviamente, necesitar·s el player de Flash Lite para probar tu aplicaciÛn. Puedes pedirlo enviando un email a flashlite_contest@macromedia.com, invluyendo el modelo del dispositivo y el IMEI del mismo.

Si quieres saber si tu dispositivo est· soportado, aquÌ tienes la lista:

http://www.macromedia.com/mobile/supported_devices/#tmobile

°Corre!. °El plazo de presentaciÛn termina el 1 de febrero!.

Diciembre 13, 2004

[PPC] AplicaciÛn del modelo-vista-controlador a una aplicaciÛn para PocketPC

Vamos a construir una aplicaciÛn muy sencilla, pero que puede ser un buen ejemplo de cÛmo aplicar el paradigma del modelo-vista-controlador a una aplicaciÛn para PocketPC. Y adem·s, utilizando la nueva clase Delegate.

Continuar leyendo "[PPC] AplicaciÛn del modelo-vista-controlador a una aplicaciÛn para PocketPC" »

Noviembre 27, 2004

Algunos beneficios pr·cticos de la programaciÛn orientada a objetos

Las cuatro palabras de moda en el mundo flash son ìProgramaciÛn Orientada a Objetosî, sobre todo desde que hace ya casi aÒo y medio se lanzara el Flash MX 2004, y con Èl el AS2.

Todos hemos oÌdo hablar de los beneficios que la programaciÛn orientada a objetos va a traer a nuestro trabajo diario, de lo f·cil que nos va a resultar mantener nuestros programas si escribimos muchas clases, de lo bueno que es escribir clases, en vez de poner cÛdigo en botones, y de lo importantes que son la encapsulaciÛn y el polimorfismo. Pero, øes realmente asÌ?. øDe verdad la programaciÛn orientada a objetos nos puede facilitar el trabajo?.

Continuar leyendo "Algunos beneficios pr·cticos de la programaciÛn orientada a objetos" »

Noviembre 08, 2004

øLos patrones de diseÒo son peligrosos?

Es, m·s o menos, el tÌtulo de una discusiÛn muy interesante el el wiki de c2. No sÛlo por la discusiÛn en sÌ, sino tambiÈn por la cantidad de enlaces a otros artÌculos que se aportan.

øPuede ser peligroso utilizar demasiado los patrones de diseÒo?. øPuede hacer que nuestros sistemas sean innecesariamente complejos?. øO son la mejor soluciÛn a muchos problemas?

La discusiÛn aquÌ ( en inglÈs )

Octubre 13, 2004

En caso de duda, composiciÛn ( y III )

Aparte de las consideraciones expuestas en el post anterior, hay un par de razones para favorecer la composiciÛn sobre la herencia que probablemente sean de mucho m·s peso.

En primer lugar, la herencia no permite cambiar las implementaciones de las clases heredadas en tiempo de ejecuciÛn, y adem·s, rompe la encapsulaciÛn, ya que la clase base es visible a travÈs de las clases heredadas.

Continuar leyendo "En caso de duda, composiciÛn ( y III )" »

En caso de duda, composiciÛn ( II )

øQuÈ pasa si nuestra jerarquÌa de clases es muy profunda o est· muy extendida?. Pues que corremos un riesgo muy grande de tener problemas si cambia el interfaz de la superclase.

Seguimos teniendo a nuestros programadores y nuestros camioneros levant·ndose por las maÒanas, yendo a trabajar, y volviendo a casa por las noches. Supongamos que en la clase base ( Persona ) hay un mÈtodo como Èste:

Continuar leyendo "En caso de duda, composiciÛn ( II )" »

En caso de duda, composiciÛn ( I )

La forma en la que todos nos adentramos en el mundo de la programaciÛn orientada a objetos suele ser parecida. Tendemos a depender en exceso de la herencia, a realizar jerarquÌas de clases muy cerradas y muy estrictas, a solucionar cualquier problema, por pequeÒo que sea, a base de crear clases hijas particularizadas para ese problema. øPero es Èsa la mejor forma de organizar nuestro cÛdigo?

Hace poco, alguien me dijo que discutir sobre herencia y composiciÛn era como discutir sobre pc vs mac. Yo creo que no es asÌ. Voy a intentar explicar por quÈ

Continuar leyendo "En caso de duda, composiciÛn ( I )" »

Septiembre 29, 2004

Un ejemplo del patrÛn abstract factory

El patrÛn Abstract Factory es uno de los patrones de construcciÛn. B·sicamente, proporciona una interfaz que permite crear familias de objetos relacionados entre sÌ, sin especificar ( ni por lo tanto, conocer a priori ) sus clases concretas.

Voy a intentar explicarlo con un ejemplo un poco m·s ìrealî. Supongamos que quiero decorar mi casa. Puedo elegir entre dos lÌneas de decoraciÛn distintas ( en este caso, ìModernaî, o ìCl·sicaî ). En principio sÛlo voy a comprar las puertas y una televisiÛn.

øPor quÈ implementar una factorÌa abstracta para resolver el problema?. Voy a intentar explicarlo sobre la marcha. En primer lugar voy a suponer que en mi ciudad hay dos tiendas de decoraciÛn, la que vende elementos decorativos cl·sicos, y la que vende elementos decorativos modernos. Adem·s, supondrÈ que las dos tiendas venden los mismos elementos decorativos ( televisores y puertas ).

Bien, si yo quiero comprar una televisiÛn, independientemente de lo moderna o cl·sica que sea, voy a la tienda y digo ìquiero una televisiÛnî. Adem·s, una televisiÛn, sea moderna o cl·sica, me permite hacer las mismas cosas: encenderla, apagarla, subir y bajar el volumen, aunque no se haga de la misma forma ( en la moderna, lo hago con el mando a distancia, en la antig¸a me tengo que levantar ).

Por lo tanto, ya sÈ que tengo que ir a la tienda, y pedir una televisiÛn. Pero tambiÈn puedo encargarle a un transportista que me traiga una televisiÛn moderna. Yo no tengo que decirle nada m·s que eso, porque es el transportista es el que se encarga de pensar ìvale, me ha dicho que quiere una tele moderna, por tanto, tengo que ir a la tienda donde venden las teles modernas, y pedir una teleî. Pues el transportista es la factorÌa abstracta. Yo, como cliente, le pido una televisiÛn moderna, y sÈ que voy a obtener una televisiÛn de plasma de 42î que puedo manejar con el mando a distancia adjunto. øQuÈ cÛmo la ha conseguido el transportista?: no me importa. SÛlo me importa que me la traiga.

Antes de empezar a implementarlo en actionScript, una consideraciÛn teÛrica importante. ActionScript no implementa clases abstractas. Es cierto que se pueden simular, pero no est·n implementadas, por lo que yo no voy a basar la arquitectura de este patrÛn en una clase abstracta, sino en un interfaz.

Empecemos. Hemos dicho que tanto si voy yo en persona a la tienda, como si hablo con un transportista, lo ˙nico que tengo que hacer es decir "quiero una tele". Por lo tanto, tanto las tiendas como el transportista van a implementar un interfaz com˙n ( si fuÈramos estrictos, deberÌan heredar de una misma clase abstracta que implementara ese interfaz ).

El interfaz ser·:

import net.designnation.patterns.AbstractFactory.* interface net.designnation.patterns.AbstractFactory.IFactoryActions { public function getTV( ): ITVActions; public function getDoor( ): IDoorActions; }

Como puede verse, hay dos acciones posibles: getTV, y getDoor ( es decir, tr·eme una tele, y tr·eme una puerta ).

Por tanto, las dos tiendas ser·n algo asÌ:

import net.designnation.patterns.AbstractFactory.* class net.designnation.patterns.AbstractFactory.ModernShop implements IFactoryActions { function ModernShop( ) { trace( "He elegido la tienda moderna" ); } public function getTV( ): ITVActions { return new BrandNewTV( ); } public function getDoor( ): IDoorActions { return new ModernDoor( ); } }

import net.designnation.patterns.AbstractFactory.* class net.designnation.patterns.AbstractFactory.ClassicShop implements IFactoryActions { public function ClassicShop( ) { trace( "He elegido la tienda cl·sica" ); } public function getTV( ): ITVActions { return new OldTV( ); } public function getDoor( ): IDoorActions { return new ClassicDoor( ); } }

Como puede verse, las dos tiendas implementan el interfaz IFactoryActions ( implementan dos mÈtodos llamados getTV y getDoor, que devolver·n respectivamente, una televisiÛn y una puerta ).

AtenciÛn. Vamos a ver con m·s atenciÛn el mÈtodo getTV( ).

public function getTV( ): ITVActions { return new OldTV( ); }

øInstanciamos una clase OldTV pero el mÈtodo devuelve un interfaz?. Cierto. Eso es lo que nos permite tratar a todas las televisiones por igual, sean modernas, antig¸as, o de gas. Porque lo que a nosotros nos interesa es poderle decir a la televisiÛn: ìenciÈndeteî, y que Èsta lo haga, como sea, pero que lo haga. Eso lo logramos haciendo que las dos clases que representan televisores implementen una interfaz com˙n:

interface net.designnation.patterns.AbstractFactory.ITVActions { public function pumpUpTheVolume( ); public function shutUp( ); }

Y por tanto, la televisiÛn moderna ser·:

import net.designnation.patterns.AbstractFactory.* class net.designnation.patterns.AbstractFactory.BrandNewTV implements ITVActions { function BrandNewTV( ) { trace( "He recibido mi televisiÛn de plasma de 42 pulgadas" ); } public function pumpUpTheVolume( ) { trace( "por supuesto, espera que busco el mando" ); } public function shutUp( ) { trace( "Presionando esta tecla, el sonido se silencia" ); } }

Mientras que la cl·sica es:

import net.designnation.patterns.AbstractFactory.* class net.designnation.patterns.AbstractFactory.OldTV implements ITVActions { function OldTV( ) { trace( "Me he comprado una tv vieja" ); } public function pumpUpTheVolume( ) { trace( "Como no tiene mando a distancia, me tengo que levantar a subir el volumen" ); } public function shutUp( ) { trace( "Como no tiene mando a distancia...." ); } }

Lo mismo pasarÌa con las puertas. Sea moderna o antigua, la puerta tiene dos posibles acciones, se puede abrir, y se puede cerrar, por lo tanto las dos clases que representan a puertas implementan un interfaz com˙n:

interface net.designnation.patterns.AbstractFactory.IDoorActions { public function open( ); public function close( ); }

La puerta moderna:

import net.designnation.patterns.AbstractFactory.* class net.designnation.patterns.AbstractFactory.ModernDoor implements IDoorActions { function ModernDoor( ) { trace( "Constructor de la puerta moderna" ); } public function open( ) { trace( "Abriendo la puerta moderna" ); } public function close( ) { trace( "Cerrando la puerta moderna" ); } }

Y la cl·sica:

import net.designnation.patterns.AbstractFactory.* class net.designnation.patterns.AbstractFactory.ClassicDoor implements IDoorActions { function ClassicDoor( ) { trace( "ClassicDoor constructor" ); } public function open( ) { trace( "Puerta cl·sica abierta " ); } public function close( ) { trace( "Puerta cl·sica cerrada" ); } }

Recapitulemos. Tenemos dos tiendas. Ambas venden puertas y televisores. La tienda cl·sica vende puertas y televisores cl·sicos, y la tienda moderna vende puertas y televisores modernos.

Bien, pues nuestro transportista serÌa la abstract factory:

import net.designnation.patterns.AbstractFactory.* class net.designnation.patterns.AbstractFactory.AbstractFactory { public static var MODERN : Number = 1; public static var CLASSIC : Number = 2; public static function getFactory( shopType: Number ): IFactoryActions { if ( ( shopType & MODERN ) == MODERN ) { return new ModernShop( ); } if ( ( shopType & CLASSIC ) == CLASSIC ) { return new ClassicShop( ); } } }

Esta clase implementa el mismo interfaz que las dos tiendas. Por tanto, yo le dirÈ, "oye, quiero una tele moderna", y me olvidarÈ de todos los detalles del proceso. Al final, tendr· algo a lo que podrÈ subir y bajar el volumen,Ö. øCÛmo?:

import net.designnation.patterns.AbstractFactory.* var factory: IFactoryActions = AbstractFactory.getFactory( AbstractFactory.MODERN ); var myTV: ITVActions = factory.getTV( ); myTV.pumpUpTheVolume( ); var myDoor: IDoorActions = factory.getDoor( ); myDoor.close( );

Septiembre 20, 2004

Flashblog: Weblog opensource realizado en flash

Flashblog ha nacido con el espÌritu de ofrecer un medio tÈcnicamente avanzado, basado en tecnologÌas como Macromedia Flash y php, donde las personas puedan exponer libremente sus pensamientos.

Flashblog funciona con cualquier configuraciÛn b·sica de Apache/Php(4)/MySQL, y sin instalaciÛn de ninguna librerÌa especial. Necesita lÛgicamente Flash MX 2004 y su Player 7 para soportar la carga de contenido gr·fico, y lo mejor de todo, es que se publicar· como OpenSource.

Flashblog se publicar· prÛximamente, pero por ahora podeis obtener m·s informaciÛn en su web: Flashblog.org

Septiembre 01, 2004

ArtÌculo en gotoAndPlay( )

La serie de posts sobre el patrÛn state y el desarrollo de juegos acaba de ser publicado como artÌculo en gotoAndPlay( ).

gotoAndPlay( ) es una comunidad dedicada al desarrollo de juegos en flash. Si tienes alg˙n problema cuando estÈs desarrollando un juego, lo m·s probable es que puedas encontrar la soluciÛn en sus foros, o en alguno de sus artÌculos. Un sitio de visita obligada.

Y si quieres leer nuestro artÌculo, aquÌ est· el link directo:
http://www.gotoandplay.it/_articles/2004/08/statePattern.php

Agosto 29, 2004

El patrÛn State aplicado al desarrollo de juegos ( IV y final )

Por fin ( todo llega ) un ejemplo de cÛmo puede desarrollar un juego a partir de una m·quina de estados.

La descripciÛn del juego es la siguiente. Van apareciendo gotas de agua en pantalla, en posiciones aleatorias. Durante el tiempo del que disponemos, tenemos que evitar que el n˙mero de gotas en pantalla sobrepase un umbral determinado. Para eliminar una gota de pantalla, basta con hacer click sobre ella. Una vez terminado el tiempo, se nos ofrece la opciÛn de volver a jugar, o de terminar el juego. Si volvemos a jugar, el n˙mero m·ximo de gotas que puede haber en pantalla disminuye. Se va repitiendo este patrÛn hasta que el jugador decida abandonar el juego, o hasta que se sobrepase el umbral m·ximo de gotas en pantalla, momento en que el juego termina, con derrota.

AquÌ puede verse el diagrama de estados correspondiente.

En nuestro ejemplo, hemos construido el juego en tres capas distintas. No es exactamente un MVC, aunque es algo parecido. Tendremos una clase DropsController que har· las funciones de controllador ( instanciar el modelo del juego, y hacer de conexiÛn entre la capa de presentaciÛn y dicho modelo ), DropsWorld, que es el modelo propiamente dicho, y la clase que tiene agregada la m·quina de estados del juego. Finalmente, tendremos una vista ( que en este caso es muy ligera, ya que consiste solamente en un ìbocadilloî de informaciÛn y un contador de tiempo ). Por lo tanto, el mundo no tiene conocimiento de la existencia de la vista, ni la vista de la existencia del mundo. No es una implementaciÛn estricta de ninguno de los patrones conocidos, pero es con la que m·s cÛmodo trabajo. Por lo tanto, es la utilizada.

El proceso de inicializaciÛn del juego es el siguiente: Al cargar el swf, se instancia el controlador, que a su vez instancia el mundo, registra los listeners al mismo, y manda arrancar su m·quina de estados. Para que el mundo pueda emitir eventos hacemos que extienda de la clase EventSource ( en el package net.designnation.events ). Dicha clase no es m·s que una parte de nuestra implmentaciÛn del patrÛn observer para poder emitir y registrarnos a eventos. De esta forma, los eventos emitidos por el mundo son escuchados por el controlador. El controlador tambiÈn crea un clip vacÌo, cuyo onEnterFrame servir· de generador de pulsos para las m·quinas de estados del juego

Una vez instanciado el mundo, se arranca su m·quina de estados:

public function initWorld( param: Object ) { this.stageMC = param.baseline; this.initBehaviour( ); var theClass: DropsWorld = this; this.base_MC.onEnterFrame = function( ) { theClass.doProcess( ); } this.mySMachine.startMachine( ); } private function doProcess( ) { this.BEngineVal.doProcess( ); }

Hemos delegado la ejecuciÛn del ciclo de la m·quina de estados en el el onEnterFrame del clip base_MC.

La m·quina de estados la definimos en el mÈtodo initBehaviour( )

private function initBehaviour( ) { var initGame: State= new State( "initGame", new CallbackDecl( this, "initGameAction" ) ); var startGame : State= new State( "startGame", new CallbackDecl( this, "startGameAction" ) ); var createDrop : State= new State( "createDrop", new CallbackDecl( this, "createDropAction" ) ); var overDrops : State = new State( "overDrops", new CallbackDecl( this, "overDropsAction" ) ); var endOfTime : State= new State( "endOfTime", new CallbackDecl( this, "endOfTimeAction" ) ); var defeat : State= new State( "defeat", new CallbackDecl( this, "defeatAction" ) ); var victory : State= new State( "victory", new CallbackDecl( this, "victoryAction" ) ); var endOfGame : State= new State( "endOfGame", new CallbackDecl( this, "endOfGameAction" ) ); new Transition( "initGameToStartGame", initGame, startGame, new CallbackDecl( this, "initGameToStartGameEval" ) ); //---------------------------------------------------------- new Transition( "startGameToCreateDrop", startGame, createDrop, new CallbackDecl( this, "startGameToCreateDropEval" ) ); //---------------------------------------------------------- new Transition( "createDropToEndOfTime", createDrop, endOfTime, new CallbackDecl( this, "createDropToEndOfTimeEval" ) ); new Transition( "createDropToOverDrops", createDrop, overDrops, new CallbackDecl( this, "createBubbleToOverDropsEval" ) ); new Transition( "createDropToSelf", createDrop, createDrop, new CallbackDecl( this, "createDropToSelfEval" ) ); //---------------------------------------------------------- new Transition( "overDropsToDefeat", overDrops, defeat, new CallbackDecl( this, "overDropsToDefeatEval" ) ); //----------------------------------------------------------- new Transition( "endOfTimeToVictory", endOfTime, victory, new CallbackDecl( this, "endOfTimeToVictoryEval" ) ); new Transition( "endOfTimeToStartGame", endOfTime, startGame, new CallbackDecl( this, "endOfTimeToStartGameEval" ) ); //------------------------------------------------------------- new Transition( "defeatToEndOfGame", defeat, endOfGame, new CallbackDecl( this, "defeatToEndOfGameEval" ) ); //------------------------------------------------------------- new Transition( "victoryToEndOfGame", victory, endOfGame, new CallbackDecl( this, "victoryToEndOfGameEval" ) ); this.mySMachine.resetToInit( initGame ); }

Y una vez instanciados tanto los estados como las transiciones, debemos implementar los callbacks que llevan asociados.

La clase que se utiliza para presentar las gotas es un controlador bastante ligero. TambiÈn extiende a EventSource, por lo que ser· capaz de emitir un evento cuando se haga click sobre el clip que lleva agregado. Seguro que este punto puede dar lugar a discusiÛn, pero una gota es una gota, no un MovieClip, por lo tanto he optado por que la clase Drop, dada su funcionalidad, tenga un clip con el gr·fico de la gota agregado, y no sea en sÌ misma una subclase de MovieClip.

El cÛdigo en general se explica por sÌ solo, por lo que una lectura atenta del mismo puede ser suficiente para comprender el funcionamiento del mismo.

TambiÈn quisiera resaltar que Èsta no deberÌa considerarse como una implementaciÛn definitiva. Gran parte del cÛdigo de DropsWorld es com˙n a todos los juegos que se desarrollen de esta forma, por lo que deberÌa subclasificarse para crear un mundo base que implementara las operaciones b·sicas de la m·quina de estados ( arranque, parada, inicializaciÛn, etc ). Por lo tanto, el cÛdigo presentado puede ( y deberÌa ) mejorarse considerablemente. Igualmente, el juego en sÌ requiere de un poco m·s de trabajo ( no hay feedback sobre cu·l es el n˙mero m·ximo de gotas que puede haber en pantalla, sobre si estamos lejos o cerca de ese umbral, etc. ). Adem·s., dada la forma en la que se registran los listeners, antes de destruir las gotas deberÌan de-registrase los listeners que tengan asociados, para evitar referencias circulares.

A˙n asÌ, tambiÈn quisiera resaltar que el tiempo del desarrollo del juego ( dejando aparte el framework base, por su puesto ), no ha llegado a dos horas. Y el resultado final es Èste:

Quisiera tambiÈn dejar constancia de mi agradecimiento a Celia Carracedo por los gr·ficos del juego.

El cÛdigo fuente del juego puede descargase aquÌ. No olvides definir el classpath apropiado para compilarlo. Los packages son:

net.designnation.behaviours
net.designnation.data
net.designnation.events
net.designnation.physics
net.designnation.PoppingDrops ( game classpath )

Agosto 21, 2004

macromedia.com para dispositivos mÛviles

Es probable que sea el ˙ltimo en enterarme, pero me acabo de dar cuenta de que toda la web de macromedia es navegable desde el pocketpc.

Yo ya me he creado un canal de avantgo para poder leer offline el Developer Center. ;)

Un trabajo impresionante. Enhorabuena!

Agosto 20, 2004

Interesante aplicaciÛn para pocketpc

Mobilympics es una aplicaciÛn para pocket pc realizada por el equipo de la web portuguesa pc de bolso.

Con esta aplicaciÛn se pueden seguir el calendario y resultados ( ya que se puede sincronizar directamente con los datos de la organizaciÛn de los juegos ) de siete deportes de equipo.

El programa es "Ad-ware", es decir que al salir del mismo nos enseÒan un anuncio de los sponsores del proyecto. Nadie es perfecto.

Agosto 13, 2004

Servidor de Sockets para AS con PHP5

Gracias a mi hermano CÈsar he descubierto este servidor de sockets,en freshmeat. Su nombre Cyber Socket Server, y seg˙n pone funciona en hosts con PHP5. Hay que bajarlo y estudiarlo un poco a ver que tal.
Direcciones:
Proyecto en freshmeat
CSS ( Cyber Socket Server )
freshmeat

Seg˙n la descripciÛn del proyecto, es similar a Flash Communication Server, yo como soy incrÈdulo dudo que transmita video ( el protocolo rtmp es de macromedia y hasta donde yo se, ni siquiera Unity que es el servidor de sockets m·s conocido tiene para emisiÛn de video ) pero aunque "sÛlo" sean datos compartidos en tiempo real, le voy a echar un vistazo con calma.
Un saludo.

Agosto 12, 2004

Sound.onSoundComplete: øBug o feature?

No lo tengo muy claro. ø Es un bug del flash player o realmente es el comportamiento esperable?

Veamos. El problema tiene cierta relaciÛn con la serie de post anteriores ( e inconclusa, lo sÈ, pero llegar· a su final en breve ) sobre las m·quinas de estados.

El caso es que tengo un juego en el que debe realizarse una transiciÛn a un nuevo estado cuando un sonido termine de "ejecutarse", es decir, cuando se lance el evento onSoundComplete del correspondiente objeto Sound. El caso es que siempre ha funcionado correctamente, pero hoy, al hacer una pasada de prueba por el juego, me he encontrado con que ya no funcionaba.

øCÛmo? Pero si esto siempre ha funcionado!!. DespuÈs de un par de horas de debugeo, se me ha encendido la bombilla. Resulta que he formateado mi m·quina de desarrollo anteayer, y al instalar el nuevo sistema, no me ha reconocido ni la tarjeta de sonido, ni la tarjeta gr·fica. Vamos, que ahora mismo, si miro el panel de control de la m·quina, no hay ning˙n dispositivo de audio.

Bueno, pues al parecer, eso hace que no se lance nunca el evento onSoundComplete.

En todo caso, sea un bug o una feature, es algo a tener en cuenta ( al menos para mÌ ).

Julio 18, 2004

Componentes FlashSim

Este juego de componentes contiene controles como potenciÛmetros, relojes graduados, ... en fin, los controles tÌpicos de mesas de mezclas y / o control.

Los componentes est·n escritos en AS2, son facilmente skineables, y contienen toda la documentaciÛn necesaria para comenzar a trabajar con ellos sin mayor dificultad.

Si quereis echarlos un vistazo, visitad FMXISComponents ( por cierto, si realizais la compra de los componentes a travÈs de este link, ayudais a mantener esta web :)

Julio 12, 2004

El patrÛn State aplicado al desarrollo de juegos ( III )

Ya ha llegado el momento de empezar a ver cÛdigo.

Puedes bajarte el cÛdigo aquÌ. Nos apoyamos tambiÈn en las implementaciones de lista enlazada y en la de HashMap

Hemos implementado la m·quina de estados utilizando cuatro clases
: Transition ( transiciones )
State ( estados )
SMachine ( mq·uina de estados )
BEngine( motor de comportamientos, es quien maneja las m·quinas de estados )

B·sicamente el procedimiento ser· el siguiente: se crear· la m·quina de estados de la entidad correspondiente, se le aÒadir·n los estados y transiciones necesarias, y m·s tarde se registrar· esa m·quina en el motor global de la aplicaciÛn. Ese motor ser· el encargado de mandar a las m·quinas de estados que tenga registradas que ejecuten el paso siguiente.

Veamos primero la estructura de ese motor. B·sicamente no es m·s que una lista enlazada en la que guardamos todas las m·quinas de estados que registremos, y mÈtodos para registrar m·quinas de estados, eliminarlas del registro, y darlas la orden de proceso.

class BEngine { private var machineListVal: List; public function BEngine( ) { this.machineListVal= new List( ); } public function registerSMachine( machine: SMachine ) { this.machineListVal.push( machine ); } public function unregisterSMachine( machine: SMachine ) { this.machineListVal.deleteElement( machine ); } public function doProcess( ) { var it: IIterator= this.machineListVal.iterator( ); while( it.hasNext( ) ) { SMachine( it.next( ) ).executeCycle( ); } } }

La m·quina de estados no la hemos implementado como una colecciÛn de estados y transiciones, sino que sÛlo guardamos una referencia al primer estado, y al estado actual en que se encuentre. Como ya las transiciones relacionan los estados entre sÌ, no tenemos necesidad de conocer todos los estados y transiciones desde la propia m·quina de estados, sino que con conocer el primero es suficiente. Lo que sÌ que tiene que controlar esta clase es si la m·quina de estados est· arrancada, o parada

class SMachine { . . . . public function resetToInit( initState: State ) { this.currStateVal = initState; this.initStateVal= initState; } . . . . }

Cada estado tendr· asociado un callback ( que es el que va a ejecutar cuando la m·quina de estados entre en ese estado, y un array con las transiciones que salen de Èl.

class State { . . . . public function addTransition( transition: Transition ) { if( transitionDoNotExist( transition ) ) { this.transitions.push( transition ); } } . . . public function evalState( paramater: Object ): fgPair { var nextState: State= undefined; var retPair: Pair; var nTam: Number= this.transitions.length; for( var nIx: Number= 0; nIx< nTam && nextState== undefined; nIx++ ) { var currentTransition: Transition= this.transitions[ nIx ]; if( currentTransition.evaluate( ) ) { if( this.__traceInfo__ ) { trace( "TRANSIT:"+ this.id+ "->"+ currentTransition.endState.id+ " BY "+ currentTransition.id ); } nextState= currentTransition.endState; retPair = new fgPair( nextState, currentTransition ); } } return retPair; } public function execute( parameter: Object ): Object { if( this.__traceInfo__ ) { trace( "S[A]:"+ this.id+"; "+ this.actionCallbackVal.callbackMethod ); } return actionCallbackVal.fire( parameter ); } . . . . }

Y por fin, las transiciones. Cada transiciÛn tiene una referencia al estado inicial y al final, asÌ como la capacidad de ejecutar el callback que se le pase.

class Transition { . . . public function set initState( state: State ) { state.addTransition( this ); this.initStateVal= state; } public function set endState( state: State ) { this.endStateVal= state; } . . . public function execute( parameter: Object ): Object { if( this.__traceInfo__ ) { trace( "T[A]:"+ this.id+"; "+ this.actionCallbackVal.callbackMethod ); } return this.actionCallbackVal.fire( parameter ); } public function evaluate( ): Boolean { var retVal: Boolean= true; if( this.evaluationCallbackVal!= undefined ) { retVal= Boolean( evaluationCallbackVal.fire( this ) ); } return retVal; } . . . }

Pues ya sÛlo falta implementar un ejemplo de utilizaciÛn. Pero eso ser· otro dÌa.

Julio 07, 2004

El patrÛn State aplicado al desarrollo de juegos ( II )

Como ya hemos explicado antes, lo que vamos a intentar hacer es manejar el comportamiento del objeto como una serie de estados relacionados entre sÌ, de manera que la entidad que implementa esa colecciÛn de estados ( conocida como ìm·quina de estadosî ) sea capaz de transitar de un estado a otro. Es decir, tendremos una clase Ball que tiene agregados una serie de objetos ( los estados ) y un gr·fico para representarse a sÌ misma ( el movieclip ). Las m·quinas de estados que vamos a implementar son no jer·rquicas y no concurrentes. Si querÈis leer algo m·s completo sobre m·quinas de estados, pasad por FlashSim orquantum-leaps ( gracias a Jonathan Kaye for the links ). Dado que estamos desarrollando un juego, y que por tanto, la performance debe ser nuestra mayor preocupaciÛn, vamos a intentar simplificar la m·quina de estados lo m·s posible.

Vamos a intentar ilustrarlo con un diagrama UML ( statechart diagram ):

M·quina de estados de la pelota

El universo del juego

Veamos este ˙ltimo diagrama con un poco m·s de detalle, para entender cÛmo funciona la m·quina de estados. Definimos los estados en los que vamos a dividir el comportamiento del juego:

1.- initGame: InicializaciÛn general del juego.
2.- initRound: InicializaciÛn de cada ronda de juego. Se pondr·n a cero los contadores de pelotas explotadas y de tiempo,Ö..
3.- gamePlay: Se est· ejecutando el juego. Las pelotas est·n botando, y el jugador est· intentando explotarlasÖ.
4.- endOfTime: Se ha terminado el tiempo. Chequearemos si se han explotado suficientes pelotasÖ
5.- defeat: No se han explotado suficientes. Hemos perdido.
6.- newChallenge: Hemos explotado suficientes, entonces se nos pregunta si queremos volver a empezar, o nos retiramos. En caso de que queramos volver a empezar, volveremos al estado initRound, y en caso de retirarnos, vamos al estado endOfGame.
7.- endOfGame: El juego ha terminado. Se puede enviar a servidor la informaciÛn sobre la puntuaciÛn, etc.

Una vez comprendida la separaciÛn conceptual en estados, veamos cÛmo funciona la m·quina de estados.
En primer lugar, en cada estado se ejecuta una acciÛn ( initGameAction, initRoundAction,Ö ). Normalmente, una m·quina de estados tiene asignadas tres acciones por estado: una a la entrada en el estado, otra en la ejecuciÛn, y otra a la salida del estado. En nuestro caso, vamos a realizar una implementaciÛn sencilla, en la que sÛlo se ejecutar· una acciÛn por estado. La m·quina de estados no es jer·rquica ni concurrente, por lo que la evaluaciÛn de las transiciones se simplifica mucho.

Por ejemplo, en el estado initRound, se ejecutar· el callback initRoundAction, que se encargar· de la inicializaciÛn de la ronda actual.

Cada una de las flechas representa una transiciÛn. Cada estado tiene asignados un n˙mero de transiciones indeterminado. Esas transiciones son callbacks que devuelven un booleano, de manera que la m·quina de estados se mover· por la transiciÛn que devuelva true. Normalmente, esas transiciones eval˙an flags que son propiedades de la clase. Voy a intentar explicarlo mejor.

La m·quina de estados est· vinculada a un temporizador ( un enterframe de un clip vacÌo, por ejemplo ), de manera que a cada tick de ese temporizador, la m·quina de estados eval˙a todas las transiciones que salen del estado en el que se encuentra, y transitarÈ por la primera que devuelve un true. Por tanto, pasar· a otro estado, ejecutando la acciÛn asignada a dicho estado, y en el siguiente tick evaluar· las transiciones de ese nuevo estado, transitando a su vez por la primera que encuentre que devuelva true.

Esto se entender· mucho mejor con el ejemplo de la pelota. Aunque todavÌa es pronto para ver cÛdigo, recordemos que habÌamos decidido que la pelota no fuera una subclase de MovieClip, sino una entidad m·s compleja, que agregara la m·quina de estados y el clip para su presentaciÛn gr·fica.

Bien, pues cuando instanciamos esa clase y creamos y arrancamos su m·quina de estados, nos encontramos en el primer estado de la misma: initBall. Se ejecutar· la acciÛn correspondiente ( initBallAction ), que se encarga de hacer un attachMovie y de colocar en el stage el correspondiente MovieClip. Una vez hecho esto, ponemos a true un flag de la clase ( por ejemplo isInitFlag ), y a false otro llamado isOutOfBoundsFlag. En cada tick del temporizador se ejecutan las transiciones asignadas al estado initBall ( en este caso sÛlo hay una, que parte de initBall y acaba en moveBall ),. Por tanto, si esa transiciÛn devuelve el valor del flag isInitFlag, devolver· true cuando el clip se haya inicializado y colocado en pantalla, por lo que la m·quina de estados transitar· al estado moveBall.

Ese estado tiene asignadas tres transiciones: una sobre sÌ mismo, otra a outOfBounds, y otra a destroyBall. Respectivamente, esas transiciones evaluar·n tres flags: isOutOfBoundsFlag== false, isOutOfBoundsFlag== true ( sÌ, es el mismo ), y isClickedFlag== true.

Mientras tanto, en la acciÛn de ese estado, primero se mover· la pelota, y luego se chequear· si la pelota est· fuera del stage ( sea por que tiene que rebotar con el suelo, o porque se ha salido por los laterales ). En caso de que asÌ ocurra, el flag isOutOfBoundsFlag se pondr· a true. Por tanto, al evaluarse las transiciones, si la bola no se ha salido del stage, el flag isOutOfBounds ser· igual a false, por lo que la transiciÛn que devolver· true ser· la que se realiza sobre sÌ mismo ( isOutOfBounds== false ), por lo que volver· a entrar en ese estado, ejecutando otra vez la acciÛn moveBallAction, por lo que se volver· a mover la bola, se volver· a chequear si se ha salidoÖ..

En caso de que la bola se hubiera salido, la transiciÛn que devolverÌa true serÌa la que termina en outOfBounds. En ese estado se cambiarÌa el movimiento de la bola ( rebote ) o la posiciÛn ( si se ha salido por un lateral ), y se volverÌa al estado de movimiento.

En caso de que se haya hecho clic en el clip se transitarÌa al estado destroyBall.

En el prÛximo post veremos esto implementado en cÛdigo, pero por ahora es m·s importante entender el concepto subyacente, que es que la propia entidad es la que, chequeando una serie de flags propios, va cambiando su comportamiento. Y ese comportamiento est· encapsulado en una serie de estados, independientes unos de otros.

Hasta pronto...

Julio 05, 2004

El patrÛn State aplicado al desarrollo de juegos ( I )

Vamos a ver un ejemplo de cÛmo podrÌa implementarse el patrÛn State, para realizar juegos con lÛgica compleja y / o reactiva, teniendo en cuenta que la implementaciÛn es bastante relajada, y que el ejemplo que se presenta es tan sÛlo eso, un ejemplo, lo suficientemente sencillo para poder ser explicado en unas pocas lÌneas, pero lo suficientemente complejo para que empiece a merecer la pena el considerar implementar este patrÛn. Obviamente, cuanto m·s complejo sea el comportamiento del juego y / o de sus entidades, esta opciÛn cobrar· m·s cuerpo.

Manos a la obra. Primero veamos quÈ es el patrÛn State.

Del libro "Patrones de diseÒo" ( Gamma et al, Addison Wesley, Madrid, 2003 )

"Permite que un objeto modifique su comportamiento cada vez que cambie su estado interno. Parecer· que cambia la clase del objeto"

Aplicabilidad: ⁄sese el patrÛn State en cualquiera de los siguientes dos casos:

1.- El comportamiento de un objeto depende de su estado, y debe cambiar en tiempo de ejecuciÛn dependiendo de ese estado.
2.- Las operaciones tienen largas sentencias condicionales con m˙ltiples ramas que dependen del estado del objeto.[Ö]. El patrÛn State pone cada rama de la condiciÛn en una clase aparte. Esto nos permite tratar al estado del objeto como un objeto de pleno derecho que puede variar independientemente de otros objetos".


Dicho en otras palabras, lo que vamos a intentar es describir el comportamiento de un objeto como una colecciÛn de estados, de manera que sea el propio objeto el que maneje su comportamiento mediante transiciones de un estado a otro.

Dicho asÌ, no hay quien lo entienda, pero vamos a intentar ilustrarlo con un ejemplo.

Imaginemos que tenemos que hacer un juego: "Explota la pelota". La especificaciÛn del juego es la siguiente: se nos presentar· un n˙mero indeterminado de pelotas en pantalla, que rebotan en el suelo sin pÈrdida de energÌa, y que no rebotan en las paredes ( es decir, si se salen por la derecha de la pantalla, han de volver a aparecer por la izquierda ). Tenemos un tiempo m·ximo para explotar un n˙mero determinado de pelotas ( haciendo clic con el ratÛn sobre ellas ). Al explotar una pelota aparecer· otra, de manera que siempre habr· el mismo n˙mero de pelotas en pantalla. La posiciÛn y velocidad inicial de las pelotas es aleatoria. Si no explotamos un n˙mero mÌnimo, perdemos. Si lo conseguimos, se nos ofrece terminar el juego con la puntuaciÛn actual, o volver a intentarlo, pero con menos tiempo y teniendo que explotar un n˙mero de pelotas mayor. AsÌ hasta que nos plantemos o perdamos.

A bote pronto ( valga la expresiÛn ) tenemos dos entidades claramente diferenciadas: el universo del juego, y la pelota en sÌ, luego parece lÛgico pensar que debamos estructurar el juego en dos clases, una que maneje la lÛgica del juego ( que se encargue de colocar las pelotas en pantalla, compruebe si se han explotado las suficientes, si queda tiempoÖ ), y otra que maneje el comportamiento de la pelota. Vamos a fijarnos en Èsta ˙ltima.

Evidentemente, la pelota se va a representar con un MovieClip. Luego podemos pensar que lo lÛgico serÌa crear una clase Pelota que extienda de MovieClip, y sobrescribir el onEnterFrame, de manera que ese mÈtodo se encargue de chequear la posiciÛn de la pelota en cada frame, haga el chequeo de colisiÛn con el suelo, compruebe si la pelota se ha salido de la pantalla por alguno de los lados, y que coloque la pelota dependiendo de esas circunstancias ( dicho de otra forma, que implemente un mecanismo para manejar la ecuaciÛn de movimiento de la pelota ), que detecte cu·ndo se ha hecho click en la pelota y se lo notifique al universo del juego, que maneje la animaciÛn de explosiÛn de la pelota, etcÖ.

…ste no creo que sea ni el momento ni el lugar para discutir sobre si ese enfoque puede considerarse el m·s apropiado o no. Partamos de la base de que no hay una forma correcta y otras incorrectas de hacer las cosas. Pero ve·moslo con espÌritu crÌtico.

Por un lado, vamos a tener una clase con una abanico de responsabilidades muy amplio ( desde comportamientos fÌsicos a mera presentaciÛn ). Eso es lo que se denomina baja cohesiÛn. Dicho de otra forma: "zapatero, a tus zapatos".

Adem·s, el comportamiento de la pelota se deber· implementar como un enorme switch o una larga serie de sentencias if ( si ha rebotado con el suelo, haz esto; si te has salido por alguno de los lados, haz esto otro;Ö.. ). Bueno, pues, esto, precisamente, es uno de los casos que se ponen como ejemplo de "Èste es el momento para implementar un state". Sobre todo teniendo en cuenta, que aunque Èste no sea el caso, el comportamiento de la pelota podrÌa ser reactivo, es decir podrÌa tener que cambiar a lo largo del juego ( cambia el rozamiento con el aire, las propiedades din·micas del rebote, etc ).

Por hoy es suficiente. En breve veremos lo que es una m·quina de estados, y cÛmo implementarla.

Junio 24, 2004

Redescubriendo el libro de B. Hall y S. Wan

No hace mucho ( no sabrÌa ahora mismo cuantificar cuanto, si fue hace dos meses, tres, cuatro...) contaba Oscar Trelles en su blog que estaba releyendo el libro de Branden Hall y de Samuel Wan "Object-Oriented Programming with ActionScript" y que le estaba resultando muy interesante, bastante m·s que la primera vez que lo leyÛ.

Continuar leyendo "Redescubriendo el libro de B. Hall y S. Wan" »

Junio 14, 2004

Curso de AS

Saludos,
bueno, ya casi 5 meses en mi nuevo trabajo, y una de las cosas que tengo que hacer es dar un curso de ActionScript en el CETIC ( Centro de TecnologÌas de la InformaciÛn y la ComunicaciÛn ), dependiente del Ayuntamiento de Vitoria-Gasteiz. El curso empieza esta misma tarde, y est· enfocado a la programaciÛn orientada a objetos. Espero que les resulte interesante a mis alumnos y no se me duerman en clase ( 4 horas al dÌa )

Bueno, pues hablando ya de todo un poco, sigo sin internet ( hay que ponerle soluciÛn a esto ya ) y sigo con mucho trabajo. Afortunadamente, aunque yo no postee nada o casi nada en el blog este sigo vivo gracias a interesantes posts de mi hermano.
Bueno, un saludo.

Junio 09, 2004

Un ejemplo del patrÛn Proxy

Quiero salvar una lista de usuarios registrados, pero no sÈ exactamente donde. La cuestiÛn es que dependiendo del valor de un checkbox ( en el que el usuario elige si est· conectado a internet o no ), debo mandar los datos a servidor ( en formato XML ) o guardarlos en disco en un Shared Object

°Esta es una misiÛn para el patrÛn Proxy. ø Por quÈ?. Porque quiero aislar el proceso de guardar los datos del resto del programa, simplemente quiero decir, "eh, guardame esto" y olvidarme de cÛmo o dÛnde se guarda.

Eso es lo que hace este patrÛn. El proxy guarda una referencia a un objeto, que es quien realmente se encargar· de ejecutar la acciÛn. Pero es el proxy el que crea ese objeto, por lo que puede crear una instancia de una u otra clase dependiendo de ciertas condiciones en tiempo de ejecuciÛn

Por tanto, todas las clases que puedan ser instanciadas por el proxy, deben implementar el mismo interfaz. Y dependiendo del tipo de proxy, puede ser una buena idea que incluso Èl mismo implemente ese interfaz, para que se pueda eliminar si es necesario.

Basta ya de literatura. Primero, el interface:

interface ISaveable { public function saveUserList( theList: Array ); }

Sencillo, øno?. Queremos salvar una lista de usuarios, por lo tanto hemos definido un mÈtodo saveUserList

Ahora, la clase que se encarga de enviar los datos a servidor

class myXML extends XML implements ISaveable { private var userArray: Array; function myXML( ) { this.userArray = new Array( ); } function sendData( ) { //this.sendAndLoad( ); } public function saveUserList( theList: Array ) { trace( "The XML is handling the data" ); this.userArray = theList; //create the XML nodes, and send to server } }

Nada complicado. Simplemente un mÈtodo p˙blico que recibe el array de usuarios, que se utilizar· para crear el XML que se enviar· a servidor

Bien, ahora la clase que guarda los datos en disco:

class mySO implements ISaveable { private var theSO: SharedObject; private var userArray: Array; function mySO( ) { this.userArray = new Array( ); } public function saveUserList( theList: Array ) { trace( "The Shared Object handles the data" ); this.userArray = theList; } }

Esta clae implementa ISaveable, y al recibir los datos, intentar· guardarlos en un Shared Object

Ahora la parte compleja. En este ejemplo, he representado el valor del checkbox ( el estado de la conexiÛn ) utilizando una variable en _root. Pero para obtener el valo9r de esa variable, voy a utilizar un singleton. Simplemente, porque me parece una manera mejor, en este caso, que hacer una referencia directa a _root desde el proxy

class singleton { private static var inst:singleton; private function singleton() {} public static function get instance():singleton { if (inst == null) inst = new singleton(); return inst; } public function isConnected( ): Boolean { return _root.connected; } }

Y, por fin, el proxy

class saveUserListProxy implements ISaveable { private var realClass: ISaveable; function saveUserListProxy( ) { var config: singleton = singleton.instance; var conFlag: Boolean = config.isConnected( ); if ( conFlag ) { this.realClass = ISaveable( new myXML( ) ); } else { this.realClass = ISaveable( new mySO( ) ); } } public function saveUserList( theList: Array ) { this.realClass.saveUserList( theList ); } }

Y finalmente, en este ejemplo, en la lÌnea de tiempo principal tendrÌamos:

var connected: Boolean = false; var theUserList: Array = new Array( ); theUserList.push( { id: 0, name: "Cesar" } ); theUserList.push( { id: 1, name: "Javier" } ); var myProxy: saveUserListProxy = new saveUserListProxy( ); myProxy.saveUserList( theUserList );

Podeis probar que todo funciona cambiando el valor de la variable "connected"

Y eso es todo. Son casi las dos de la maÒana de otra jornada laboral de casi 11 horas. Creo que ya va siendo hora de irse a la cama.....

Mayo 30, 2004

Banco de sonidos del Ministerio de EducaciÛn

El Ministerio de EducaciÛn espaÒol pone a nuestra disposiciÛn casi 5000 sonidos en formato wav y mp3, que pueden ser utilizados libremente en el ·mbito de la educaciÛn. Lo posteo sobre todo para no perder el link ( los aÒos no perdonan ).

La direcciÛn: http://iris.cnice.mecd.es/bancoimagenes/sonidos/index.php

TambiÈn hay vÌdeos, im·genes y seÒales.

ACTUALIZACI”N ( 3/7/2005 ): Mauricio Becerra nos indica que el link correcto para el banco de sonidos es Èste: http://recursos.cnice.mec.es/bancoimagenes/sonidos/index.php

Mayo 19, 2004

Sobre los interfaces de colaboraciÛn

No espereis nada brillante en este post, sÛlo es una historia que muestra cÛmo los interfaces de colabroaciÛn pueden ayudar en el trabajo diario

Durante los ˙ltimos tres meses he estado trabajando en un framework para poder generar juegos con gran rapidez. Estamos llegando a nuestra primera gran entrega, por lo que no tenemos mucho tiempo libre, que digamos

Ayer empecÈ el desarrollo de un grupo de cinco juegos muy similares entre sÌ. Los hemos llamado "juegos de disposiciÛn" porque se trata de disponer diversos elementos en la pantalla, siguiendo una reglas previas. Hay cinco juegos diferentes ( por ejemplo, uno en el que hay que colocar a unos escolares en un autob˙s, sin poner juntos a los niÒos conflictivos, en otro hay que realizar una serie de tareas en un orden correcto, etc )

La arquitectura de los juegos es muy simple. Hay una clase llamada "mundo" que agrega otra llamada "scenario", que contiene la lÛgica del juego. La clase mundo se encarga de controlar el tiempo de juego, enviar mÈtricas a servidor, cargar los elementos gr·ficos, etc. Los cinco juegos son tan similares que hemos intentado construirlos con la mayor cantidad de cÛdigo com˙n posible

Hemos decidido que tendrÌamos un swf ( dispositionMotor ) donde se inicializa el mundo, y que carga otro swf ( nameOfGame.swf ) que contiene el escenario del juego y las reglas del mismo. Por tanto, habr· sÛlo un "dispositionMotor" y cinco ( por ahora ) "nameOfGame"

Se nosplanetan dos posibilidades: primero, podemos tener cinco clases mundo distintas, y que cada una de ellas inicialice el escenario que corresponda, o una sola clase mundo genÈrica y cinco escenarios diferentes ( Èsta, Èsta!! )

Continuar leyendo "Sobre los interfaces de colaboraciÛn" »

Mayo 17, 2004

Conferencias WWUGM

El prÛximo dÌa 19 tendr· lugar una serie de conferencias en Madrid, Oviedo y Barcelona.

Las conferencias se podr·n seguir tanto on-line (via FlashComm) o de forma presencial. Se han organizado 3 conferencias, 1 de dreamweaver y 2 de flash. Hay algo m·s de informaciÛn en ( http://www.5dms.com/wwugm )

Los organizadores del evento dicen que uno de los objetivos que han buscado al organizar todo esto era ponernos caras los unos a los otros y llevar la comunidad Flash Hispana un pelÌn m·s lejos. El encuentro ser· bastante informal sin pretender ning˙n tipo de formalismo, sino todo lo contrario, que no sean conferencias sino charlas.

El sistema habilitado para las conferencias on-line permitir· hacer preguntas, ver y oir al ponente, etc, etc.

M·s informaciÛn en http://www.5dms.com/wwugm

Mayo 06, 2004

Ted Patrick anuncia PRIM

Ted Patrick ( desarrollador de, entre otros, PowerSDK ), ha anunciado el inmilente lanzamiento de PRIM.

øPero quÈ es PRIM? B·sicamente es un conjunto de primitivas para flash. Es decir, que proporciona tipado de datos. La diferencia con el tipado de datos propio de AS2 es que, con PRIM, ese tipado se produce en tiempo de ejecuciÛn, y no en tiempo de compilaciÛn.

El misterio est· en la propia estructura de estas librerÌas. En realidad PRIM es un conjunto de getter-setters predefinidos, que son los que, en tiempo de ejecuciÛn, se encargan de mantener el tipado.

Entre los tipos proporcionados est·n Boolean, Integer, Number,....

Puedes ver la documentaciÛn completa aquÌ.

Mayo 03, 2004

Componente Accordion

Este es un ejemplo de cÛmo el componente accordion puede contener otros componentes. De hecho es el cÛdigo fuente del acordeÛn que se puede ver en la p·gina principal de este blog.

Este es el resultado final:

Tiene tres pestaÒas, la primera contiene una lista, la segunda un ·rbol, y la tercera un movieclip sencillo

Lo primero de todo ser· arrastrar al stage una instancia del componente list y otra del componente tree. Una vez en el stage, las borramos. De esta forma, quedan en la librerÌa

TambiÈn he colocado en el stage una instancia del componente accordion, le he asignado altura y anchura, y el nombre de instancia "accordion" ( sin las comillas ). …sta instancia no hay que borrarla

TambiÈn he creado un movieclip con la informaciÛn de contacto. Su linkage ( o vinculaciÛn ) es "contact" ( tambiÈn sin las comillas )

Quiero que las secciones de descargas y enlaces recogan los datos de xmls externos, para que todo sea m·s facil de mantener y actualizar. Puedes ver el xml para las descargas aquÌ, y el de los enlaces aquÌ

Por tanto, nuestro cÛdigo cargar· esos dos xmls, y cuando los haya cargado asignar· el dataProvider correspondiente de cada uno de los componentes:

import mx.controls.Tree; import mx.controls.List; //var language: String = "es"; _global.style.setStyle("fontFamily", "TrebuchetMS" ); _global.style.setStyle("fontSize", 12); _global.style.setStyle("themeColor", "haloOrange"); var ac = this.accordion; ac.createChild( List, "downloadsF", { label: "Downloads", _width: 200, _height: 236 } ); ac.createChild( Tree, "linksF", { label: "Links", _width: 200, _height: 236 } ); ac.createChild( "contact", "contactF", { label: "Contact" } ); var myList = ac.getChildAt( 0 ); myList.vScrollPolicy = "auto"; myList.dataProvider = [ { label: "loading data", data: 0 } ]; myListXML = new XML( ); myListXML.ignoreWhite = true; myListXML[ "theList" ] = myList; myListXML.onLoad = function( success ) { if ( success ) { var theDP: Array = new Array( ); var elements: Array = this.firstChild.childNodes; var numElem: Number = elements.length; for ( var k: Number= 0; k< numElem; k++ ) { theDP.addItem( { label: elements[ k ].attributes[ "label" ], data: elements[ k ].attributes[ "data" ] } ); } this[ "theList" ].dataProvider = theDP; } } if ( language=="es" ) { myListXML.load( "http://www.design-nation.net/enlaces/downloads.xml" ); } else { myListXML.load( "http://www.design-nation.net/enlaces/downloads_en.xml" ); } var myTree = accordion.getChildAt( 1 ); myTree.vScrollPolicy = "auto"; myTree.setStyle("openEasing", mx.transitions.easing.Back.easeInOut ); myTreeDataProvider = new XML(); myTreeDataProvider.ignoreWhite = true; if (language=="es"){ myTreeDataProvider.load("http://www.design-nation.net/enlaces/tree.xml?ran="+ Math.random()); }else{ myTreeDataProvider.load("http://www.design-nation.net/enlaces/tree_en.xml?ran=" + Math.random()); } myTreeDataProvider.onLoad = function(){ myTree.dataProvider = this; } eventListener = new Object(); eventListener[ "tree" ] = myTree; eventListener[ "list" ] = myList; eventListener.change = function(eventObject){ if ( eventObject.target._name == "linksF" ) { var theSelectedNode = eventObject.target.selectedNode; var theSelectedNodeLabel = theSelectedNode.attributes.label; var esLink = theSelectedNode.attributes.isLink; var esBranch = this.tree.getIsBranch( theSelectedNode ) if ( esBranch ){ if ( this.tree.getIsOpen( theSelectedNode ) ){ this.tree.setIsOpen( theSelectedNode, false, true ); }else{ this.tree.setIsOpen( theSelectedNode, true, true ); } }else{ if ( esLink ){ var theSelectedNodeURL = theSelectedNode.attributes.url; getURL( theSelectedNodeURL ); } } } if ( eventObject.target._name == "downloadsF" ) { getURL( myList.selectedItem.data ); } } myTree.addEventListener("change", eventListener); myList.addEventListener( "change", eventListener );

Eso es todo. Enhorabuena si no te has dormido antes de llegar aquÌ.

 

Abril 30, 2004

Seguimos con los botones

Hace un par de semanasposteÈ sobre los problemas que est·bamos teniendo con unos botones.

Aunque hubo comentarios con soluciones bastante interesantes, nos vimos obligados a seguir adelante con nuestra "soluciÛn" por falta de tiempo para hacer otra cosa.

Pero, finalmente, nos hemos visto obligados a cambiar algunos de los botones, para poderlos "calzar" en unos di·logos modales que estamos construyendo.

AsÌ que ahora tenemos un movieclip con tres frames, con etiquetas "normal", "over", y "click", y un textfield con nombre de instancia "literal". Queremos asignar el contenido del literal del botÛn, su formato, y el handler para el onRelease, pero tenemos que poder hacerlo en momentos distintos de la ejecuciÛn del programa. Cuando la aplicaciÛn se inicializa, asignamos texto y formato, y el handler depender· del flujo de ejecuciÛn del programa

Este es el resultado:

class net.designnation.UI.buttonHandler { public static function setBTHandlers( buttonInstance: MovieClip, texto: String ) { buttonInstance[ "textoParam" ] = texto; buttonInstance[ "literal" ].text = texto; buttonInstance.onRollOver = function( ) { this.gotoAndStop( "over" ); var theInstance: String = ""; this[ "literal" ].text = this[ "textoParam" ]; }; buttonInstance.onRollOut = function( texto ) { this.gotoAndStop( "normal" ); this[ "literal" ].text = this[ "textoParam" ]; }; buttonInstance.onPress = function( texto ) { this.gotoAndStop( "click" ); this[ "literal" ].text = this[ "textoParam" ]; }; } public static function setNewTextFormat( buttonInstance: MovieClip, format: TextFormat ) { buttonInstance.literal.setNewTextFormat( format ); } public static function setTextFormat( buttonInstance: MovieClip, format: TextFormat ) { buttonInstance.literal.setTextFormat( format ); } public static function setOnRelease( buttonInstance: MovieClip, value: Function ) { buttonInstance._onRelease = value; buttonInstance.onRelease = function () { this._onRelease( ); this.gotoAndStop( "normal" ); } } }

°Buen fin de semana!

Abril 13, 2004

Las rarezas de los botones

HacÌa aproximadamente un par de aÒos que no tenÌa que vÈrmelas con un botÛn, pero ayer en el curro recibimos una avalancha de elementos gr·ficos de un freelance, entre otros una tacada de botones.

Esos botones deben presentar un texto din·mico, y contienen dos campos de texto distintos. Uno para el estado normal, y otro para el rollover. AsÌ que all· que me lancÈ

class net.designnation.UI.buttonHandler { public static function setHandlers( instanceName: MovieClip, text: String ) { instanceName[ "theText" ] = text; instanceName.onRollOver = function( ) { this.tf.text = this[ "theText" ]; } instanceName.onRollOut = function( ) { this.tf.text = this[ "theText" ]; } } }

No funcionÛ. AsÌ que intentÈ tracear el contenido del botÛn:

class net.designnation.UI.buttonHandler { public static function setHandlers( instanceName: MovieClip, text: String ) { instanceName[ "theText" ] = text; instanceName.onRollOver = function( ) { for ( var k in this ) { trace( k ); } this.tf.text = this[ "theText" ]; } instanceName.onRollOut = function( ) { this.tf.text = this[ "theText" ]; } } }

Y aquÌ llegÛ la sorpresa. En el primer rollover la traza fue:

tabIndex
getDepth
enabled
useHandCursor
instance2

Pero en el rollout, instance2 cambiÛ a instance3. Y en el siguiente rollover a instance4, y en el rollout instance5, y asÌ sucesivamente.La primera vez que veÌa algo parecido, aunque supongo que para muchos de vosotros no ser· ninguna novedad. øLa soluciÛn?: pues nada elegante, ya que se basa precisamente en ese comportamiento tan extraÒo:

class net.designnation.UI.buttonHandler { public static function setHandlers( instanceName: MovieClip, text: String ) { instanceName[ "theText" ] = text; instanceName.onRollOver = function( ) { for ( var k in this ) { if ( k.substring( 0,8 )== "instance" && k.text != undefined ) { this[ k ].text = this[ "theText" ]; } } } instanceName.onRollOut = function( ) { for ( var k in this ) { if ( k.substring( 0,8 )== "instance" && k.text != undefined ) { this[ k ].text = this[ "theText" ]; } } } } }

øDurante cu·nto tiempo funcionar·? Pues no lo sÈ, la verdad.

Una razÛn m·s para no volver a utilizar botones, y hacerlo todo con movieclips

Abril 07, 2004

Fix para el "Flash Resource Manager"

Mike Chambers publicÛ esta maÒana en su blog esta aplicaciÛn. El caso es que al instalarla y ejecutarla en mi sistema ( windowsXP y 2000 en espaÒol ), obtenÌa un error como Èste:

------------------------------------------------
07/04/2004 10:51:17 : Error parsing help file.
C:\Documents and Settings\ctarda\ConfiguraciÛn local\Datos de programa\Macromedia\Flash MX 2004\es\Configuration\HelpPanel\Help\ActionScriptDictionary\help_toc.xml
There is an invalid character in the given encoding. Line 3, position 26.

Repetido varias veces y con varios archivos distintos. Tras varios e-mails de ida y vuelta con Mike Chambers, finalmente hemos encontrado la soluciÛn.

1.- En primer lugar hay que editar el archivo de configuraciÛn ( app.config ) que se encuentra en la carpeta /config. Hay que cambiar el contenido del nodo "Language" para que contenga la cadena "es" ( sin comillas )

2.- Hay que coger uno por uno todos los archivos que aparecen en el mensaje de error ( tambiÈn se puede ver en el fichero /logs/error.log ), abrirlos con un editor de texto, y guardarlos con formato utf-8.

Y ya est·. Toda la ayuda de Flash, el MXNA, Fullasagoog, ayuda de Central, de componentes, ........ TODO en una ˙nica aplicaciÛn de escritorio.

A disfrutarlo!

Abril 06, 2004

Tabla hash V2

Hace m·s o menos un mes, publiquÈ una implementaciÛn de una tabla hash. El caso es que ayer encontrÈ un pequeÒo bug a la hora de borrar elementos, y ya que estaba, he hecho un par de mejoras.

Podeis encontrar el post original aquÌ

Y podeis bajaros el cÛdigo actualizado aquÌ

Felices vacaciones ( a los que las tengan, claro )

Marzo 26, 2004

øAlguien utiliza el panel de mysql?

Hace ya un tiempo publicamos una extensiÛn para el IDE que consistÌa en un panel para poder ver la estructura de una base de datos mySQL que se estuviera ejecutando en la misma m·quina que el IDE de flash, acompaÒada de una clase php. ( Lo puedes encontrar aquÌ )

Ya hemos superado las 1000 descargas de ese panel ( entre la versiÛn inglesa y la espaÒola ), y el caso es que nadie, absolutamente nadie, nos ha comunicado ning˙n error, fallo, problema en la instalaciÛn, etc.

Esto sÛlo me lleva a una conclusiÛn: nadie lo est· utilizando realmente. O tal vez me equivoque,simplemente funciona bien... De todas formas, si lo has utilizado, me gustarÌa saber tu opiniÛn.

Marzo 25, 2004

Un post que no sirve para mucho

Tras un dÌa entero serializando y deseralizando clases, necesitaba hacer algo lo m·s "flashero" posible. Pues aquÌ est·: una clase que puede utilizarse como temporizador.

Permite ejecutar algo determinado ( que se le pasa como par·metro ) cuando ha pasado el tiempo que se le pasa como par·metro tambiÈn, y permite resetear ese temporizador de manera que act˙e como timeout, permite pararlo, eliminarlo, ...

Continuar leyendo "Un post que no sirve para mucho" »

Marzo 20, 2004

Mi experiencia con el desarrollo de un framework en AS2

Durante los dos ˙ltimos meses, he estado trabajando en el desarrollo de un framework escrito en AS2, como parte de un proyecto de dos aÒos, que incluye el desarrollo de unos 200 juegos y de una plataforma de e-learning.

Este framework ser· la base del desarrollo de esos 200 juegos, de heco, ya hemos realizado algunos juegos con fÌsica sencilla ( tiros parabÛlicos, rebotes,.. ) en unas cuatro o cinco horas.

El desarrollo est· basado en la aplicaciÛn de patrons de diseÒo, sobre todo de m·quinas de estados, aunque tambiÈn estamos implmentando otros patrones, como el Modelo-vista-controlador, Fachada, Singleton, Decorator, etc.

Teniendo en cuenta que yo provengo del mundo del script puro y duro no me ha resultado muy facil adaptarme ( y no creo que realmente lo consiga del todo nunca ), aunque debo reconocer que tanta abstracciÛn en el cÛdigo nos va a permitir, no sÛlo sacar adelante el proyecto, sino mantener el cÛdigo con mucha mayor facilidad.

Merece la pena intentar zambullirse a fondo el POO. Pero sobre todo merece la pena hacerlo en flash, porque, antes o despuÈs, va a llegar el momento en el que va a hacer falta recurrir a lo mejor que tiene este lenguaje: su flexibilidad, las animaciones procedurales, ...

Marzo 11, 2004

El estilo de mi cÛdigo

Ultimamente, he leido varios posts sobre estilo de cÛdigo, o coding standards( como Èste de Dominick ). Bueno, pues Èste es mi estilo:

En primer lugar, el cÛdigo debe explicarse por sÌ mismo. Por eso, en mi trabajo no escribimos demasiados comentarios, aunque sÌ escribimos diagramas UML.

Pero lo podreis ver todo mucho m·s claro con una clase de ejemplo:

/* El nombre de la clase est· precedido de las iniciales del proyecto. En este caso, esta clase extiende a otra */ class net.designnation.pnTestClass extends pnSuperClass { /* Primero, definimos las variables privadas. Como las vamos a manipular a travÈs de getter/setters, todas terminan con el sufijo "Val" */ private var strVal : String; private var boolVal : String; private var mcVal : MovieClip private var arg : Number; /* Ahora va el constructor */ function pnTestClass( argParam: Number ) { this.arg = argParam } /* Y los getter/setters. SÛlo definiremos los que hagan falta, es decir, si no necesitamos un getter, no lo definiremos. */ function set str( value: String ) { this.strVal = value; } function get str( ): String { return this.strVal; } /* AquÌ sÛlo definimos el setter */ function set bool( value: Param ) { this.boolVal = value; } function set mc( value: MovieClip ) { this.mcVal = value; } //Los mÈtodos privados private function privateMethod( Void ): Void { } // El resto de mÈtodos p˙blicos e // implementaciÛn de interfaces public function publicMethod( Void ): Boolean { //Accedemos a una propiedad privada desde //la clase, por lo que no necesitamos un getter var returnVal: Boolean = false; if ( this.boolVal ) { returnVal = true; } return returnVal; } /* Y finalmente, callbacks y listeners */ public function onKeyUp( ) { } }

Un par de detalles importantes. Siempre utilizamos el "this", para que asÌ sea m·s facil ver cu·ndo estamos utilizando un mÈtodo o propiedad que pertenece a la clase. Si no utilizamos el this, se sobreentiende que el mÈtodo o propiedad es de la superclase

El espaciado muy importante. HAce que el cÛdigo sea m·s facil de leer, y de comprender. No nos importa que la calse tenga muchas lÌneas en blanco, si eso ayuda a ver "bloques" de cÛdigo

Las llaves van siempre pareadas. Y siempre hay un espacio en blanco entre operadores

Los mÈtodos que devuelvan un valor, deber·n tener un ˙nico punto de salida ( "return" )

Espero que os resulte util. Para nosotros, la verdad, lo es.

Marzo 09, 2004

MXNA

Acabamos de recibir el e-mail en el que nos comunican que la versiÛn inglesa ( bueno, en eso que parece inglÈs ) de este blog va a ser agregado por el MXNA desde hoy.

Sobra decir que lo consideramos, a la vez, un honor, y desde luego una gran responsabilidad.

MXNA ( Macromedia XML News Aggregator ) es, como su nombre indica, un agregador de blogs, que aunque sÛlo agrega webs en inglÈs, es uno de los recursos m·s importantes para que cualquier usuario ( sea diseÒador, programador, o cualquier perfil entre medias) pueda encontrar informaciÛn actualizada sobre cualquiera de las herramientas de Macromedia ( Flash, Director, Dreamweaver, Flex, ... ).

En fin, algo, que al menos para nosotros, siempre ha sido una de las visitas diarias obligatorias. Esperamos que, aunque ahora estemos tambiÈn nosotros, lo sigais visitando ;P

Marzo 01, 2004

Patrones de diseÒo: Modelo-vista-controlador ( de verdad )

Darron Schall comentÛ ayer en la versiÛn inglesa de este blog que la implementaciÛn presentada de este patrÛn no se ajustaba a los c·nones establecidos.

Efectivamente, en mi implementaciÛn, era el controlador el que se encargaba de realizar la comunicaciÛn entre el modelo y la vista, de manera que esas dos capas no tuvieran conocimiento la una de la otra. Hace ya tiempo que lo hago asÌ, y habÌa olvidado que lo que dicen los libros es que es la vista la que debe escuchar los eventos emitidos por el modelo.

Bueno, pues rectificar es de sabios (dicen). Lo cierto es que el cÛdigo del post de ayer en realidad no era un MVC, y por eso, he refactorizado el cÛdigo para cumplir estrictamente con el patrÛn.

Ahora el controlador agrega una instancia de la vista y otra del modelo. La vista escucha los eventos del modelo, y se comunica con el modelo utilizando el controlador.

Probablemente lo veais m·s claro viendo el cÛdigo fuente

Patrones de diseÒo: MVC (Modelo.vista-controlador)

Vamos a hacer un contador de tiempo inverso. Al hacer un click en el fondo se inicializa el contador, que se puede poner en pausa haciendo otro click en el fondo. Haciendo otro click m·s se vuelve a arrancar

Podeis encontrar una explicaciÛn muy completa de en quÈ consiste el patrÛn MVC aquÌ

B·sicamente, se trata de dividir la aplicaciÛn en tres capas. El modelo, son los datos o la lÛgica de la aplicaciÛn, la vista el interfaz, y el controlador el encargado de unir uno y otro, es decir, de actualizar los datos cuando se manipula el interfaz, y de actualizar el interfaz cuando cambian los datos.

En nuestro caso, el modelo es una clase AS2 que es la encargada de llevar la cuenta del tiempo. A cada segundo, emite un evento, que recibe el controlador, que a su vez, se encargar· de actualizar la vista, que es un campo de texto donde se presenta el tiempo restante. Cuando se hace un click en el fondo, la vista comunica el click al controlador, que a su vez, comunica al modelo que debe cambiar su estado (para si estaba arrancado, o arrancar si estaba parado).

Aprovechamos que el orden de carga ( configuraciÛn de publicaciÛn ) del swf es de abajo a arriba, para instanciar el controlador en la primera capa del primer frame , y la vista en la segunda capa del primer frame.

Para instanciar el controlador:

import net.designnation.patterns.* var myController: controller = new controller( this ); myController.init( 60 );

El controlador tiene agregado una instancia del modelo, de manera que en el modelo se instancia en el mÈtodo init( ) del controlador :

public function init( time: Number ) { this.myClock = new clock( this.timeline, time ); this.myClock.addEventListener( "endOfTime", this ); this.myClock.addEventListener( "updateTime", this ); this.myClock.init( ); }

De este modo, se instancia la clase clock, pas·ndola como par·metros una referencia al _root, y el tiempo total. Esa referencia al _root se utiliza para crear un clip vacÌo, en cuyo onEnterFrame se decrementa el tiempo total.

public function init( ) { this.clockClip = timeline.createEmptyMovieClip( "empty", this.timeline.getNextHighestDepth( ) ); this.clockClip[ "owner" ] = this; this.clockClip.onEnterFrame = function ( ) { if ( this[ "owner" ].workingFlag ) { if ( this[ "owner" ].actualTime>= 1 ) { this[ "owner" ].actualTime--; if ( this[ "owner" ].actualTime % FRAMERATE == 0 ) { this[ "owner" ].dispatchTime( this[ "owner"].actualTime ); } } else { this[ "owner" ].dispatchTime( ); delete this.onEnterFrame; } } } }

Observemos la sintaxis de la lÌnea

this.clockClip[ "owner" ] = this;

Es lo mismo que escribir

this.clockClip.owner = this;

El hecho de meter "owner" entre corchetes es tan sÛlo para identificar esa propiedad con un vistazo como una propiedad que he creado din·micamente. Por tanto, es una de las convenciones que yo utilizo, no tiene mayor significado.

Como puede verse, cuando hace falta actualizar el campo de texto con el tiempo restante, la instancia de clock dispara un evento

private function dispatchTime( actualTime: Number ) { if ( actualTime == null ) { var event = "endOfTime"; } else { var event = "updateTime"; } this.dispatchEvent( {type: event, target: this, time: ( actualTime/ FRAMERATE ) } ); }

Como el controlador est· registrado como listener de clock, se ejecuta el mÈtodo correspondiente:

public function updateTime( arg: Object ) { this.timeline.clock.text = arg.time; }

que es el que se encarga de actualizar la vista.

En sentido contrario, la lÛgica es parecida, salvo que se ejecutan directamente los mÈtodos p˙blicos correspondientes ( que, en realidad deberÌan formar parte de un interfaz de comunicaciÛn, pero eso ya es complicarnos demasiado por hoy ).

Cuando se hace click en el fondo,

this.onMouseUp = function( ) { myController.changeClockState( "clock" ); }

Y en el controlador:

public function changeClockState( ) { this.myClock.changeClockState( ); }

Y finalmente, en la clase clock:

public function changeClockState( ) { this.workingFlag = !this.workingFlag; }

Resumiendo, todas las comunicaciones en uno u otro sentido se har·n a travÈs del controlador. De ese modo, aseguramos la independencia entre la parte gr·fica de la aplicaciÛn y los datos de la misma, y por tanto nuestra aplicaciÛn ser· m·s modular, m·s f·cil de mantener, de modificar, nuestro cÛdigo estar· m·s estructurado, ....

Por otra parte, podeis ver cÛmo la vista no est· estructurada como clase AS2, ya que no parece necesario hacerlo. Es una de las cosas que me encantan de flash. Podemos mezclar cÛdigo en uno u otro estandar, dependiendo de lo que nos interese en cada momento....

Descarga el cÛdigo fuente y el fla aquÌ

Febrero 17, 2004

Estructuras de datos: tabla hash

Una tabla hash es una especie de colecciÛn de listas enlazadas. Nos permite guardar pares clave-valor, y luego recuperar esos datos utilizando la clave.

Encontrar·s una definiciÛn mejor aquÌ

Y mi implementaciÛn aquÌ

Para testearlo puedes utilizar algo como esto:

import net.designnation.structs.* var a: HashMap= new HashMap( ); // Setitem // key= "4"; trace( "Agrego "+ key ); a.setItem( key, new Object( key ) ); trace( "Contenidos del HashMap: "+ a.toString( ) ); key= "21"; trace( "Agrego "+ key ); a.setItem( key, [ "a1", "a2" ] ); trace( "Contenidos del HashMap: "+ a.toString( ) ); key= "5"; trace( "Agrego "+ key ); a.setItem( key, new Object( key ) ); trace( "Contenidos del HashMap: "+ a.toString( ) ); key= "8"; trace( "Agrego "+ key ); a.setItem( key, new Object( key ) ); trace( "Contenidos del HashMap: "+ a.toString( ) ); key= "81"; trace( "Agrego "+ key ); a.setItem( key, new Object( key ) ); trace( "Contenidos del HashMap: "+ a.toString( ) ); key= "8"; trace( "Agrego "+ key ); a.setItem( key, new Object( key ) ); trace( "Contenidos del HashMap: "+ a.toString( ) ); // GetItem // key= "8"; trace( "Tomo el valor de "+ key ); trace( a.getItem( key ).toString( ) ); // Count // trace( "TamaÒo: "+ a.count( ) ); // Remove // key= "4"; trace( "Elimino "+ key ); a.remove( key ); trace( "Contenidos del HashMap: "+ a.toString( ) ); trace( "TamaÒo: "+ a.count( ) ); key= "4"; trace( "Elimino "+ key ); a.remove( key ); trace( "Contenidos del HashMap: "+ a.toString( ) ); trace( "TamaÒo: "+ a.count( ) );

Febrero 11, 2004

Accediendo a las propiedades de una clase de forma din·mica

Es probable que esto no suponga niguna novedad, pero de todas formas, vamos all·:

Actualmente estoy trabajando en una clase para serializar y deserializar otras clases. Por ejemplo, la siguiente:

class net.designnation.tests.Serializable { private var prop1: String; private var prop2: Number; private var prop3: Object; private var unseen: String; public static var CONSTANT: String = "Esto es una constante"; function Serializable( ) { this.unseen = "Hola, mundo!"; } public function set val1( param: String ) { this.prop1 = param + " <:::::::: setter "; } public function get val1( ): String { return this.prop1 + " <:::::::: getter ";; } public function set val2( param: Number ) { this.prop2 = param + 100; } public function get val2( ): Number { return this.prop2 + 10000; } public function set val3( param: Object ) { this.prop3 = param; } public function get val3( ): Object { return this.prop3; } }

Para leer sus propiedades, podemos hacer lo siguiente:

import net.designnation.tests.* import net.designnation.utils.* var myClass: Serializable = new Serializable( ); myClass.val1 = "Hi!"; myClass.val2 = 32; myClass.val3 = { prop: "value" }; trace(" ------------------------\n "); for ( var k in myClass ) { trace( k + " == " + myClass[ k ] ); } //setting for ( var k in myClass ) { if ( k == "prop1" ) myClass[ k ] = "modificado"; if ( k == "unseen" ) myClass[ k ] = "unseen, modificado"; } //checking trace(" \n------------------------\n "); for ( var k in myClass ) { trace( k + " == " + myClass[ k ] ); }

Pero, quÈ ocurre cuando queremos acceder a esas propiedades a travÈs de sus getters / setters?. Pues que no lo podemos hacer, ya que no aparecen en el bucle for .. in

Pero, utilizando ASSetPropFlags, se pueden mostrar todas las propiedades y mÈtodos de myClass.__proto__, es decir, de la clase a partir de la cual se instancia ese objeto. Esto es muy peligroso, porque realmente no se sabe durante cu·nto tiempo va a seguir existiendo ese mÈtodo. Pero, para nuestro caso, es la forma de poder acceder a todos los mÈtodos de la clase

class net.designnation.utils.showProps { static function showAll( obj ) { _global.ASSetPropFlags( obj.__proto__, null, 0, 1 ); return obj; } }

De vuelta al script:

// Mostrando todas las propiedades myClass = showProps.showAll( myClass ); trace(" \n------------------------\n "); for (var k in myClass) { trace( k ); } //Obeteniendo los valores a travÈs de los getters trace( " \n------------------------\n " ); trace( " Llamando a los getters \n" ); for (var k in myClass) { var prefix: String = k.substring( 0, 7 ); var posfix: String = k.substring( 7, k.length); if ( prefix == "__get__" ) { trace( myClass[ k ]( ) ); } } trace( " \n------------------------\n " ); trace( " seteando utilizando los setters \n" ); for (var k in myClass) { var prefix: String = k.substring( 0, 7 ); var posfix: String = k.substring( 7, k.length); if ( prefix == "__set__" ) { if ( posfix == "val1" ) myClass[ k ]( " the end " ); } } trace( myClass.val1 );

Resuelto. Peligroso, no muy limpio, pero puede sacar de alg˙n apuro.

Febrero 09, 2004

Lista enlazada V2

La semana pasada publicamos una clase para implementar listas enlazadas. Bueno, pues ahora esa clase ha sido mejorada y limpiada, para hacerla m·s eficaz.

No cambia nada en la forma de implementarla, excepto el mÈtodo "insert" que ahora se llama "insertOrdered".

Descarga las clases necesarias aquÌ.

Febrero 01, 2004

ImplementaciÛn de una lista enlazada

Pues vamos con una implementaciÛn de una lista enlazada simple. El cÛdigo necesita ser optimizado (sobre todo porque el mÈtodo deleteElement se apoya en otro que hace pr·cticamente lo mismo, y porque la lista se recorre por Ìndices, y podrÌa hacerse mejor simplemente mirando a los punteros). Pero sirve para empezar. De todas formas, seg˙n vaya oiptimizando el cÛdigo, irÈ posteando las novedades.

øCÛmo funciona?. Pues para crear una instancia de la lista, se le pasa como par·metro una instancia de una clase llamada "comparador", que tiene definido un mÈtodo lessThan() que es el que se encarga de decidir cÛmo se debe ordenar la lista. En este caso, la lista va a contener objetos, y la ordenaciÛn ser· por la propiedad "index" de esos objetos (ordenaciÛn ascendente, por cierto).

Por tanto, esa clase comparador quedarÌa m·s o menos asÌ:

class net.designnation.structs.Comparador implements IOrder { function Comparador() { } public function lessThan( firstComp: Object, secondComp: Object): Boolean { if (firstComp.index< secondComp.index) { return true; } else { return false; } } }

Entonces, para crear la lista harÌamos:

import net.designnation.structs.*; var myList:List = new List(new Comparador());

Y para manipularla:

myList.push({index:6, prop:"propvalue6"}); myList.insert({index:3, prop:"propvalue3"}); trace("Lista " + myList); myList.insert({index:0, prop:"propvalue0"}); trace("Lista " + myList); myList.insert({index:2, prop:"propvalue2"}); trace("Lista " + myList); myList.insert({index:1, prop:"propvalue1"}); trace("Lista " + myList); myList.insert({index:4, prop:"propvalue4"}); trace("Lista " + myList); myList.insert({index:5, prop:"propvalue5"}); trace("Lista " + myList); myList.insert({index:7, prop:"propvalue7"}); trace("Lista " + myList); myList.insert({index:6, uno:"propvalue6"}); trace("Lista " + myList);

Si te resulta de interÈs, puedes descargarte el cÛdigo aquÌ

Enero 19, 2004

Panel para flash: mySQL

Esto es algo que utilizo habitualmente, y que tal vez os pueda resultar util a alguno.

Se trata de un panel para poder ver la estructura de una base de datos mySQL. Necesita tener un servidor web capaz de ejecutar php's, y no permite ver los registros de la base de datos, tan sÛlo la estructura de la misma.

En una prÛxima versiÛn es probable que incluya la posibilidad de lanzar querys contra la base de datos, y navegar los resultados.

Instrucciones de instalaciÛn
----------------------
1.- Descomprimir y copiar el contenido de la carpeta php a una carpeta del servidor web

Ej: En una m·quina windows, se pueden copiar esos archivos a

c:\apache\htdocs\databases\

2.- Instalar el archivo mxp desde el Extension Manager

3.- Arrancar Flash. Se puede acceder al panel desde el men˙ Ventana->Otros paneles->databasesList

4.- Introducir los datos de configuraciÛn:

4.1.-script: DirecciÛn de la carpeta en la que se encuentran los php. Siguiendo el
ejemplo anterior:

http://localhost/databases/

Debe incluirse la barra final.

4.2.- host: servidor mySQL. Normalmente ser· localhost

4.3.- User: usuario del servidor

4.4.- Password: password para ese usuario

Por favor, dejad cualquier comentario, sugerencia, reporte de errores, etc.

Descargar el panel mySQL

Enero 16, 2004

øPlayer o m·quina virtual?

Buena pregunta. øRealmente podemos referirnos al flash player como m·quina virtual?

El tÈrmino proviene de Java. La m·quina virtual es el intÈrprete que ejecuta el bytecode generado por el compilador Java. Realmente eso es lo mismo que hace el flash player. Pero entonces, øporquÈ uno se llama player y el otro m·quina virtual?.

La diferencia, a mi entender, proviene de la funcionalidad que ambos permiten. Probablemente, uno de los puntos fuertes de flash sea el poco peso del player. Claro, que eso se paga en cuanto nos ponemos a mirar lo que podemos hacer con Èl, que es m·s bien poco. No podemos acceder a disco, ni acceder directamente a bases de datos, ni a la configuraciÛn del sistema, ni un largo etcÈtera. Dicho de otra manera, no podemos hacer demasiadas cosas fuera de un navegador.

Pero, ørealmente tendrÌa sentido que pudiÈramos hacer en flash lo mismo que hacemos en java, o en C#?. Pues la verdad, no lo sÈ.

Tengo la sensaciÛn que la direcciÛn en la que nos estamos moviendo es la de implantar una nueva plataforma de desarrollo, alternativa a Java (Sun) o .Net(Microsoft), sÛlo que esta vez de Macromedia. Y eso me parece bueno, pero tambiÈn me parece que corremos el riesgo de olvidar lo que nos ha hecho llegar hasta aquÌ.

øAlg˙n comentario?

Enero 13, 2004

Componentes de Remoting para mx 2004

VÌa Metalogic recojo la noticia de la salida de componentes de flash remoting para mx 2004. Lo puedes descargar del sitio de macromedia

Enero 11, 2004

Flare 0.5 AS decompiler

VÌa Swftools.com, he encontrado esta herramienta, un AS decompiler freeware. LÈelo aquÌ.

Enero 09, 2004

Crear un mÈtodo com˙n a todas las instancias de MovieClip (AS2)

Muy sencillo, direis: crÈalo en el prototipo de movieclip. Pero, øquÈ sucede cuando estamos escribiendo AS 2.0?

Ahora no podemos modificar la clase MovieClip, sino que sÛlo podemos extenderla, y aÒadir nuevos mÈtodos a esas clases hijas. øSeguro?. Veamos:

La teorÌa sobre programaciÛn orientada a objetos es que si queremos aÒadir alg˙n mÈtodo a la clase movieclip, lo que debemos hacer es:

class net.designnation.exp.Mezcla extends MovieClip{ function Mezcla(){ trace("constructor de mezcla"); } //Este es el mÈtodo que queremos que // tengan todos los movieclips private function metodoAS1(){ trace("este es el mÈtodo particular"); } }

Bien, esto nos permite hacer que la clase Mezcla tenga todos los mÈtodos heredados de MovieClip, y adem·s el mÈtodo metodoAS1. Pero ese mÈtodo AS1 pertenece a la clase Mezcla, y sÛlo a ella. Es decir, que si cre·ramos otra clase que extendiera de movieclip, si queremos que tenga el mÈtodo metodoAS1, deberÌamos definirle.

De todas formas, algunos ya habreis pensado: distintas clases con el mismo mÈtodo.... øinterfaces?. Efectivamente, podemos implementar un interface:

interface net.designnation.exp.MCInterface{ public function metodoAS1():Void; }

Y hacer que nuestras clases lo implementen:

import net.designnation.exp.*; class net.designnation.exp.Mezcla extends MovieClip implements MCInterface{ function Mezcla(){ trace("constructor de mezcla"); } //Este es el mÈtodo que forma parte del interfaz. //debemos definirlo aquÌ!!! private function metodoAS1(){ trace("Èste es el mÈtodo particular"); } }

øEst· nuestro problema solucionado?. No del todo. El hacer que una clase implemente un interfaz sÛlo sirve para que el compilador nos dÈ un error si esa clase no tiene implementados todos los mÈtodos del interfaz. Dicho de otra manera, el hacer que una clas implemente un interfaz, nos sirve sÛlo para asegurarnos que esa clase implementa una serie de mÈtodos, que hemos enumerado en otro lugar (el interfaz).

Pero esos mÈtodos debemos implementarlos en todas y cada una de las clases que implementen el interfaz, con lo que tampoco conseguimos lo que queremos, que por si alguien se ha perdido (y yo estoy a punto) no es m·s que definir una sola vez un mÈtodo, y que ese mÈtodo sea accesible a MovieClip y a todas sus subclases.

Probablemente la soluciÛn m·s estricta y elegante serÌa hacer una clase que heredara de movieclip, con el mÈtodo que queremos implementar definido en ella, y hacer que el resto de clases hereden de esa clase, en vez de hacerlas heredar de movieclip.

Pero si por algo nos caracterizamos los programadores (o desarrolladores, o scripters o lo que seamos) que trabajamos con actionscript es por que no nos gustan demasiado las soluciones estrictas y elegantes. Para eso ya hay gente que sabe muchÌsimo Java.

Por lo tanto, vamos a lo que nos gusta de verdad.

Recordemos la ìviejaî forma de definir un mÈtodo com˙n a todas las instancias de una clase:

MovieClip.prototype.metodoAS1 = function(){ trace("Bien!. Se ha ejecutado el mÈtodo AS1"); };

Si escribimos ese cÛdigo en el primer frame de nuestro fla, antes de cualquier otra cosa, todas las instancias de MovieClip tendr·n implementado ese mÈtodo.

øPero quÈ pasa con nuestra clase?. Veamos: nuestra clase hereda de MovieClip, luego:

class net.designnation.exp.Mezcla extends MovieClip{ function Mezcla(){ trace("constructor de la clase Mezcla"); } private function metodoAS2(){ trace("Y yo soy el mÈtodo AS2"); }; public function onRollOver(){ //Ejecuto el mÈtodo metodoAS1 de la superclase. super.metodoAS1(); metodoAS2(); }; }

Para ilustrar el ejemplo, vamos a crear un movieclip, que utilizaremos como botÛn. Dentro de ese clip, hay que dibujar una forma cualquiera, porque lo que queremos es asignarle a la clase anterior, y ver quÈ pasa cuando hacemos rollOver sobre Èl.

Una vez creado el movieclip, en sus propiedades de vinculaciÛn, asignamos como Indentificador ìMiClipî y como Clase de AS 2.0 ìnet.designnation.exp.Mezclaî

Por tanto, el cÛdigo del primer frame de nuestro fla queda de la siguiente manera:

MovieClip.prototype.metodoAS1 = function(){ trace("Bien!. Se ha ejecutado el mÈtodo AS1"); }; //Al hacer attachmovie, se instanciar· la clase Mezcla this.attachMovie("MiClip", "instancia", 1);

øQuÈ pasa al hacer rollover sobre el clip?. Premio!. Se ejecuta el mÈtodo que definimos en el prototype de MovieClip. Pero, ese mÈtodo reside en la superclase de la clase Mezcla, luego øcÛmo podemos ejecutar desde ese mÈtodo otros mÈtodos de la clase Mezcla?

Modifiquemos un poco los mÈtodos metodoAS2 y onRollOver de Mezcla

private function metodoAS2(arg){ trace("Y yo soy el mÈtodo AS2 " + arg); }; public function onRollOver(){ super.metodoAS1(this); };

TambiÈn la definiciÛn de metodoAS1 en el prototype de MovieClip:

MovieClip.prototype.metodoAS1 = function(ref){ trace("Bien!. MÈtodo AS1" + this.constante); ref.metodoAS2("x " + this._width); };

øQuÈ hemos hecho?. Pues desde la clase Mezcla llamamos al mÈtodo de su superclase, pas·ndole una referencia a la clase desde la que dicho mÈtodo ha sido llamado. Por tanto, ahora, la superclase sabe quÈ clase la ha llamado, y puede saber a quiÈn debe contestar.

øA alguien le han quedado ganas de hacer alg˙n comentario?

Enero 07, 2004

BotÛn redimensionable

El problema: hace falta un botÛn que pueda presentarse en distintos tamaÒos, sin que deforme el texto del mismo.

La soluciÛn: construir el botÛn en tiempo de ejecuciÛn. Para ello, tenemos tres clips: borde izquerdo, borde derecho, y fondo. Lo dem·s, lo resolveremos al inicializar el botÛn.

Pero primero veamos el resultado:

Continuar leyendo "BotÛn redimensionable" »

El pirata del mar de plata

Eres el pirata m·s temido del mar de la plata. °Defiende tu castillo de las tropas del gobernador!






El juego es muy sencillo, pero iremos repasando el cÛdigo poco a poco.

Los gr·ficos del juego son de Celia Carracedo. Es recomendable pasarse por su web ;)

Diciembre 30, 2003

Mi primera extensiÛn!!! (jsfl)

Uno de los proyectos en los que estoy trabajando est· formado por catorce fla, que utilizan algunas clases comunes a todos ellos, de manera que cuando se quiere hacer alg˙n cambio, hay que publicarlos todos uno a uno. øNo serÌa mejor poder publicarlos todos a la vez?

°Bien!. °Justo lo que necesitaba!: una oportunidad para hacer mi primera extensiÛn. Es algo muy sencillo, pero es la primera, y eso es lo que cuenta.

Descarga PublishAll.mxp

Diciembre 29, 2003

CuestiÛn de flexibilidad (AS 2.0)

Pero esta flexibilidad no es exclusiva del "viejo" actionscript, sino que podemos hacer exactamente lo mismo con AS2.0

En primer lugar, vamos a crear nuestra clase de pruebas:

class net.designnation.exp.Dinamica{ public var prop1:String; public var prop2:String; public var prop3:String; function Dinamica(){ } public function metodo(Void):Void{ trace("mÈtodo ------"); trace(prop1 + " " + prop2 + " " + prop3); } }

Esta clase tiene que salvarse en disco en un archivo que se llame Dinamica, y en el path correspondiente (es decir, net/designnation/exp).

En el primer frame de la lÌnea de tiempo principal escribimos lo siguiente:

import net.designnation.exp.*; var testClass:Dinamica = new Dinamica(); testClass.prop1 = "Hola"; testClass["prop2"] = "estoy"; var cadena:String = "prop3"; testClass[cadena] = "probando"; //Ahora recupero los valores for (var k=1;k<4;k++){ trace(testClass["prop"+k]); } //Y ejecuto el mÈtodo definido testClass.metodo(); //o bien testClass["metodo"](); //o bien var cadena2:String="metodo"; testClass[cadena2](); stop();

Ahora, pues, podemos hacer que un mÈtodo de la clase ejecute otro cuyo nombre se pasa como par·metro, o que una clase ejecute mÈtodos de otra, o......

En fin, que, una vez m·s, actionScript demuestra ser un lenguaje muy potente y flexible.

CuestiÛn de flexibilidad

Como ya es conocido, los objetos en ActionScript realmente son una especie de arrays accesibles no sÛlo por n˙mero de Ìndice, sino por un identificador.

Por tanto, cuando queremos manipular alguna de las propiedades de un objeto lo podemos hacer de las siguiente manera:

var miObj = new Object(); miObj.prop1 = "design-nation";

Aunque tambiÈn podemos hacerlo asÌ:

var miObj = new Object(); miObj["prop1"] = "design-nation";

Y esto nos abre la puerta a acceder a los valores de las propiedades de objetos de forma din·mica. Por ejemplo:

var miObj = new Object(); miObj.prop1 = "propiedad1"; miObj.prop2 = "propiedad2"; miObj.prop3 = "propiedad3";

Y luego podemos acceder a esos valores de la siguiente manera:

for (var k=1;k<4;k++){ trace("la propiedad prop"+k+ " tiene el valor " + miObj["prop"+k]); }

øY quÈ pasa con los mÈtodos?. Pues algo parecido. Veamos:

var miObj = new Object(); miObj.metodo1 = function(){ trace("metodo1"); } miObj["metodo1"]();

Por tanto, podremos ejecutar mÈtodos de un objeto de forma din·mica, sin saber realmente lo que estamos ejecutando.

Diciembre 27, 2003

Extensiones para Flash MX 2004

Impresionante colecciÛn de extensiones para el entorno de Flash. (informaciÛn recogida del blog de Josh Dura)

Diciembre 26, 2003

Componente Tree (·rbol)

Estoy empezando a trabajar con los nuevos componentes de Flash MX 2004.

Hoy, un poco tambiÈn para probar su supuesta facilidad de uso, he hecho la pequeÒa "aplicaciÛn" de enlaces que podeis ver en la parte derecha.

Y efectivamente, ha sido r·pido y f·cil:

_global.style.setStyle("fontSize", 12); myTree.setStyle("color", 0x999966); myTree.setStyle("borderStyle","solid"); myTree.setStyle("themeColor", "haloBlue"); // carga y asignacion de contenido myTreeDataProvider = new XML(); myTreeDataProvider.ignoreWhite = true; myTreeDataProvider.onLoad = function(){ myTree.dataProvider = myTreeDataProvider; } myTreeDataProvider.load("/enlaces/tree.xml"); myTreeListener = new Object(); myTreeListener.tree = myTree; //Listener para el evento change del arbol //Quiero desplegar nodos al seleccionarlos myTreeListener.change = function(eventObject){ var theSelectedNode = eventObject.target.selectedNode; var theSelectedNodeLabel = theSelectedNode.attributes.label; var esLink = theSelectedNode.attributes.isLink; var esBranch = this.tree.getIsBranch(theSelectedNode) if (esBranch){ if (this.tree.getIsOpen(theSelectedNode)){ this.tree.setIsOpen(theSelectedNode, false, true); }else{ this.tree.setIsOpen(theSelectedNode, true, true); } }else{ if (esLink){ var theSelectedNodeURL = theSelectedNode.attributes.url; //trace("url " + theSelectedNodeURL); getURL(theSelectedNodeURL, "_blank"); } } } myTree.addEventListener("change", myTreeListener); stop();

Dos cosas a tener en cuenta: evidentemente, el nombre de instancia del componente es myTree; y podeis ver el formato que tiene el xml carg·ndolo desde el Internet Explorer

Diciembre 23, 2003

Nuevo build de PrimalScript 3.1 beta

La verdad es que estoy gratamente impresionado. Acabo de recibir un email de los chicos de soporte de Sapien, comunicando que han publicado un nuevo build de la beta de PromalScript 3.1.

Entre otras mejoras, han resuelto el problema de la instalaciÛn en sistemas no USA, es decir, que si tienes el flash en espaÒol, funcionar·n los codehints y la ayuda.

Puedes bajar el nuevo build aquÌ

Diciembre 22, 2003

CaÌda libre (cÛdigo fuente)

AquÌ est· el cÛdigo fuente de la caÌda libre.

Como podrÈis ver, no es un cÛdigo particularmente brillante, y puede (y deberÌa) optimizarse para que no fuera tan intensivo para el procesador.

Pero, aun asÌ, lo m·s importante es demostrar que todo se puede realizar sin que haya referencias explÌcitas ni a _root ni a ninguna otra lÌnea de tiempo en concreto.

De esta manera, ganamos en portabilidad y modularidad, ya que este "experimento" puede construirse sobre el _root, dentro de un movieclip, dentro de un movieclip que a su vez est· dentro de otro, cargarse dentro de otro swf, etc.

Todo ello se consigue aquÌ:

var miGravedad:Gravedad = new Gravedad(this);

Al pasar como par·metro al constructor del objeto miGravedad la referencia a la lÌnea de tiempo, resolvemos todos los problemas que nos podÌa reportar el tener una referencia a_root.

B·jate el cÛdigo fuente (si quieres, claro)

CaÌda libre de un objeto

Otro pequeÒo ejercicio m·s. Arrastra el cÌrculo, y suÈltalo para verlo caer. Tanto la aceleraciÛn de la caÌda, como la absorciÛn de energÌa en el rebote son parametrizables.

Desde luego, no es un modelo real, pero.....







Diciembre 19, 2003

Expermiento 3.0

Sigo buscando inspiraciÛn para hacer otras cosas:







Diciembre 18, 2003

Experimento 2.0

Una vuelta de tuerca m·s:







Un pequeÒo experimento

Estoy comenzando a preparar un juego, y como trabajo previo estoy escribiendo unas cuantas funciones matem·ticas para manejar la fÌsica del mismo.

Por ahora, sÛlo he escrito dos cosas muy simples: una funciÛn que devuelve la distancia entre dos puntos, y otra que devuelve el ·ngulo del vector que une a dos puntos. El caso es que, llegado a ese punto, me he empezado a aburrir, y se me ha ocurrido jugar un poco con unos cuantos movieclips.

El resultado est· aquÌ (hace falta el flashplayer 7):







Obviamente, no est· ni por asomo optimizado, es tan sÛlo algo que he montado en media hora, pero seg˙n lo estaba haciendo me he dado cuenta de que podÌa ser es el primer swf que poste·ramos en el blog, asique...

Si quieres bajarte el fla y las clases, haz click aquÌ.

Diciembre 17, 2003

Planear bien un proyecto

Parece una obviedad, pero el hecho de no haber planeado bien un proyecto, antes de comenzar a escribir cÛdigo o a generar gr·ficos, puede convertirlo en una pesadilla. Y m·s cuando se quiere realizar alguna aplicaciÛn para dispositivos port·tiles (pocketPC, telÈfonos,...).

En esos casos, m·s que nunca, hay que realizar un trabajo previo bastante intenso: definir claramente la funcionalidad, intentar separar la estructura de datos de la presentaciÛn de los mismos, conocer las limitaciones de la plataforma a utilizar, planear los tests, identificar los puntos dÈbiles de la aplicaciÛn,....

En el "Mobile and Devices Developer Center" de Macromedia han publicado un artÌculo bastante interesante sobre la materia (en inglÈs):

Planning Your Mobile Flash Projects

Diciembre 15, 2003

que viene que viene

moock

Diciembre 10, 2003

M·s sobre PrimalScript 3.1

Bueno, pues en principio las cosas no ha funcionado como deberÌan.

Parece que esta aplicaciÛn no se ha previsto para funcionar en sistemas distintos al inglÈs. De hecho, en mi trabajo, con un Windows 2000 SP5 en espaÒol, no he conseguido que funcione correctamente, ya que la carpeta donde flash instala las clases y la ayuda es c:\Documents and Settings\usuario\ConfiguraciÛn local\........

Seg˙n parece, el programa busca las clases de macromedia, y las del usuario en c:\Documents and settings\usuario\Local settings\........

He mandado un par de correos a Sapien, exponiendo el problema.

Ya os contarÈ cÛmo sigue el asunto.

PrimalScript 3.1 Public Beta

Hoy ve la luz la beta p˙blica de PrimalScript 3.1, el primer IDE (que yo conozca) especÌficamente orientado al desarrollo con ActionScript 2.0.

Yo he estado usando PrimalCode 3.0 en mis proyectos con AS2, y la verdad es que he quedado bastante contento: navegador de clases, pistas de cÛdigo, auto-completado, y m·s funcionalidades que facilitan bastante la vida.

Yo ya me he bajado mi copia de la beta, y voy a empezar a utilizarlo ahora mismo. Ya os contarÈ.

M·s info: aquÌ

Descarga: aquÌ

Diciembre 09, 2003

LoadVars que carga un XML

Antes de continuar con la serie de "tutoriales" sobre ActionScript 2.0, y aunque est· claro que no deberÌa publicarlo ahora, sin todavÌa haber visto un poco m·s en profundidad los fundamentos del lenguaje, querÌa postear esta clase, que he escrito la semana pasada para un proyecto en el que estoy trabajando.

El escenario es el siguiente:

Necesito enviar el "login" y "password" que el usuario introduce a un script en php, que una vez ha identificado al usuario, devuelve un XML con el contenido de los men˙s de la aplicaciÛn para el perfiel de ese usuario.

øCÛmo hacerlo?. La primera parte est· clara. Utilizando la clase LoadVars, puedo enviar los datos necesarios a servidor, gracias al mÈtodo sendAndLoad. Dicho mÈtodo recoge la respuesta del servidor (que suele ser del tipo "variable1=valor1&variable2=valor2....." de manera que en el objeto destino de esa peticiÛn se generan las propiedades recibidas con los valores recibidos.

Pero øy si necesito recoger de servidor un XML?. Pues es muy f·cil. Asignando lo que se recibe de servidor a un objeto XML. øQuieres saber cÛmo?

Continuar leyendo "LoadVars que carga un XML" »

Noviembre 30, 2003

API de FlashPaper

Macromedia acaba de publicar la documentaciÛn de la API de FlashPaper.

Para los que a˙n no lo sep·is, FlashPaper es parte de Contribute 2, y permite publicar documentos vectoriales (como si fueran pdf), pero en formato swf.

El conocer esta API nos va a permitir embeber los documentos flashpaper dentro de nuestras aplicaciones flash.

Api de FlashPaper
Contribute

Noviembre 29, 2003

ActionScript 2.0 - clase 1.0

Vamos a comenzar una serie de pequeÒos "tutoriales" sobre ActionScript 2.0. La sintaxis de este lenguaje, es la derivada del est·ndar ECMAScript 4, y es la misma que, por ejemplo, la de JScript .Net. Ahora tenemos clases m·s parecidas a las de Java, que las propias de ActionScript 1.0, sobre las que por cierto, se han vertido rÌos de tinta discutiendo si eran clases reales o no. Sea como fuere, vamos a crear nuestra primera (e inutil) clase en ActionScript 2.0 Vamos all·: class DesignBlog{ private var texto:String function DesignBlog(arg){ texto = arg; }; public function resultado(Void):String{ return texto.toUpperCase(); }; }

Continuar leyendo "ActionScript 2.0 - clase 1.0" »

Servidor de Flash Remoting en Java

Midnight Coders acaba de lanzar la beta2 de su servidor de Flash Remoting implementado en Java, FlashORB.

Puedes encontrar m·s informaciÛn sobre el producto en http://www.flashorb.com

Festival de tipografÌas

øBuscas una tipografÌa nueva?. øEst·s aburrido de usar siempre los mismos tipos de letra?.

Tal vez deberÌas pasarte por TypeBase...

Noviembre 19, 2003

La importancia de un diseÒador

Con la llegada de Flash MX 2004, y su nuevo set de componentes (UI Components) se facilita enormemente el desarrollo de aplicaciones con un entorno gr·fico de usuario (GUI) de gran calidad, dejando tiempo al desarrollador para centrarse en la lÛgica de la aplicaciÛn.

Pero este nuevo paso en el proceso seguido por Macromedia de hacer de Flash la nueva "herramienta de desarrollo" encierra muchos riesgos. Para mÌ, el m·s evidente es que, cuando ya han pasado m·s de dos meses desde el lanzamiento de Flash MX 2004, todavÌa no he visto ninguna aplicaciÛn que haya, simplemente, eskineado dichos componentes.

Me parece que nos precipitamos por un camino que no tiene f·cil vuelta atr·s. Si prescindimos de los diseÒadores, corremos el peligro de que todas las aplicaciones realizadas en flash sean iguales, y que ocurra como ocurriÛ con Java, y que esa uniformidad sea uno de los primeros sÌntomas de declive.

Creo que no debemos olvidar de dÛnde venimos. Esto es flash. AprovechÈmoslo!!

La eterna batalla

Soy de los que opinan que es muy difÌcil determinar cual es el mejor lenguaje de programaciÛn, y que en muchas ocasiones determinar si es este o el otro viene dado no tanto por el lenguaje de programaciÛn sino por el proyecto a realizar.

Continuar leyendo "La eterna batalla" »

Noviembre 10, 2003

DocumentaciÛn de JSAPI

Al fin Macromedia ha publicado la documentaciÛn de la API Javascript que est· implementada en FLash MX2004.

La documentaciÛn est· aquÌ

Noviembre 09, 2003

Livedocs

Livedocs contiene las ayudas de los programas de Macromedia, con la particularidad de que los usuarios podemos incluir comentarios.

En livedocs, se puede encontrar la documentaciÛn de Flash MX2004, Dreamweaver MX2004, Flash Remoting MX, ColdFusion MX 6.1, JRun 4, etc.

Sparkle, el prÛximo flash-killer

Los hechos:

En Microsoft est·n trabajando en una herramienta para generar gr·ficos y animaciÛn para el nuevo sistema operativo de Microsot (Longhorn), llamado "Sparkle".

Dicha herramienta estar· integrada con el .NET runtime environment, y permitir· a los desarrolladores integrar f·cilmente animaciÛn e interactividad en sus aplicaciones.

Hasta ahÌ, todo normal. Pero claro, lo que Microsoft realmente plantea es una especie de Flash o Director para integrarlo dentor de su plataforma .NET, por lo que ha habido mucha gente que ha empezado a hablar de Sparkle como la aplicaciÛn llamada a acabar con Flash.

Yo personalmente pienso que, en primer lugar, Longhorn no est· previsto hasta el 2006. Y que no sabemos dÛnde estar· Flash dentro de 3 aÒos. Y que si recordamos dÛnde estaba Flash hace 3 aÒos, es de suponer que no debamos temer mucho. Pero, por si acaso, yo hace ya un tiempo que empecÈ a aprender .NET....

Unos cuantos links:
AtNewYork
ActionScript.com
PSDK::Ted
Ars Technica

Noviembre 02, 2003

Compilador de ActionScript

Mike Chambers ha publicado un compilador de Flash 2004.

Aunque el compilador abre el entorno de Flash, puede integrarse perfectamente con varios de los editores de cÛdigo m·s extendidos, como EditPlus, o SciTE|Flash. De esta manera, podemos ganar mucho tiempo en nuestro trabajo diario.

El compilador requiere del .Net Framework, al estar escrito en C#.

M·s informaciÛn: aquÌ.

El nuevo IDE de flash

Durante esta semana he comenzado mi primer proyecto de producciÛn real con el nuevo Flash MX 2004.

La verdad es que la primera aproximaciÛn al nuevo entorno no ha sido muy satisfactoria que digamos. Reconozco que tenÌa unas expectativas demasiado altas (injustificadamente, desde luego), pero lo cierto es que me siento ampliamente decepcionado.

El IDE sigue estando a aÒos luz de los existentes para otros lenguajes (sobre todo Java). No hay codehints para clases del usuario, no hay un navegador de clases, lista de tareas pendientes, y un largo etcÈtera.

Desde luego, el esfuerzo de Macromedia ha sido evidente, pero a˙n queda muchÌsimo para que tengamos un IDE parecido al IntelliJ IDEA. Y nuestro trabajo lo demanda cada vez m·s.

Octubre 28, 2003

Flash MX y Dreamweaver MX Bajo Linux!

Seg˙n slashdot, ya se ha conseguido correr Flash MX y Dreamweaver MX bajo Linux, utilizando CrossOver Office 2.1, de CodeWeavers.

Por fin podemos migrar completamente a Linux!!

Para leer la noticia completa: aquÌ