domingo, 25 de marzo de 2012

JavaFX 2.0. Vamos a crear una historia. Parte II

Ahora vamos con las implementaciones. Por ahora voy a incluir las implementaciones de actor y de la cabeza. No hay cuerpo pero ya se puede hablar y mover la cabeza.












- ActorImpl:


package es.historia.mueve.impl;

import es.historia.IActor;
import es.historia.ICabeza;
import es.historia.ICuerpo;
import javafx.scene.Group;

import javafx.scene.media.MediaPlayer;
import javafx.scene.media.Media;
import javafx.util.Duration;



/**
*
* @author Propietario
*/
public class ActorImpl implements IActor {
private ICabeza cabeza;
private ICuerpo cuerpo;
@Override
public Group dibujar() {
Group salida =new Group();
if (cabeza != null){
salida.getChildren().add(cabeza.dibujar());
cabeza.empezarMovimientoFijo();
}
if (cuerpo != null)
salida.getChildren().add(cuerpo.dibujar());
return salida;
}

@Override
public void mover() {
if (cabeza!= null)
cabeza.mover();
}

@Override
public void definir(ICabeza cabeza, ICuerpo cuerpo) {
this.cabeza = cabeza;
this.cuerpo= cuerpo;
}

@Override
public void hablar(String frase , final ICabeza cabeza) {
final MediaPlayer player = new MediaPlayer(new Media( frase));
player.play();
cabeza.empiezaHablar();
player.seek(Duration.ZERO);
player.setOnEndOfMedia(new Runnable() {

@Override
public void run() {
cabeza.terminaHablar();
}
});
}

@Override
public void establecerPosicion(int i, int i0) {
throw new UnsupportedOperationException("Not supported yet.");
}

Es esta clase podemos ver la funcionalidad de reproducir audio. Lo mas destacable del objeto MediaPlayer es que nos permite lanzar un hilo con una funcionalidad al "suceder" uno de los siguientes eventos:












- CabezaImpl:

package es.historia.parte.impl;

import es.historia.HistoriaExcepcion;
import es.historia.ICabeza;
import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.scene.Group;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.transform.Affine;
import javafx.util.Duration;

/**
*
* @author Propietario
*/
public class CabezaImpl implements ICabeza{
private Timeline timelineTodo;
private Timeline timelineBoca;
private ImageView visorParteSuperior;
private ImageView visorParteInferior;

@Override
public void establecerCara(String caraInferior, String caraSuperior) throws HistoriaExcepcion {
Image imagen1 = new Image(caraSuperior);
if (imagen1 == null || imagen1.isError())
throw new HistoriaExcepcion("La imagen " + caraSuperior + " no es accesible");
Image imagen2 = new Image(caraInferior);
if (imagen2 == null || imagen2.isError())
throw new HistoriaExcepcion("La imagen " + caraInferior + " no es accesible");
visorParteSuperior= new ImageView (imagen1);
visorParteInferior= new ImageView (imagen2);
}

@Override
public Group dibujar() {
Group salida =new Group();
salida.getChildren().add(visorParteSuperior);
salida.getChildren().add(visorParteInferior);
return salida;
}

@Override
public void mover() {
}

@Override
public void establecerPosicion(int x, int y) {
visorParteInferior.setLayoutX(x);
visorParteInferior.setLayoutY(y + visorParteSuperior.getImage().getHeight());
visorParteSuperior.setLayoutX(x);
visorParteSuperior.setLayoutY(y);
}

@Override
public void empezarMovimientoFijo() {
timelineTodo = new Timeline();
timelineTodo.setCycleCount(Timeline.INDEFINITE);
timelineTodo.setAutoReverse(true);
final Affine reflectTransform = new Affine();
//
visorParteSuperior.getTransforms().add(reflectTransform);
visorParteInferior.getTransforms().add(reflectTransform);
timelineTodo.getKeyFrames().addAll(new KeyFrame(Duration.ZERO,
new KeyValue(reflectTransform.mxxProperty(), -1, Interpolator.DISCRETE),
new KeyValue(reflectTransform.txProperty(), visorParteSuperior.getBoundsInLocal().getWidth(),
Interpolator.DISCRETE)
),
new KeyFrame(new Duration(2000L),
new KeyValue(reflectTransform.mxxProperty(), 1, Interpolator.DISCRETE),
new KeyValue(reflectTransform.txProperty(), 0, Interpolator.DISCRETE)),
new KeyFrame(new Duration(4000L),
new KeyValue(reflectTransform.mxxProperty(), -1, Interpolator.DISCRETE),
new KeyValue(reflectTransform.txProperty(), visorParteSuperior.getBoundsInLocal().getWidth(),
Interpolator.DISCRETE)
));
timelineTodo.play();
}

@Override
public void empiezaHablar() {
timelineBoca = new Timeline();
timelineBoca.setCycleCount(Timeline.INDEFINITE);
timelineBoca.setAutoReverse(true);
timelineBoca.getKeyFrames().addAll(new KeyFrame(Duration.ZERO,
new KeyValue(visorParteInferior.rotateProperty(), 40, Interpolator.DISCRETE),
new KeyValue(visorParteInferior.translateYProperty(), 30, Interpolator.DISCRETE)),
new KeyFrame(new Duration(100L),
new KeyValue(visorParteInferior.rotateProperty(), 0, Interpolator.DISCRETE),
new KeyValue(visorParteInferior.translateYProperty(), 0, Interpolator.DISCRETE)),
new KeyFrame(new Duration(200L),
new KeyValue(visorParteInferior.rotateProperty(), -40, Interpolator.DISCRETE),
new KeyValue(visorParteInferior.translateYProperty(), 30, Interpolator.DISCRETE)),
new KeyFrame(new Duration(300L),
new KeyValue(visorParteInferior.rotateProperty(), 0, Interpolator.DISCRETE),
new KeyValue(visorParteInferior.translateYProperty(), 0, Interpolator.DISCRETE)));

timelineBoca.play();
}

@Override
public void terminaHablar() {
timelineBoca.stop();
visorParteInferior.setRotate(0);
visorParteInferior.setTranslateY(0);
}

}

Lo mas destable es:

  • Se utilizan dos linas de tiempo. Una que no para nunca que cambia la orientacion de la cabeza y otra que solo funciona cuando se esta hablando y mueve la boca.
  • Las transformaciones. Siempre que se pueda se debe utilizar una propiedad (como setRotate) pero su la transformacion que se desea no se puede conseguir con una funcion que ofrece la clase entonces se puede usar transformaciones en forma de matriz(Affine).

No hay comentarios: