Mostrando entradas con la etiqueta adobe. Mostrar todas las entradas
Mostrando entradas con la etiqueta adobe. Mostrar todas las entradas

lunes, 16 de febrero de 2009

Como reemplazar y centrar textos incrustados en archivos Adobe Illustrator con JavaFX


Uno de los beneficios de crear gráfica para JavaFX con Adobe Illustrator, es que luego esta puede ser reemplazada sin necesidad de alterar el código. Esto permite cambiar rápidamente la apariencia de una aplicación o dotarla de "pieles" o "skins" (distintas apariencias, a elección del usuario). Estas plantillas, que permiten incluso cambiar la posición de los elementos en la interfaz de usuario, entre otras cosas, pueden contener textos, que son posibles de reemplazar (haciendo su contenido dinámico).

Pero, para hacerlo hay un par de detalles que es necesario conocer.

Primero crearé una plantilla con Adobe Illustrator:



Una vez generado el archivo .FXZ podemos analizar el código.

Sólo me concentraré en la manipulación de textos, ya que en artículos anteriores he mostrado como trabajar con otro tipo de elementos gráficos generados con Adobe Illustrator.

Primero, crearemos una clase que cargue el archivo gráfico (.fxz) y que obtenga de él los nodos con los objetos.


import javafx.scene.Node;
import javafx.fxd.UiStub;
import javafx.scene.text.*;

public class gaugeui extends UiStub {

override public var url = "{__DIR__}gauge.fxz";

public var reflex: Node;
public var needle: Node;
public var decoration: Node;
public var body: Node;

public var dispvalue: Text;
public-read var dispvaluew;
public-read var dispvaluex;

override protected function update() {

reflex = getNode("reflex");
needle = getNode("needle");
decoration = getNode("decoration");
body = getNode("body");

dispvalue = getNode("dispvalue") as Text;
dispvaluew = dispvalue.boundsInLocal.width;
dispvaluex = dispvalue.boundsInLocal.minX;

}
}

Revisemos el código:

override public var url = "{__DIR__}gauge.fxz";

Esa línea indica desde donde debe descargar el archivo con la gráfica: {__DIR__} apunta al mismo directorio que la aplicación;

public var reflex: Node;
public var needle: Node;
public var decoration: Node;
public var body: Node;

Declara algunas variables para contener otros elementos gráficos;

public var dispvalue: Text;
public-read var dispvaluew;
public-read var dispvaluex;

Declara una variable (dispvalue) de tipo TEXTO, para obtener el nodo que contiene el texto que vamos a reemplazar en este ejercicio, y dos variables adicionales asociadas a ese texto: una (dispvaluew) que contendrá el ancho del area reservada originalmente para el texto y otra (dispvaluex) que contendrá la posición horizontal original para el área de texto;

override protected function update() {

// obtiene los nodos graficos
reflex = getNode("reflex");
needle = getNode("needle");
decoration = getNode("decoration");
body = getNode("body");

// obtiene el nodo, pero lo transforma en texto
dispvalue = getNode("dispvalue") as Text;

// obtiene el ancho del texto original
dispvaluew = dispvalue.boundsInLocal.width;
// obtiene la posicion horizontal original del texto
dispvaluex = dispvalue.boundsInLocal.minX;

}


Para rescatar los nodos desde el archivo .fxz, utilizamos los nombres de asignamos a los elementos en el diseño. En nuestro ejemplo, llamamos al elemento de texto que deseamos manipular "jfx:dispvalue" (la identificacion jfx: permite identificar las etiquetas de nodos que importará JavaFX), y por lo tanto, obtenemos ese nodo con un getNode("dispvalue"), e inmediatamente lo convertimos en un Text (as Text).

Ahora bien, uno de los inconvenientes de la modificación de los textos desde un script, es que al modificar el contenido, se modifica el ancho del elemento que contiene el texto, y dependiendo de la alineación también puede modificarse la posición horizontal.

Por eso, al obtener el nodo de texto original, también almaceno la posición (dispvaluex) y el ancho (dispvaluew) que tenía el texto en el diseño. Con esta información más la nueva información de ancho generada al modificar el contenido del texto, puedo calcular la posición centrada del texto.

Para conseguirlo, puedo hacer algo como esto:

// instancia la clase que carga la gráfica (arriba)
var ui = gaugeui{};

// variable (degree) que mostrará en el area de texto
var degree = 0.0 on replace {

// actualiza contenido con numero entero convertido en string
ui.dispvalue.content="{degree as Integer}";

// obtiene nuevo ancho del texto (alterado por nuevo contenido)
var w = ui.dispvalue.boundsInLocal.width;

// calcula coordenada horizontal para mantener el texto
// centrado respecto a su posicion original en el diseño
ui.dispvalue.x = ui.dispvaluex +
ui.dispvaluew / 2 - w / 2;


};


Al modificarse degree, obtiene su valor entero y lo convierte en un string. Esto lo hace al incluir la variable como parte de una cadena de texto entre paréntesis de llave... "{expresión}"

A continuación, obtiene el nuevo ancho del texto modificado, con un: elemento_texto.boundsInLocal.width

Finalmente, obtiene la nueva posición horizontal del texto, usando la posición original del texto en el diseño mas la mitad del ancho del texto original. En este punto sabemos cual era el punto medio del texto original (posición respecto a la cual centraremos el nuevo texto).

