lunes, 30 de marzo de 2009

Usando FX.deferAction()


Al desarrollar el componente de acordeón de imágenes, se producía un "pestañeo extraño" al momento de solicitar a los elementos que actualizaran su posición. Le dí algunas vueltas al código hasta comprobar que: no era resultado de algo producido por un error en el código, sino por algo relacionado con el refresco de la pantalla (o algo por el estilo ¿?).

Así que recurrí un poco al instinto y a la memoria... y... recorde haber leido algo sobre deferAction. Así que incluí el código que solicita el ajuste de posición, dentro de la llamada de esta función y el problema terminó:

El siguiente código:


public-read var active: Integer on replace {
for (item in pictures) {
item.adjust();
};
};



Pasó a ser este:


public-read var active: Integer on replace {
FX.deferAction(function():Void {
for (item in pictures) {
item.adjust();
};
});
};



Sólo anidé el for dentro de FX.deferAction(function():Void { ... });

Sí descargan la biblioteca memeFX y quitan el FX.deferAction en ImagesAccordion.fx, quizás puedan ver el problema que me llevó a esta solución (no sé si el problema sea reproducible en otras máquinas). Tampoco me quedó claro que produce el problema ni por qué lo resuelve deferAction, voy a buscar información al respecto. Por ahora, sólo comparto el "tip" en caso que alguien tenga un problema similar.

http://code.google.com/p/memefx/

domingo, 29 de marzo de 2009

Por qué incluir canSkip:true en los timelines


Este video muestra la diferencia en el rendimiento de las animaciones gráficas con y sin canSkip:true. Es recomendable incluir este parametro en los KeyFrame que alteran valores (values:) asociados a animaciones y efectos (cambio de posiciones, variación de sombras, difuminado, etc... cualquier efecto o movimiento gradual).

Una persona del grupo JavafxProgramming creo una aplicación Flex que luego replicó en JavaFX. Su problema era el rendimiento de JavaFX, que hacia su aplicación inutilizable. Pidió consejos al foro, pero nada funcionó... hasta que incluyó el canSkip:true en los timelines... recién ahí la aplicación funcionó como debía.

Quizás sería bueno que Sun incluyera el canSkip con true como valor por defecto. Esto puede terminar desprestigiando la plataforma.

En todo caso, sería bueno que todos comparta este detalle o lo tengan muy presente al momento de usar los timelines o de tener problemas con el rendimiento.

domingo, 22 de marzo de 2009

memeFX 0.2.2 : ImagesAccordion con ORIENTACION


Ahora se puede cambiar la orientación del componente de "acordeón", para que las imágenes se desplacen horizontal o verticalmente. Basta con incluir en la definición del componente, un:

orientation: ImagesAccordion.VERTICAL

para que las imágenes se muevan verticalmente.

viernes, 20 de marzo de 2009

Como crear juegos para móvil con Netbeans 6.5


Realmente, es increible lo fácil que resulta crear un juego para teléfono con Netbeans 6.5. De hecho, este tutorial demuestra como crear uno en ¡10 minutos! Vale la pena verlo y tenerlo en cuenta.

Blogger no me permite incrustar el video aquí, así que ahí les va el enlance (se ve mejor a pantalla completa): CLICK AQUI

- Crea tu propio juego para móvil. Hands on Lab6400 (pdf)
- Mobile Game Project.zip
- Guía para el GameBuilder de Netbeans

memeFX v0.2


Ya está disponible la librería incluyendo una versión final de "acordeón de imágenes". La verdad que tiene muchas opciones para personalizar el componente. Además, permite enlazar algunas acciones del usuario con funciones.

Asi, por ejemplo, se podría hacer el que componente comience a tocar un MP3 distinto al pasar el mouse sobre los distintos elementos del "acordeón", y que muestre detalles sobre la música si se hace click sobre ese elemento. Pudiendo además dejar de tocar al abandonar el "acordeón" (al sacar el mouse de encima).

Proyecto memeFX y descarga código fuente, CLICK AQUI


Demo Java Web Start del ImageAccordion, CLICK AQUI

Esto me dio la idea de hacer una variación que permita crear un "acordeón de formulario", es decir, que haya varios formularios con campos, botones, etc. Y que uno pueda pasar de uno a otro igual que en el acordeón de imágenes. Voy a darle vueltas y veré que resulta.

jueves, 19 de marzo de 2009

Timelines de duración variable y el at(..)


Uno de los inconvenientes de trabajar en un ambientea tan nuevo como el JavaFX script, es que no abundan las fuentes de información.

Una de las cosas que no tenía claras (seguramente porque no investigué lo suficiente, o no miré mejor los ejemplos), era cómo se hace que un timeline tenga duración variable.

Bueno, ahora descubrí que diablos es el at(..) en los timeline y cómo se hace para que la duración sea variable.

Primera cosa, cuando uno usa at(), en realidad está usando una "abreviatura" en la manera de definir un timeline. La idea es que sólo sea una opción breve para escribir el código, pero por lo mismo, no es la forma más "potente".

Tomemos este ejemplo:

var x:Number;
Timeline {
repeatCount: 1
keyFrames: [
at (0s) { x => 0.0}
at (3s) { x => 100.0}
]
}.play();

En él, definimos una variable x, que al segundo 0s -de iniciado el timeline- asume un valor de 0.0, luego, x asumirá gradualmente los valores entre 0.0 y 100.0, alcanzando el máximo valor (100.0) en 3s segundos.

El asunto que me faltaba comprender era... ¿como cambiaba el tiempo en at(3s)?, porque no acepta ni variables ni bind dentro de los paréntesis.

Pues resulta que con at(..) no lo vas a conseguir (por lo menos eso entiendo en este momento), la forma correcta y potente de usar las lineas de tiempo es esta:


var dur=3s;
var x:Number;
Timeline {
repeatCount: 1
keyFrames : [
KeyFrame {
time : 0s
values: [x=>0]
},
KeyFrame {
time: bind dur
values: [x=>100]
}
]
}.play();

De hecho, esta forma de definir un timeline permite anidar timelines o agregar un action: en cada KeyFrame, de manera que una acción sea ejecutada cada vez que una etapa de la animación o transición se completa.


var dur=3s;
var dur2=5s;
var x:Number;
Timeline {
repeatCount: 1
keyFrames : [
KeyFrame {
time : 0s
values: [x=>0]
},
KeyFrame {
time: bind dur
canSkip: true
values: [x=>50]
action: function() {
println("completo etapa 1");
};
},
KeyFrame {
time: bind dur2
canSkip: true
values: [x=>200]
action: function() {
println("completo etapa 2");
};
}
]
}.play();

miércoles, 18 de marzo de 2009

Un "acordeón" de imágenes


Este componente aun no está terminado, pero ya lo pueden probar usando el link de más abajo.

Lanzar demo Java Web Start, CLICK AQUI

Código fuente componente y demo, CLICK AQUI


El código para crear un "Acordeón de imágenes" es el siguiente:

var accordion = ImagesAccordion{
width: 650,
height: 350,
lineWidth: 1.0,
lineColor: Color.WHITE
images: [
ImageItem {
id: "moais",
caption: "Moais"
image: Image { url: "{__DIR__}moais.jpg"
}
message: "Easter Island (Rapa Nui) is a Polynesian island in the "
"southeastern Pacific Ocean, The island is a special "
"territory of Chile. Easter Island is famous for its "
"monumental statues, called moai."
messageArea: Rectangle2D {
minX: 30,
minY: 253,
width: 350,
height: 87
}
call: click
},
ImageItem {
id: "anakena",
caption: "Anakena"
image: Image { url: "{__DIR__}anakena.jpg"
}
message: "‘Anakena is a white coral sand beach in Rapa Nui..."
messageArea: Rectangle2D {
minX: 20,
minY: 233,
width: 360,
height: 107
}
messageFont: Font { size: 12
}
call: click
},
ImageItem {
id: "glacier",
caption: "Grey glacier"
image: Image { url: "{__DIR__}grey.jpg"
}
message: "The Glacier is in the south end..."
messageArea: Rectangle2D {
minX: 30,
minY: 270,
width: 320,
height: 70
}
call: click
},
ImageItem {
id: "torres",
caption: "Torres del Paine"
image: Image { url: "{__DIR__}paine.jpg"
}
message: "Spectacular mountain group in Torres del Paine..."
messageArea: Rectangle2D {
minX: 30,
minY: 270,
width: 320,
height: 70
}
call: click
},
ImageItem {
id: "salar",
caption: "Atacama desert"
image: Image { url: "{__DIR__}salar.jpg"
}
message: "The Atacama Desert is a virtually rainless plateau in Chile..."
messageArea: Rectangle2D {
minX: 20,
minY: 237,
width: 380,
height: 103
}
// messageFont: Font { size: 12 }
call: click
},
/* ImageItem {
id: "crayons",
caption: "Crayones"
message: "Recuerdos de la niñez"
image: Image { url: "{__DIR__}crayons.jpg"}
call: click
},*/
ImageItem {
id: "chaiten",
caption: "Chaiten"
image: Image { url: "{__DIR__}chaiten.jpg"
}
message: "Hell on Earth. Chaitén is a volcanic caldera..."
messageArea: Rectangle2D {
minX: 20,
minY: 270,
width: 420,
height: 70
}
call: click
}
]
effect: Reflection { fraction: 0.1,
}

};

function click(image:ImageItem) {
println(image.id);
}

martes, 17 de marzo de 2009

Un pequeño bug en el Timeline y una solución


Estaba haciendo unas pruebas y de vez en cuando notaba un comportamiento extraño, finalmente descubrí que el problema se origina en la reutilización de un Timeline, que estaba definido como:

var timeline= Timeline {
repeatCount: 1
keyFrames: [
at (0s) { currentX => startX }
at (0.5s) { currentX => posX }
]
};

Aunque no es el ideal que haya bugs, es algo habitual en una plataforma nueva (he leído que Adobe Flex tiene demasiados bugs, así que -aunque es consuelo de tontos- me voy a conformar con este pequeño error en JavaFX).

La solución fue tan simple como... no reutilizar el Timeline una y otra vez, sino que recrearlo cuando lo voy a usar:

var timeline:Timeline;

...

timeline = Timeline {
repeatCount: 1
keyFrames: [
at (0s) { currentX => startX }
at (0.5s) { currentX => posX }
]
};
timeline.playFromStart();

El problema específico de mi programa, era que a veces asignaba currentX igual a 0 en at (0s), aunque startX no tenia ese valor.

En todo caso, no es un problema que ocurra con frecuencia (supongo que debe ser un pequeño error el compilador), así que no es necesario hacer esto cada vez que utilicen un Timeline... pero si notan algo extraño como que un elemento asociado de alguna manera a un timeline salta de manera no esperada, intenten esto (por lo menos hasta que el bug sea corregido).

lunes, 16 de marzo de 2009

for... indexof


Este es un detalle muy menor, pero UTIL... típicamente, cuando uno recorre una lista, crea una variable que sirva de puntero y que se incremente en la medida que pasa los elementos de la lista.


var names=["peter","john","james"];

var i=0;
for (name in names) {
println("{name} {i}");
i++;
}

Con JavaFX script esto no es necesario, sólo basta con un:

var names=["peter","john","james"];

for (name in names) {
println("{name} {indexof name}");
}

¿Comó aplicar más de un efecto a un nodo?


Si por ejemplo, se desea hacer difusa una imagen y al mismo tiempo reducir su brillo.

El "truco" está en que casi todos los efectos tienen un INPUT. Eso permite anidar los efectos.


var img = ImageView {
image: Image { url: "{__DIR__}crayons.jpg"},
effect:
GaussianBlur {
input:
ColorAdjust{
brightness: -0.5
}
}
};