【JavaFX】アニメーション処理の適用

2018年7月18日

JavaFXには既にアニメーションが実装できる機能が用意されています。

今回は、このアニメーション系クラスの利用方法を見ていきたいと思います。

今回のベースプログラムはこちらを利用します。サンプルではViewクラスを修正し、結果を見ていきます。

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Test extends Application{

	public static void main(String[] args) {
		launch(args);
	}

	@Override
	public void start(Stage primaryStage) {
		View v = new View();
		Scene scene = new Scene(v, 400, 300);
		primaryStage.setScene(scene);
		primaryStage.show();
	}
}
class View extends Group{
	public View() {
		//ここにアニメーションやオブジェクトの適用処理を記述
	}
}

基本機能

・setCycleCount(ループ回数)でアニメーションの繰り返し回数を指定できます。

・setAutoReverse(有効かどうか)でアニメーションが終了した後反対の処理を実行するかどうかを設定できます。例えばフェードインアニメーションを設定した場合、終了後にフェードアウトアニメーションが始まります。この反転アニメーションもCycleCount一回分の扱いになるようです。

・playメソッドを呼び出すとアニメーションを開始します。

・pauseメソッドを呼び出すとアニメーションを一時停止します。

・stopメソッドを呼び出すとアニメーションを停止します。

・Durationクラスはアニメーションの実行期間を表すクラスとして利用します。例えば1秒でDurationオブジェクトを作成し、アニメーションクラスに渡した場合はそのアニメーションは1秒で完了するように実行されます。Durationのインスタンス化は通常staticメソッドを使用するほうが良いでしょう。

Duration.millis(ミリ秒)でミリ秒指定のDurationオブジェクトの取得が可能。
Duration.seconds(秒)で秒指定のDurationオブジェクトの取得が可能。
Duration.minutes(分)で分指定のDurationオブジェクトの取得が可能。
Duration.hours(時)で時指定のDurationオブジェクトの取得が可能。

平行移動アニメーション

TranslateTransitionを利用することで平行移動アニメーションを実装できます。内部では単純にx,y座標を加算したりするだけですね。

一応3Dようにz座標の変更処理も入れられるようになっています。

setFromX(開始X座標)
setFromY(開始Y座標)
setFromZ(開始Z座標)
setToX(終了X座標)
setToY(終了Y座標)
setToZ(終了Z座標)

class View extends Group{
	public View() {
		Rectangle rect = new Rectangle(0,0,50,50);
		TranslateTransition animation = new TranslateTransition(Duration.seconds(3), rect);
		animation.setFromY(0);
		animation.setToY(250);
		animation.setFromX(0);
		animation.setToX(350);
		animation.setCycleCount(2);
		animation.setAutoReverse(true);
		animation.play();
		getChildren().add(rect);
	}
}
実行結果

拡大縮小アニメーション

ScaleTransitionを利用することで拡大縮小アニメーションを実装できます。拡大倍率をメソッドの引数に指定します。

setFromX(開始X倍率)
setFromY(開始Y倍率)
setFromZ(開始Z倍率)
setToX(終了X倍率)
setToY(終了Y倍率)
setToZ(終了Z倍率)

サンプルでは縦幅を最大5倍、横幅を最大7倍にしました。

class View extends Group{
	public View() {
		Rectangle rect = new Rectangle(175,125,50,50);
		ScaleTransition animation = new ScaleTransition(Duration.seconds(3), rect);
		animation.setFromY(1);
		animation.setToY(5);
		animation.setFromX(1);
		animation.setToX(7);
		animation.setCycleCount(2);
		animation.setAutoReverse(true);
		animation.play();
		getChildren().add(rect);
	}
}
実行結果

回転アニメーション

RotateTransitionを利用することで回転アニメーションを実装できます。

setFromAngle(開始角度)
setToAngle(終了角度)

で指定しましょう。

class View extends Group{
	public View() {
		Rectangle rect = new Rectangle(175,125,50,50);
		RotateTransition animation = new RotateTransition(Duration.seconds(3), rect);
		animation.setFromAngle(0);
		animation.setToAngle(360);
		animation.setCycleCount(2);
		animation.setAutoReverse(true);
		animation.play();
		getChildren().add(rect);
	}
}
実行結果

パス移動アニメーション

PathTransitionを利用すると作成したパスの通りに移動するアニメーションを実装できます。

setPath(Shapeオブジェクト)でPathオブジェクトを指定してください。

setOrientation(OrientationType.ORTHOGONAL_TO_TANGENT)と指定すると、オブジェクトの回転角度をパスの進行方向に傾けることができます。

引数がShapeオブジェクトであるため、Rectangleクラスなどのオブジェクトも指定できます。

class View extends Group{
	public View() {
		Rectangle rect = new Rectangle(0,0,50,50);
		PathTransition animation = new PathTransition(Duration.seconds(3), null, rect);
 
		Path path = new Path();
 
		MoveTo move1 = new MoveTo();
		move1.setX(50);
		move1.setY(50);
 
		LineTo line1 = new LineTo();
		line1.setX(250);
		line1.setY(50);
 
		QuadCurveTo qc = new QuadCurveTo();
		qc.setControlX(400);
		qc.setControlY(150);
		qc.setX(250);
		qc.setY(250);
 
		LineTo line2 = new LineTo();
		line2.setX(50);
		line2.setY(250);
 
		path.getElements().add(move1);
		path.getElements().add(line1);
		path.getElements().add(qc);
		path.getElements().add(line2);
		path.getElements().add(new ClosePath());
 
		animation.setOrientation(OrientationType.ORTHOGONAL_TO_TANGENT);
		animation.setPath(path);
		animation.setCycleCount(2);
		animation.setAutoReverse(true);
		animation.play();
		getChildren().add(rect);
	}
}
実行結果

フェードアニメーション

FadeTransitionクラスを利用することでNodeオブジェクトのopacity値を変更するアニメーションを実装できます。ゲーム制作で画面遷移するときに暗転アニメーションを挟みたいときに使えそうですね。

class View extends Group{
	public View() {
		Rectangle rect = new Rectangle(0,0,400,300);
		FadeTransition animation = new FadeTransition(Duration.seconds(3), rect);
		animation.setFromValue(0);
		animation.setToValue(1);
		animation.setCycleCount(2);
		animation.setAutoReverse(true);
		animation.play();
		getChildren().add(rect);
	}
}
実行結果

線の色を変更するアニメーション

StrokeTransitionを利用すると線の色を変更できるアニメーションが実装できます。

setFromValue(開始Colorオブジェクト)
setToValue(終了Colorオブジェクト)

と指定します。

class View extends Group{
	public View() {
		Rectangle rect = new Rectangle(175,125,50,50);
		rect.setFill(null);
		StrokeTransition animation = new StrokeTransition(Duration.seconds(3), rect);

		animation.setFromValue(Color.RED);
		animation.setToValue(Color.BLUE);

		animation.setCycleCount(2);
		animation.setAutoReverse(true);
		animation.play();
		getChildren().add(rect);
	}
}
実行結果

塗りつぶし色変更アニメーション

FillTransitionを利用すると塗りつぶしの色を変更できるアニメーションが実装できます。

setFromValue(開始Colorオブジェクト)
setToValue(終了Colorオブジェクト)

と指定します。

class View extends Group{
	public View() {
		Rectangle rect = new Rectangle(175,125,50,50);
		FillTransition animation = new FillTransition(Duration.seconds(3), rect);

		animation.setFromValue(Color.RED);
		animation.setToValue(Color.BLUE);

		animation.setCycleCount(2);
		animation.setAutoReverse(true);
		animation.play();
		getChildren().add(rect);
	}
}
実行結果

汎用アニメーション

Timelineを利用すると汎用的なアニメーション処理を実装できます。その代わり少々手間がかかります。

Timelineの引数KeyFrameはKeyValueとアニメーションの実行間隔を指定します。KeyValueはオブジェクトのどの値を変更するのか、と実行間隔ごとの最終値を指定します。その内容に応じたアニメーションが実行されるわけです。扱う値が数値の場合は自動的に補完アルゴリズムが適用され、アニメーション処理を実行できます。そうでない場合はInterpolatableインターフェースの内容によって補完処理を実行します。値がInterpolatableを実装しない場合は離散補間が利用されます。補間アルゴリズムはInterpolatorクラスを指定して変更することもできます。