A esa posición, restamos la mitad del nuevo ancho del texto.... y como resultado, el texto se mantiene visualmente centrado.



La inconveniente con el uso de TextAlignment.CENTER, es que el texto se centra respecto a las demás líneas de un párrafo (con más de una línea), entonces, si usamos un texto con una sóla línea, TextAligment.CENTER no tiene ningún efecto.

En resumen, hay que recuperar el nodo del texto por su nombre, convertilo y almacenarlo como Text, obtener el ancho y posición original del texto en el diseño... y calcular la posición horizontal del texto al modificar su contenido.

Por cierto, es posible exportar los archivos Illustrator a .fxz sin los fonts, pero si te quieres asegurar que los textos se mantendrán en apariencia, tamaño y posición, es mejor incluirlos. El resultado no es extremadamente grande, un font típico pesa cerca de 50KB.

Ojalá esto sea de utilidad.

miércoles, 28 de enero de 2009

Mi primer juego en JavaFX: Alunizaje


Al juego le falta un par de detalles, como que la nave aparezca inicialmente en cualquier area de la pantalla. Por ahora aparece al centro a una velocidad y dirección aleatoria. También me falta agregar que la "base" de alunizaje tenga una posición aleatoria y que detecte cuando aterriza fuera de ella. Son detalles menores que quizas hasta puedes terminar tú.



El juego usa 4 teclas. La barra de espacio, para encender el motor principal. Las teclas de flecha hacia izquierda y derecha, que encienden los motos auxiliares para inclinar el módulo, y la tecla con la flecha hacia arriba, que enciende el piloto automático, para frenar la rotación del módulo (automáticamente).

Está bastante realista, los retrocohetes se encienden cuando corresponde y dejan de operar cuando no hay mas combustible. También incluye alarmas visuales y sonoras para cuando se excede la velocidad de aterrizaje, la inclinación del módulo es incorrecta cuando esta cerca de alunizar o cuando el combustible baja de 1/3 del estanque.

Me resultó entretenido hacer este juego y también descubrir LO INCREIBLEMENTE SIMPLE que es desarrollar cosas bastante decentes en tan poco tiempo (el grueso estaba operando en un par de horas... ¡y eso que estoy aprendiendo JavaFX script!).

La facilidad de incluir gráficos desde Adobe Illustrator sin duda es una ventaja inmensa. Especialmente, porque puede ser reemplazada por el trabajo de un diseñador más experto, sin necesidad de tocar el código de JavaFX script ya desarrollado. De hecho, con poco trabajo adicional podría agregarse multiples "skins" o apariencias al juego... escenarios de distintos planetas y naves por ejemplo (pudiendo relocalizar las alarmas, botones, formas de la nave, motores, entorno, etc).

El proyecto Netbeans 6.5 completo está disponible aquí (código fuente, gráfica, sonidos, etc).

El código requiere que esté incluida la libreria JavaFX FXD 1.0 en el proyecto.

miércoles, 21 de enero de 2009

JavaFX: Integración con recursos Adobe Illustrator


JavaFX permite integrar fácilmente recursos gráficos en el código, permitiendo dar una apariencia más rica y atractiva a las aplicaciones y juegos desarrollados con JavaFX.



Para traspasar recursos de Adobe Illustrator a JavaFX, tienes que instalar el JavaFX Production Suite.

Una copia completa del proyecto Netbeans -con los recursos Adobe Illustrator- está aquí ... (Download Complete Project)


archivo CDartUI.fx


package animatecd;

import javafx.scene.Node;
import javafx.fxd.UiStub;
import javafx.scene.Group;

public class CDartUI extends UiStub {

override public var url = "{__DIR__}CDart.fxz";
public var Artwork: Node;

override protected function update() {

Artwork=getNode("Artwork");
}

}

Archivo Main.fx

package animatecd;

import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.text.Text;
import javafx.scene.text.Font;
import javafx.scene.Group;
import javafx.animation.Timeline;

// carga imagenes de Illustrator
var ui = CDartUI {};
var scale:Number;

Timeline {
repeatCount: Timeline.INDEFINITE
autoReverse: true
keyFrames: [
at(0s) { scale => 0.1 }
at(10s) { scale => 12.0 }
]
}.play();

Stage {
width: 400
height: 400
scene: Scene {
content: Group {
content:ui
scaleX:bind scale
scaleY:bind scale
translateX:bind scale*80
translateY:bind scale*80
rotate:bind scale*36
}
}
}

{__DIR__} indica que el archivo CDart.fxz está en el mismo directorio que las clases compiladas (basta poner el archivo CDart.fxz en el directorio que contiene el código fuente para que Netbeans lo copie al directorio correspondiente con la copia para distribuir).

Si el archivo de Adobe Illustrator contiene mas de un elemento (layers identificados con la etiqueda "jfx:" y el nombre del elemento), puede acceder a las propiedades usando (en este caso) ui.Artwork.nombre_de_la_propiedad. Esto le permitirá mover los elementos contenido en el archivo Adobe, de manera independiente. Otras propiedades que puede alterar son... cambiar su opacidad (transparencia), rotarlo, escalarlo, etc.