« Febrero 2005 | Inicio | Abril 2005 »

Marzo 29, 2005

Planeta cÛdigo

Planeta cÛdigo es un agregador de weblogs en castellano, reciÈn creado por Juanjo Navarro, cuyo objetivo es "potenciar la escena de programaciÛn y desarrollo en castellano".

Planeta cÛdigo agrega en el momento de escribir este post a 16 blogs, y pretende, a medio plazo, convertirse en una comunidad para desarrolladores en castellano.

Una visita obligada.

Un ejemplo del PatrÛn Prototype ( la versiÛn Java )

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?

El Profesor Dispar era un respetado cientÌfico espaÒol, que se convirtiÛ en un genio del mal por sus malas condiciones laborales ( y por que su novia se la pegaba con otro, la verdad ). Ahora, su ˙nico deseo es llevar a cabo su malvado plan para °°°dominar el mundo!!!

professorCoupling.jpg
El Profesor Dispar

AsÌ que, en sus delirios paranoides, ha construido una m·quina para clonar. Una m·quina para clonar muy especial, porque puede ser programada en Java

El plan del Profesor Dispar es clonar todas las ovejas que pueda, para asÌ controlar la economÌa mundial y dominar el mundo ( la verdad, no entiendo el porquÈ de ese plan, pero recuerda, aunque estÈ loco, es un genio! ).

sheep.jpg
Una oveja ( vista frontal )

La m·quina para clonar es algo asÌ:

class CloningMachine { public CloningMachine( ) { } public Sheep buildClone( ) { return new Sheep( ); } public Sheep[] buildManyClones( int cloneNum ) { Sheep[] returnArray = new Sheep[ cloneNum ]; for( int k=0; k< clonesNum; k++ ) { returnArray[ k ] = new Sheep( ); } return returnArray; } }

Y la oveja:

class Sheep { public Sheep( ) { System.out.println( "beeeee. Soy una oveja reciÈn creada" ); } }

Tras inundar el mundo con ovejas clonadas ( es su malvado plan, no el mÌo ), el Profesor Dispar se dio cuenta que clonar unos cuantos miles de vacas le ayudarÌa a dominar el mundo m·s r·pido. Pero su m·quina para clonar no fue construida para clonar vacas, sino para clonar ovejas

cow.jpg
Una vaca ( vista lateral )

AsÌ que el malvado genio del mal decide aÒadir a su m·quina la funcionalidad necesaria para clonar vacas. øCÛmo?. Mira:

class CloningMachine { function CloningMachine( ) { } public Sheep buildClone( ) { return new Sheep( ); } public Cow buildCowClone( ) { return new Cow( ); } public Sheep[] buildManyClones( int cloneNum ) Sheep[] returnArray = new Sheep[ cloneNum ]; for( int k=0; k< clonesNum; k++ ) { returnArray[ k ] = new Sheep( ); } return returnArray; } }

El Profesor Dispar est· loco, pero no es idiota. Por tanto, enseguida se da cuenta de que puede encontrarse con problemas si quiere clonar otros animales, como, por ejemplo, p·jaros, o incluso humanos

Tras pensar cuidadosamente sobre su problema, hace otro intento:

class CloningMachine { function CloningMachine( ) { } public Object buildClone( String type ) { if( type.equals( "sheep" ) ) { return new Sheep( ); } else if ( type.equals( "cow" ) ) { return new Cow( ); } } public Sheep[] buildManyClones( int cloneNum ) Sheep[] returnArray = new Sheep[ cloneNum ]; for( int k=0; k< clonesNum; k++ ) { returnArray[ k ] = new Sheep( ); } return returnArray; } }

Tras varios minutos de las tÌpicas risas histÈricas, el Profesor Dispar empieza a pensar en la forma en que ha implementado su m·quina para clonar, y enseguida encuentra varios puntos dÈbiles.

En primer lugar, el mÈtodo buildClone devuelve un Object, no una oveja ( Sheep ) o una vaca ( Cow ). øPor quÈ?. Porque este mÈtodo no sabe lo que va a crear a priori. El Profesor Dispar ( recuerda, est· loco, pero no es idiota ) barrunta que Èsta no es la mejor soluciÛn posible