かなり粗削りな方法ですが、ここではInterpolatableを実装してメッセージアニメーションを実装できるように定義してみました。オリジナルアニメーション作成の参考になれば良いのですが。

class AnimationString implements WritableValue<AnimationString.Value>{
	private StringProperty prop;
	private Value value;

	public AnimationString(StringProperty prop) {
		this.prop = prop;
		value = new Value(prop.getValue());
	}

	@Override
	public Value getValue() {
		return value;
	}

	@Override
	public void setValue(Value value) {
		prop.setValue(value.text);
		this.value = value;
	}

	static class Value implements Interpolatable<Value>{
		private String text;

		public Value(String text) {
			this.text = text;
		}

		@Override
		public Value interpolate(Value endValue, double t) {
			String s = endValue.text;
			int len = s.length() + 1;
			int result = Math.min(s.length(),(int) (t * len));

			if ( result != text.length() ) {
				return new Value(s.substring(0, result));
			}
			return this;
		}
	}
}

class View extends Group{
	public View() {
		Text text = new Text(50,50,"");

		String str = "あいうえおあいうえおあいうえお\nかきくけこかきくけこかきくけこ";
		AnimationString.Value asv = new AnimationString.Value(str);
		AnimationString as = new AnimationString(text.textProperty());
		KeyValue kv = new KeyValue(as, asv);
		KeyFrame kf = new KeyFrame(Duration.seconds(3), kv);
		Timeline animation = new Timeline(kf);

		animation.setCycleCount(2);
		animation.setAutoReverse(true);
		animation.play();
		getChildren().add(text);
	}
}
実行結果

KeyValueクラスはWritableValueと変更対象の値を引数に受け取るため、オリジナルのWritableValueを作成し、TextノードのtextPropertyをラップできるクラス、AnimationStringを作成しました。値にはStringをラップしたAnimationString.Valueを定義します。そして、補間処理にはInterpolatableを実装しておき、interpolateの引数tを利用し、その割合に応じて文字列を切り出す処理を実装しています。

Textオブジェクトの初期テキスト値は無視されますので設定する必要はありません。

順番にアニメーション処理を実行

SequentialTransitionクラスを使用することで順番にアニメーションを実行することができます。

new SequentialTransition(animationオブジェクト…)

で複数指定しましょう。

class View extends Group{
	public View() {
		Rectangle rect = new Rectangle(0,125,50,50);

		//移動アニメーションと回転アニメーションを定義
		TranslateTransition animation1 = new TranslateTransition(Duration.seconds(2), rect);
		animation1.setFromX(0);
		animation1.setToX(175);
		RotateTransition animation2 = new RotateTransition(Duration.seconds(2), rect);
		animation2.setFromAngle(0);
		animation2.setToAngle(360);

		//順番にアニメーションさせるためのオブジェクト作成
		SequentialTransition animation = new SequentialTransition(animation1, animation2);
		animation.setCycleCount(2);
		animation.setAutoReverse(true);
		animation.play();

		getChildren().add(rect);
	}
}
実行結果

アニメーションの同時実行

ParallelTransitionを利用すると複数のアニメーションを同時に実行できます。

new ParallelTransition(animationオブジェクト…)

で複数指定しましょう。

class View extends Group{
	public View() {
		Rectangle rect = new Rectangle(0,125,50,50);

		//移動アニメーションと回転アニメーションを定義
		TranslateTransition animation1 = new TranslateTransition(Duration.seconds(2), rect);
		animation1.setFromX(0);
		animation1.setToX(175);
		RotateTransition animation2 = new RotateTransition(Duration.seconds(2), rect);
		animation2.setFromAngle(0);
		animation2.setToAngle(360);

		//同時にアニメーションさせるためのオブジェクト作成
		ParallelTransition animation = new ParallelTransition(animation1, animation2);
		animation.setCycleCount(2);
		animation.setAutoReverse(true);
		animation.play();

		getChildren().add(rect);
	}
}
実行結果

アニメーションクラスを利用する場合に気を付けること

アニメーションクラスを利用する場合は下記の記事で紹介したことも考慮して使用したほうがいいです。

JavaJavaFX

Posted by nompor