JavaFXでアニメーション AnimationTimerとTimelineの違い
JavaFXを使ってアニメーションを表示する方法について説明しています。
二つの方法で立方体を回転させるアニメーションを作りました。
AnimationTimerを用いる
AnimationTimerを使って割り込みを行い、この中で動かします。
アニメーションタイマーは60FPSで割り込みをかけます。逆に言うと1秒間に60回です。
サンプルプログラムでは、1秒間経つごとに立方体の角度を変えています。
handleメソッドで現在の時刻がナノミリ秒単位で得られるので、これを使って経過時間を調べています。
サンプルプログラム
package x_test.fx;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.geometry.*;
import javafx.scene.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Box;
import javafx.scene.transform.*;
import javafx.stage.Stage;
/**単純なJavaFX楽天 プログラム
*アニメーション
* */
public class BoxAnimation extends Application {
Rotate boxrotateX = null;
Rotate boxrotateY = null;
public static void main(String[] args) {
Application.launch(args);
}
@Override
public void start(Stage stage) throws Exception {
Scene scene = make3dScene();
stage.setScene(scene);
//タイトルの表示
stage.setTitle("AnimationTimer");
stage.show();
//アニメーションを始める
new Animation().start();
}
private Scene make3dScene(){
Group group = new Group();
//箱を置く
Box box = new Box( 10 , 10 , 10 );
boxrotateX = new Rotate( 0 , new Point3D( 1 , 0 , 0 ) );
boxrotateY = new Rotate( 0 , new Point3D( 0 , 1 , 0 ) );
box.getTransforms().add( boxrotateX );
box.getTransforms().add( boxrotateY );
group.getChildren().add( box );
// カメラを置く
PerspectiveCamera camera = new PerspectiveCamera( true );
//方向と位置
Translate cameratranslate = new Translate(0,0,-50);
camera.getTransforms().add( cameratranslate );
//視界の角度
camera.setFieldOfView( 30. );
group.getChildren().add( camera );
//点光源を置く
LightBase light = new PointLight();
light.setTranslateX( 30.0 );
light.setTranslateY( -30.0 );
light.setTranslateZ( -30.0 );
group.getChildren().add( light );
//Sceneの設定
Scene s3d = new Scene(group, 640, 480);
s3d.setFill(Color.ALICEBLUE);
s3d.setCamera( camera );
return s3d;
}
private class Animation extends AnimationTimer {
long stime = 0;
long foreno = -1;
int i=-1;
@Override
public void handle(long now) {
//nowはナノ秒単位
if( stime == 0 ){ stime = now; }
i++;
//所定時間経過の確認
Long no = (Long)( ( now - stime )/1000000000 );
if( foreno != no ){ foreno = no; } else { return; }
System.out.println(no+" 秒経過 " + i +" 回/秒" );
i=0;
//更新作業
boxrotateX.setAngle( no );
boxrotateY.setAngle( no );
}
}
}
Timelineを用いる
Timelineを使うと割り込み間隔は1msごとに設定できます、最小で1秒間に1000回割り込むことが可能です。
間隔は初期化時に決めます。
Timeline timer = new Timeline(new KeyFrame(Duration.millis(1), new EventHandler
アニメーションの場合は60FPSでも十分ですが、割り込みでたくさんの計算をしたい場合はこちらを使うほうが良いでしょう。
計算が長くて終わらない場合は、タイマーを一旦止めてから計算して終わった後に再始動します。
これをしないと計算中に次の割り込みがかかってしまいます。
しかし一旦止めてから再開するとこれにも時間がかかるので、悩ましいところです。
それでも時間の掛かる計算をする場合は、一旦止めてから重い計算を実行して再開した方がAnimationTimerを用いるよりも早くなります。
こちらのサンプルプログラムも1秒経つことに立方体の角度を変えています。
動作は同じですが、AnimationTimerは60回ほどの割り込み、タイムラインは1000回の割り込みを行っています。
サンプルプログラム
package x_test.fx;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.*;
import javafx.scene.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Box;
import javafx.scene.transform.*;
import javafx.stage.Stage;
import javafx.util.Duration;
/**単純な
Java
楽天 FXプログラム
*アニメーション
* */
public class BoxTimeLine extends Application {
Rotate boxrotateX = null;
Rotate boxrotateY = null;
public Timeline timer=null;
public static void main(String[] args) {
Application.launch(args);
}
@Override
public void start(Stage stage) throws Exception {
Scene scene = make3dScene();
stage.setScene(scene);
//タイトルの表示
stage.setTitle("AnimationTimer");
stage.show();
//アニメーションを始める
this.setTimer();
}
private Scene make3dScene(){
Group group = new Group();
//箱を置く
Box box = new Box( 10 , 10 , 10 );
boxrotateX = new Rotate( 0 , new Point3D( 1 , 0 , 0 ) );
boxrotateY = new Rotate( 0 , new Point3D( 0 , 1 , 0 ) );
box.getTransforms().add( boxrotateX );
box.getTransforms().add( boxrotateY );
group.getChildren().add( box );
//
カメラ
楽天 を置く
PerspectiveCamera camera = new PerspectiveCamera( true );
//方向と位置
Translate cameratranslate = new Translate(0,0,-50);
camera.getTransforms().add( cameratranslate );
//視界の角度
camera.setFieldOfView( 30. );
group.getChildren().add( camera );
//点光源を置く
LightBase light = new PointLight();
light.setTranslateX( 30.0 );
light.setTranslateY( -30.0 );
light.setTranslateZ( -30.0 );
group.getChildren().add( light );
//Sceneの設定
Scene s3d = new Scene(group, 320, 240);
s3d.setFill(Color.ALICEBLUE);
s3d.setCamera( camera );
return s3d;
}
long foreno = -1;
long i=-1;
private void setTimer() {
//タイマーをセットする
timer = new Timeline(new KeyFrame(Duration.millis(1), new EventHandler<ActionEvent>(){
@Override
public void handle( ActionEvent event ){
//timer.pause();
i++;
//所定時間経過の確認
Long no = (Long)( i/1000 );
//System.out.println( i +" 回/秒" );
if( foreno != no ){ foreno = no; } else { /*timer.play();*/return; }
System.out.println( no+" 秒経過 " );
//i=0;
//更新作業
boxrotateX.setAngle( no*2 );
boxrotateY.setAngle( no*2 );
//timer.play();
return;
}
}));
timer.setCycleCount(Timeline.INDEFINITE);
timer.play();
return;
}
最終更新日: 2020-03-16 14:34:57