TambiÈn se da cuenta que si en alg˙n momento quisiera clonar alg˙n otro animal, deberÌa cambiar de nuevo su m·quina para clonar. Y eso no hace su m·quina f·cil de mantener.

Pero entonces, una idea empieza a abrirse paso en su malvado cerebro. A˙n no sabe exactamente cÛmo hacerlo, pero øquÈ pasarÌa si pudiera darle algo a la m·quina( una oveja, una cabra, un humano, o una piedra ) y pedirle a la misma que le devolviera 500 copias del mismo?. °°Brillante!! ( m·s risas histÈricas ). AsÌ, no tendrÌa que preocuparse de cÛmo funciona la m·quina, simplemente la m·quina le devolverÌa tantas copias como necesitara del original que Èl le facilitara.

Entonces, el Profesor Dispar recuerda sus tiempos de estudiante, cuando leyÛ un libro llamado "Patrones de diseÒo: Elementos de software orientado a objetos reutilizable" ( el GoF ), y aquella cosa que se llamaba el "patrÛn prototype"

Por tanto, la m·quina para clonar no puede saber quÈ tiene que clonar ni cÛmo debe clonarlo. …sa ( la creaciÛn de la copia ), ser· una responsabilidad de cada uno de los animales ( o cosas a clonar ). La m·quina de clonar, simplemente recibir· un animal, y le dir· a Èste que produzca tantas copias de sÌ mismo como se necesiten, y luego se las devolver· al Profesor Dispar.

De hecho, el Profesor Dispar se ha dado cuenta de que la forma en la que deben crearse las nuevas copias de los animales no ha de ser la misma para todos, sino que en algunos casos le va a interesar utilizar el mecanismo de clonado de Java, y en otros tener un control m·s fino del mismo.

AsÌ que, la primera tarea del Profesor ser· crear un interfaz ( que extiende Cloneable, implementando de este modo el mÈtodo clone( ) ), que ser· el que implementen tanto la Vaca como la Oveja

public interface CloneableAnimal extends Cloneable { public CloneableAnimal duplicate( ); }

[ Nota ]. SerÌa posible que todos los animales extendieran de una clase base, y que por tanto el tipo que devuelve el mÈtodo duplicate( ) fuera esa clase base. Pero yo voy a continuar mi ejemplo con este interfaz, porque de esta forma el diseÒo es mucho m·s flexible.

Ese mÈtodo duplicate( ) ser· el encargado de crear y devolver una nueva copia de cada animal que lo implemente.

La oveja ahora ser·:

public class Sheep implements CloneableAnimal { public Sheep( ) { System.out.println( "Creada la plantilla de la oveja" ); } public CloneableAnimal duplicate( ) { System.out.println( "La oveja se va a clonar a sÌ misma" ); Sheep returnValue = null; try { returnValue = ( Sheep ) super.clone( ); } catch( Exception e ) { System.out.println( "error cloning Sheep" ); } return returnValue; } public String toString( ) { return "Soy una oveja clonada, beeeeee"; } }

Como se puede ver, el mÈtodo duplicate( ) de la oveja ejecuta el mÈtodo clone( ) de su superclase.

AquÌ est· la vaca:

public class Cow implements CloneableAnimal { public Cow( ) { System.out.println( "Creada la plantilla de la vaca" ); } public CloneableAnimal duplicate( ) { System.out.println( "creando una nueva instancia de Cow" ); return new Cow( ); } public String toString( ) { return "Muuuu, soy un clon de vaca" ; } }

Ahora, el Profesor Dispar tan sÛlo tendr· que hacer algo asÌ:

public class ProfessorCoupling { public static void sayIt( String words ) { System.out.println( "" ); System.out.println( words ); System.out.println( "" ); } public static void main( String[] args ) { CloningMachine cMachine = new CloningMachine( ); sayIt( "creating Sheep and Cow templates" ); Sheep sheepTemplate = new Sheep( ); Cow cowTemplate = new Cow( ); Cow clonedCow = ( Cow ) cMachine.newClone( cowTemplate ); sayIt( "primera vaca clonada" ); Sheep clonedSheep = ( Sheep ) cMachine.newClone( sheepTemplate ); sayIt( "first cloned sheep" ); System.out.println( clonedSheep ); sayIt( "Creando 10 vacas nuevas" ); CloneableAnimal[] newCows = cMachine.cloneMany( 10, cowTemplate ); sayIt( "Creando 10 ovejas nuevas" ); CloneableAnimal[] newSheeps = cMachine.cloneMany( 10, sheepTemplate ); sayIt( "Probando las vacas" ); for( int i=0; i< newCows.length; i++ ) { System.out.println( newCows[ i ] ); } sayIt( "Probando las ovejas" ); for( int i=0; i< newSheeps.length; i++ ) { System.out.println( newSheeps[ i ] ); } } }

Ahora, el Profesor Dispar puede seguir inundando el mundo con los clones creados por su m·quina ( m·s risas histÈricas ), sabiendo que puede crear copias de todo lo que le dÈ la gana, porque le ha dado a su m·quina el "don" de crear objetos sin saber de quÈ tipo deben ser.

Pero el Profesor es un hombre de ciencia, y en su af·n por alcanzar el conocimiento absoluto, sigue leyendo documentaciÛn sobre el patrÛn prototype, y entonces se da cuenta de que tambiÈn ha separado el cÛdigo que crea los objetos del cÛdigo que maneja los detalles de la creaciÛn de nuevos objetos ( eso queire decir que, por ejemplo, si quiere crear 1000 ovejas rojas hoy, y 1000 ovejas azules maÒana, tan sÛlo debe aÒadir una m·quina para pintar animales al lado de la m·quina para clonar, y esa m·quina de pintar se encargar· de darlas color, sin saber cÛmo ni donde se han creado esos animales ).

Gracias a Celia Carracedo, hoy concretamente por los dibujos de la oveja, la vaca, y el malvado Profesor Dispar.

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?

El Profesor Dispar era un respetado cientÌfico espaÒol, que se convirtiÛ en un genio del mal por sus malas condiciones laborales ( y por que su novia se la pegaba con otro, la verdad ). Ahora, su ˙nico deseo es llevar a cabo su malvado plan para °°°dominar el mundo!!!

professorCoupling.jpg
El Profesor Dispar

AsÌ que, en sus delirios paranoides, ha construido una m·quina para clonar. Una m·quina para clonar muy especial, porque puede ser programada en ActionScript

El plan del Profesor Dispar es clonar todas las ovejas que pueda, para asÌ controlar la economÌa mundial y dominar el mundo ( la verdad, no entiendo el porquÈ de ese plan, pero recuerda, aunque estÈ loco, es un genio! ).

sheep.jpg
Una oveja ( vista frontal )

La m·quina para clonar es algo asÌ:

class CloningMachine { function CloningMachine( ) { } public function buildClone( ): Sheep { return new Sheep( ); } public function buildManyClones( cloneNum: Number ) { var returnArray: Array = new Array( ); for( var k=0; k< clonesNum; k++ ) { returnArray[ k ] = new Sheep( ); } return returnArray; } }

Y la oveja:

class Sheep { function Sheep( ) { trace( "beeeee. Soy una nueva oveja reciÈn creada" ); } }

Tras inundar el mundo con ovejas clonadas ( es su malvado plan, no el mÌo ), el Profesor Dispar se dio cuenta que clonar unos cuantos miles de vacas le ayudarÌa a dominar el mundo m·s r·pido. Pero su m·quina para clonar no fue construida para clonar vacas, sino para clonar ovejas

cow.jpg
Una vaca ( vista lateral )

AsÌ que el malvado genio del mal decide aÒadir a su m·quina la funcionalidad necesaria para clonar vacas. øCÛmo?. Mira:

class CloningMachine { function CloningMachine( ) { } public function buildClone( ): Sheep { return new Sheep( ); } public function buildCowClone( ): Cow { return new Cow( ); } public function buildManyClones( cloneNum: Number ) { var returnArray: Array = new Array( ); for( var k=0; k< clonesNum; k++ ) { returnArray[ k ] = new Sheep( ); } return returnArray; } }

El Profesor Dispar est· loco, pero no es idiota. Por tanto, enseguida se da cuenta de que puede encontrarse con problemas si quiere clonar otros animales, como, por ejemplo, p·jaros, o incluso humanos

Tras pensar cuidadosamente sobre su problema, hace otro intento:

class CloningMachine { function CloningMachine( ) { } public function buildClone( type: String ): Object { if( type == "sheep" ) { return new Sheep( ); } else if ( type == "cow" ) { return new Cow( ); } } public function buildManyClones( cloneNum: Number ) { var returnArray: Array = new Array( ); for( var k=0; k< clonesNum; k++ ) { returnArray[ k ] = new Sheep( ); } return returnArray; } }

Tras varios minutos de las tÌpicas risas histÈricas, el Profesor Dispar empieza a pensar en la forma en que ha implementado su m·quina para clonar, y enseguida encuentra varios puntos dÈbiles.

En primer lugar, el mÈtodo buildClone devuelve un Object, no una oveja ( Sheep ) o una vaca ( Cow ). øPor quÈ?. Porque este mÈtodo no sabe lo que va a crear a priori. El Profesor Dispar ( recuerda, est· loco, pero no es idiota ) barrunta que Èsta no es la mejor soluciÛn posible

TambiÈn se da cuenta que si en alg˙n momento quisiera clonar alg˙n otro animal, deberÌa cambiar de nuevo su m·quina para clonar. Y eso no hace su m·quina f·cil de mantener.

Pero entonces, una idea empieza a abrirse paso en su malvado cerebro. A˙n no sabe exactamente cÛmo hacerlo, pero øquÈ pasarÌa si pudiera darle algo a la m·quina( una oveja, una cabra, un humano, o una piedra ) y pedirle a la misma que le devolviera 500 copias del mismo?. °°Brillante!! ( m·s risas histÈricas ). AsÌ, no tendrÌa que preocuparse de cÛmo funciona la m·quina, simplemente la m·quina le devolverÌa tantas copias como necesitara del original que Èl le facilitara.

Entonces, el Profesor Dispar recuerda sus tiempos de estudiante, cuando leyÛ un libro llamado "Patrones de diseÒo: Elementos de software orientado a objetos reutilizable" ( el GoF ), y aquella cosa que se llamaba el "patrÛn prototype"

Por tanto, la m·quina para clonar no puede saber quÈ tiene que clonar ni cÛmo debe clonarlo. …sa ( la creaciÛn de la copia ), ser· una responsabilidad de cada uno de los animales ( o cosas a clonar ). La m·quina de clonar, simplemente recibir· un animal, y le dir· a Èste que produzca tantas copias de sÌ mismo como se necesiten, y luego se las devolver· al Profesor Dispar.

Por tanto ( recuerda, no hay clases abstractas en ActionScript ), todos los animales deber·n implementar un interfaz, que contiene sÛlo un mÈtodo:

interface ICloneable { public function clone( ): ICloneable; }

[ Nota ]. SerÌa posible que todos los animales extendieran de una clase base, y que por tanto el tipo que devuelve el mÈtodo clone( ) fuera esa clase base. Pero yo voy a continuar mi ejemplo con este interfaz, porque de esta forma el diseÒo es mucho m·s flexible.

Ese mÈtodo clone( ) ser· el encargado de crear y devolver una nueva copia de cada animal que lo implemente.

La oveja ahora ser·:

class Sheep implements ICloneable { function Sheep( ) { trace( "Hola, soy Dolly, me van a clonar en un plis" ); } public function clone( ): ICloneable { trace( "Beeee, soy un nuevo clon de Dolly" ); return new Sheep( ); } public function toString( ): String { return "{ Hola, soy una oveja clonada. }"; } }

Y aquÌ est· la vaca:

class Cow implements ICloneable { function Cow( initFlag: Boolean ) { trace( "Muuuu, soy una vaca, a mÌ tambiÈn me van a clonar en un momento" ); if( initFlag == true ) { init( ); } } private function init( ) { trace( "Soy una vaca inicializada, signifique eso lo que signifique" ); } public function clone( ): ICloneable { return new Cow( true ); } public function toString( ): String { return "{ sÌ, soy una vaca clonada, muuuuuu }"; } }

Ahora, el Profesor Dispar tan sÛlo tendr· que hacer algo asÌ:

var cMachine: CloningMachine = new CloningMachine( ); cMachine.buildClone( new Sheep( ) ); cMachine.buildClone( new Cow( ) ); trace( "--" ); var sheepClones: Array = cMachine.buildManyClones( 5, new Sheep( ) ); var cowClones: Array = cMachine.buildManyClones( 5, new Cow( ) ); trace( "--" ); trace( "sheepClones " + sheepClones ); trace( "cowClones " + cowClones );

Por tanto, la m·quina para clonar podr· recibir cualquier animal ( una instancia de una clase ), y mandarla que cree todas las copias de sÌ misma que se necesiten.

class CloningMachine { function CloningMachine( ) { } public function buildClone( template: ICloneable ): ICloneable { return template.clone( ); } public function buildManyClones( clonesNum: Number, template: ICloneable ): Array { var returnArray: Array = new Array( ); for( var k=0; k< clonesNum; k++ ) { returnArray[ k ] = template.clone( ); } return returnArray; } }

Ahora, el Profesor Dispar puede seguir inundando el mundo con los clones creados por su m·quina ( m·s risas histÈricas ), sabiendo que puede crear copias de todo lo que le dÈ la gana, porque le ha dado a su m·quina el "don" de crear objetos sin saber de quÈ tipo deben ser.

Pero el Profesor es un hombre de ciencia, y en su af·n por alcanzar el conocimiento absoluto, sigue leyendo documentaciÛn sobre el patrÛn prototype, y entonces se da cuenta de que tambiÈn ha separado el cÛdigo que crea los objetos del cÛdigo que maneja los detalles de la creaciÛn de nuevos objetos ( eso queire decir que, por ejemplo, si quiere crear 1000 ovejas rojas hoy, y 1000 ovejas azules maÒana, tan sÛlo debe aÒadir una m·quina para pintar animales al lado de la m·quina para clonar, y esa m·quina de pintar se encargar· de darlas color, sin saber cÛmo ni donde se han cread esos animales ).

Gracias a Celia Carracedo, hoy concretamente por los dibujos de la oveja, la vaca, y el malvado Profesor Dispar.

Marzo 28, 2005

[XP] Propiedad colectiva del cÛdigo, tests, y coding standards

Extreme Programming (que es casi m·s una filosofÌa que un mÈtodo de desarrollo) se basa en doce pr·cticas.

Desde mi punto de vista, una de las pr·cticas fundamentales es la "propiedad colectiva del cÛdigo".

øPero, quÈ quiere decir eso?. Pues, como el nombre indica, el cÛdigo no es propiedad de quien lo escribe, sino que cualquier miembro del equipo puede ( y de hecho debe ) mejorar cualquier parte del cÛdigo en cualquier momento.

Esta forma de atacar el desarrollo tiene bastantes ventajas, se programe en parejas, o de forma individual. En primer lugar, se evitan los cuellos de botella. Adem·s, si se ve alguna parte del cÛdigo que necesita ser mejorada, se debe hacer lo antes posible, sin importar quiÈn lo escribiera. De esta forma, el cÛdigo tiende a simplificarse y hacerse m·s sencillo, pero no sÛlo en segmentos concretos del mismo, sino que todo el cÛdigo del proyecto en general va mejorando, ya que se est· refactorizando contÌnuamente. Esas refactorizaciones, adem·s, son mucho m·s simples de realizar, ya que el conocimiento sobre el proyecto se va repartiendo entre todos los miembros del equipo. TambiÈn, la productividad de ese equipo mejora, ya que todo el mundo puede ayudar a cualquiera en cualquier momento, y el nivel de frustraciÛn tiende a bajar ( si eso es posible en un programador ), ya que no hay parones, ni se puede culpar a nadie de que algo no funciones correctamente.

Pero para conseguir llevar a cabo esas "buenas intenciones", hay dos aspectos sobre los que ha habido que trabajar con anterioridad: los tests, y los est·ndares en la estructura del cÛdigo.

Se va a trabajar en un equipo que va a estar cont˙nuamente refinando el cÛdigo. Por tanto, tiene que haber una forma de asegurarse que los cambios que se vayan realizando no van a llevar al proyecto a un punto en el que nada funciona y no se puede volver atr·s. AsÌ que debe haber una serie de tests que permitan ir probando lo que se va cambiando. De hecho ( aunque eso es materia para otro post ), esos tests deberÌan realizarse antes de comenzar a escribir el cÛdigo real. DeberÌa haber un test para cada clase antes incluso de escribir esa clase. De esta forma, cuando alguien cambie una clase, sÛlo tiene que volver a correr el test. øQue todo funciona bien?. Pues a otra cosa.

Pero adem·s, si todos van a poder modificar el cÛdigo, Èste tiene que estar escrito en un lenguaje que todos entiendan ( y no me refiero a lenguaje de programaciÛn, sino a la forma en que est· escrito el cÛdigo ). Si voy a tener que cambiar lo que ha escrito otra persona, lo mejor es que estÈ escrito como si fuera mÌo: nombres de variables similares, nombres de mÈtodos similares, la misma disposiciÛn de parÈntesis, llaves, corchetes, saltos de lÌnea, incluso de espacios en blanco. Esos est·ndares pueden ( mejor, deben ) estar definidos y consensuados por todo el equipo, por todos los que los van a utilizar.

Por cierto, herramientas como Eclipse, facilitan mucho el trabajo a la hora de definir los est·ndares de cÛdigo. Basta con definir unas preferencias ( Ventana->Preferencias->Java->Code Style ) y exportarlas despuÈs a todos los ordenadores de los miembros del equipo.

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.

Por supuesto, el motivo para realizar un motor de estas caracterÌsticas, es el hecho de poder crear numerosas aventuras gr·ficas con el mismo motor, por lo que supuestamente el esfuerzo de programaciÛn debe descender exponencialmente a medida que se van realizando aventuras gr·ficas.

Una vez programado el motor, para cada aventura gr·fica, en el departamento de la empresa al que pertenezco, desarrollamos los archivos XML en el que indicamos quÈ objetos aparecen en cada escena, y lo que ocurre al interactuar con cada uno de ellos ( cambios que se producen en ese y en otros objetos, paso de objetos a inventario, formulaciÛn de preguntas, visualizaciÛn de avisos, requerimiento de objetos de inventario etc... )

Cada cdrom, lleva unos 650 - 700 ficheros flash ( lo que supone unas 2000 animaciones/grafismos diferentes ), y tantos xml de configuraciÛn de escenas, como escenas hay en el juego ( aparte de un par de archivos xml de configuraciÛn general del juego ).
De lo que estoy m·s satisfecho es de los siguientes puntos.

1.Ninguno de estos 700 archivos fla/swf lleva una sola lÌnea de programaciÛn ( a excepciÛn del stop() final de las animaciones )

2.Debido a esto, cada archivo xml de configuraciÛn de una escena est· siendo desarrollado por personas que no tienen conocimientos de flash. ( A la hora de empezar a montar las escenas de configuraciÛn del primer cdrom, estas personas nunca habÌan abierto flash, lo que no impide que creen una escena de dificultad media en unos 20 minutos ). Evidentemente estas personas sÌ tenÌan una amplia experiencia en desarrollo de aplicaciones que incluÌan el uso de archivos XML, por lo que trabajar con este tipo de archivos no era ninguna novedad para ellos.

3. El "mÛdulo 3d" que permite que aunque la escena tenga una visualizaciÛn frontal, o lateral, o dividida en dos pisos... el personaje protagonista de las aventuras pueda pasar por delante y por detr·s de los objetos, bien sea objetos situados en primer plano, en el centro de la escena etc... De esto estoy muy satisfecho, pues dada las diferentes posibles formas de visualizaciÛn habÌa que encontrar un sistema lo suficientemente genÈrico como para funcionar en todas, y no en una sola ( Habitualmente los juegos de este tipo, se construyen con una perspectiva isomÈtrica, pues la soluciÛn al z-sorting es conocida, permite una gran reutilizaciÛn de objetos gr·ficos, algoritmos de pathfinder etc.., pero el cliente no querÌa esto, por lo que tenÌamos que encontrar la forma de hacerlo funcionar con las especificaciones dadas ).


La aplicaciÛn tiene unas 8000 lÌneas de cÛdigo ( incluyendo las necesarias para las pantallas intermedias de selecciÛn de personje, introducciÛn de datos, almacenamiento de los mismos, gestiÛn de las puntuaciones etc...)

Est· construida utilizando un diseÒo orientado a objetos( unos 65 ficheros entre clases e interfaces ) ( toda la aplicaciÛn est· construida usando POO y se arranca llamando al mÈtodo main de la clase base de la aplicaciÛn )

Esta clase base, gestiona las comunicaciones entre las dem·s clases, mediante la emisiÛn y recepciÛn de eventos, aislando asÌ unas de otras, permitiendo la m·xima independencia de cada una de ellas, de modo que una clase no se ve afectada por cambios en las dem·s.

Un ejemplo es la clase "proxy" desarrollada para el almacenamiento de los datos y puntuaciones del usuario. Actualmente, esta salvaguarda de datos se lleva a cabo mediante el uso de sharedObjects en la m·quina del usuario. AsÌ cada vez que el jugador llega a una situaciÛn en la que hay que mostrarle sus puntuaciones y almacenarlas en disco el proceso es el siguiente.

La clase base, recibe un evento desde otra clase, que le indica que el usuario ha llegado a la situaciÛn de mostrar/almacenar puntuaciones. Nuestra clase base indica mediante un evento a la clase encargada de mostrar las puntuaciones, que pinte los valores en pantalla. Cuando esta clase termina de hacerlo, no los almacena, sino que le devuelve un evento a la clase base indic·ndole que ya ha terminado de pintar los datos y que se puede proceder a grabarlos. Entonces la clase base, le envÌa un evento a nuestra clase "proxy", que se encargar· de guardar los datos. Cuando los datos estÈn salvados, le enviar· un evento a la clase base, indic·ndole que el proceso de salvaguarda est· finalizado. Y una vez recibido este evento, nuestra clase base decidir· lo que hay que hacer, si llevar al usuario a otra pantalla ( emitiendo un evento que ser· recogido por el controlador de la vista de destino ) o bien cualquier otra acciÛn. -El uso de estas clases "proxy" es muy habitual por mi parte, pues me permiten no tener que modificar nada de la aplicaciÛn en sÌ, si se produce un cambio de tecnologÌa de servidor ( ASP, PHP, JSP que es la utilizada habitualmente en la empresa, ColdFusion, ...)y se pasa de utilizar una a utilizar otra-.

Uno de los requerimientos del cliente era que la aplicaciÛn fuese f·cilmente portable a web. Cuando llegue el momento, no habr· que hacer m·s que cambiar los mÈtodos "insertData" y "receiveData" de esta clase para que en lugar de almacenar los datos en un sharedObject, llamen a cualquier tecnologÌa de servidor. ( Extender la clase y sobrescribir la parte necesaria de los mÈtodos implicados, o bien utilizar otra clase que implemente la misma interfaz ).

Cada objeto de la aplicaciÛn tiene su propia m·quina de estados, y cada objeto puede tener tantos estados y transiciones entre estados, como se le indique desde el archivo xml de configuraciÛn de la escena( un estado, dos, ......, n estados ). TambiÈn desde este archivo, indicamos quÈ efectos en otros objetos ( cambios de estado en otros objetos ) se producen al interactuar con cada objeto ( en funciÛn de cu·l sea su estado actual ).

Evidentemente, el primer cdrom fue como un parto para todos los departamentos implicados, pero una vez determinado a partir de esa experiencia el sistema de trabajo m·s adecuado, los cdroms se van haciendo a gran velocidad a pesar de las numerosas animaciones necesarias para cada uno de ellos. Adem·s, la experiencia que se va adquiriendo con cada cdrom, hace que los departamentos de guiÛn y de animaciÛn y grafismo, vayan cada vez exprimiendo m·s las posibilidades del juego, y sac·ndolas mayor provecho, haciendo que cada aventura sea m·s bonita gr·ficamente y en cuanto a nivel de animaciÛn que la anterior, y con unas "tramas" m·s complejas. Estamos todos muy satisfechos.

ø QuiÈn dijo que con flash no se podÌan hacer este tipo de cosas?

Marzo 09, 2005

AsÌ, yo tampoco quiero ser EspaÒol

En la p·gina 9 del periÛdico QuÈ! del dÌa 9 de marzo del 2005, y firmado por un tal Louis Anchez

"No quiero ser espaÒol. Quiero llamarme con un nombre raro que tenga muchas consonantes y ser de otro paÌs. AsÌ podrÈ vender en la calle sin licencia, obtener becas para el colegio, acceder a pisos bonitos y caros. øY si me pillan?. QuÈ m·s da. Me pagar·n el vuelo de vuelta."

IncreÌble pero cierto. Hay quien se atreve no sÛlo a pensar estas barbaridades, sino a publicarlas.

No se puede razonar con la locura, la irracionalidad, con lo peor que los seres humanos llevamos dentro.

Es el momento de que los que creemos que simple y llanamente todas las personas somos iguales empecemos a manifestarnos abiertamente, que con el mismo descaro que tienen ellos para lanzar su odio les hagamos saber que no vamos a consentir que traten asÌ a la gente.

Al autor del libelo que abrÌa este post: si de verdad te apetece tanto llevar la vida de un emigrante, hazlo. Pero, eso sÌ, lo hagas o no, por favor, c·llate. Ya.

Marzo 07, 2005

Y las lechugas a dos euros

Vale que los pisos estÈn a cojÛn ( que no a huevo, maravillas del lenguaje ), pero lo de las lechugas ya tiene -utilÌcese aquÌ lo que se quiera, en este caso ambos vocablos valen-.

O esto es una conspiraciÛn de todas las fruterÌas de Vallecas para que engordemos ( a˙n m·s ) a base de comer sÛlo filetes, o hay alguien en alg˙n sitio que est· ahora mismo muriÈndose de risa viÈndonos por un agujerito ( aparte del que pone el precio a los pisos, claro ).

1 lechuga = 2 euros. Pues nada, que sigan estirando la cuerda.

Mini review del mac mini

El viernes, por fin, despuÈs de un mes de espera, recibÌ mi mac mini. Tras dos dÌas de uso, aquÌ est·n mis primeras impresiones.

Primero, unas fotos:

La caja:

mini_caja.jpg

Los contenidos de la caja:

mini_package.jpg

Y el ordenador en su "cunita":

mini_global.jpg

Y la mini review:

1.- InstalaciÛn.

El proceso de instalaciÛn fue extremadamente f·cil y r·pido. Simplemente, se enchufan los cables, se presiona el botÛn de encendido, y ya est·.

ComprÈ el ordenador para dar un descanso a mi viejo pc, pero todavÌa le queda mucha vida como servidor de archivos y cvs, asÌ que tambiÈn comprÈ este switch KVM. TardÈ m·s en desconectar los cables del pc viejo y conectarlos en el switch que en arrancar el mini.

2.- Aplicaciones.

Adem·s del Mac OSX 10.3.7, el ordenador tiene preinstaladas bastantes aplicaciones: iLife'04 (sÌ, 04, not 05), Mail, Safari, iCal, iChat...

En el paquete viene tambiÈn el DVD de iLife '05, por lo que actualizar la suite iLife no lleva m·s que unos minutos.

3.- Performance.

Las especificaciones de hardware:

Procesador: PPC G4 ( 1.42 GHz )
RAM: 512 MB
HDD: 80 GB
Bluetooth / Superdrive

La verdad es que estoy impresionado con la performance del ordenador. Ahora mismo se est·n ejecutando iTunes, iPhoto, Firefox, Mail, iCal, Adium, QuickSilver, ecto, NetNewsWire, AddressBook, un escritorio remoto al pc con windows, y, por supuesto, Flash MX 2004. Y el ordenador funciona con una suavidad impresionante.

Trabajar con flash es suave, mucho m·s que en mi viejo pc. Pero Eclipse ( que es el IDE que utilizo habitualmente ) no es que funcione demasiado suelto, sobre todo cuando se est· picando cÛdigo Java.

4.- VentilaciÛn y ruido.

El ordenador es extremadamente silencioso. Tanto el ventilador como el disco duro son inaudibles en condiciones normales. Pero el SuperDrive es ruidoso, no al ver una pelÌcula, pero sÌ cuando se est· instalando software, por ejemplo.

En cuanto al calor, tras dos dÌas de uso contÌnuo, todas las superficies del ordenador est·n frÌas.

Resumiendo, que estoy impresionado tanto por la facilidad de uso del sistema, como por la facilidad con la m·quina mueve las aplicaciones.

En unas horas, tendrÈ que volver a la oficina a trabajar con mi windows de siempre. Odio los lunes.