Java/JavaFX/アニメーション

Top > Java > JavaFX > アニメーション

アニメーション

アニメーションというのはもともとは複数の静止画像を時間に沿って切り替えることによって,動きを表現する技術です。
時間の経過と共に複数の描画を切り替えることでアニメーションを実現することができます。
JavaFXの場合,タイムラインはjavafx.animation.Timelineクラスで表します。
特定の時間での状態を表すのがjavafx.animation.KeyFrame?クラスです。

アニメーションの作成

ノードを移動させるアニメーションを作成します。

Node作成

アニメーションを作成する前にノードを作成します。
javafx.scene.image.ImageView?クラスを使用して、イメージを作成します。

   Stage {
       title: "Let is go Seal!"
       scene: Scene {
           width: 550
           height: 150
           content: [
               //イメージ
               ImageView {
                   x: 20
                   y: 50
                   image: Image {
                       url: "{__DIR__}aza.jpg"
                   }
               },
               SwingButton {
                   translateX: 20
                   translateY: 10
                   text: "Start"
                   action: function() {
                   //アニメーションを実行する処理
                      }
               }
           ]
       }
   }
animation_00.JPG

これでNodeが作成できました。次に、アニメーションを加えていきます。
変化させる要素を変数と定義します。
水平方向へ移動させるので変数xを定義します。ノードでは水平方向へ移動量を表す、変数translateXをxにバインドさせます。
次はTimelineクラスとKeyFrame?クラスを使用して、変数xに値を変化させます。
Timelineクラスは、KeyFrame?クラスの配列である、変数keyFramesを持ちます。
keyFramesにKeyFrame?オブジェクトで指定した時間における値を表します。

   // イメージの位置を表す変数
   var x = 0;     
   //イメージ
   ImageView {
       // 移動量を x にバインドする
       translateX: bind x
       x: 20
       y: 50
       image: Image {
           url: "{__DIR__}aza.jpg"
       }
   }

KeyFrame?クラスは経過時間を表す変数timeと,変数timeで表した時間における値を表す変数valuesを持ちます。
変数timeの型は時間間隔を表すDurationです。2つの時間,0秒と4秒での値を表します。
変数valuesでは,=>演算子で値を代入します。
この=>演算子は変数timeに指定した時間までに,指定した値にするという意味を持ちます。
2つめのKeyFrame?オブジェクトでは4秒後までにxを450にするという意味です。

play関数

Timelineオブジェクトは生成しただけではアニメーションは始まりませんのでplay関数を使用します。

  • play関数
    アニメーションの開始
  • stop関数
    アニメーションの停止

ボタンのactionにplay関数を追加します。

   // 車の位置を表す変数
   var x = 0;

   var timeline = Timeline {
       keyFrames: [
           KeyFrame {
               // はじめは 0 の位置
               time: 0s
               values: x => 0
           },
           KeyFrame {
               // 4 秒後に 400 まで進む
               time: 4s
               values: x => 400
           }
       ]
   };
   Stage {
       title: "Let is go Seal!"
       scene: Scene {
           width: 550
           height: 150
           content: [                
              // イメージ
               ImageView {
                   // 移動量を x にバインドする
                   translateX: bind x
                   x: 20
                   y: 50
                   image: Image {
                       url: "{__DIR__}aza.jpg"
                   }
               },
               SwingButton {
                   translateX: 20
                   translateY: 10
                   text: "Start"
                   action: function() {
                   // アニメーションをスタート
                      timeline.play();
                   }
               }
           ]
       }
   }

これでボタンを押すと移動します。

#ref(): File not found: "JavaFXについて/アニメーション/" at page "Java/JavaFX/アニメーション"

stop関数

この場合Timelineクラスは一度playすると4秒後の処理を定義していませんがタイムラインはそのまま動作しています。
再度、アニメーションを実行するには、一度タイムラインを終了させる必要があります。このときに、stop関数を使用します。

   
   action: function() {
      // アニメーションをストップさせてからスタート
       timeline.stop();
      timeline.play();
   }

またはタイムラインをリセットして開始するplayFromStart?関数を使用します。

   action: function() {
       // タイムラインをリセットしてアニメーションをスタート
       timeline.playFromStart();
   }

この処理を行うことで繰り返しアニメーションを行えます。

自然に動かす

移動量を時間で均等に割って,アニメーションさせているので動きが一定のスピードで動きます。
自然に動かしたいときはjavafx.animation.lnterpolatorクラスを使用します。

  • lnterpolatorクラス
    自然に動かすにためのクラスです。2つの動きをします。。
    • イーズアウト、一定のスピードから徐々にゆっくりになる。
    • イーズイン、徐々に速くなり一定のスピードになる。

使用方法

lnterpolatorオブジェクトは、KeyFrame?オブジェクトの変数valuesの設定時に、twen演算子で指定します。

   var timeline = Timeline {
       keyFrames: [
           KeyFrame {
               // はじめは 0 の位置
               time: 0s
               values: x => 0
           },
           KeyFrame {
               // 4 秒後に 400 まで進む
               // イーズイン,イーズアウトを指定
               time: 4s
               values: x => 400 tween Interpolator.EASEBOTH
           }
       ]
   };

Interpolatorクラスには、次の定数を持っています。

  • EASEIN、イーズイン対応。
  • EASEOUT、イーズアウト対応。
  • EASEBOTH、イーズイン、イーズアウト両方に対応。

繰り返し

何度も繰り返しアニメーション実行したいときは、Timelineクラスの変数repeatCountを使用します。
変数repeatCountは、繰り返す回数を設定します。
変数repeatCountの値を、Timeline.INDEFINITEに設定すると無限に繰り返しされます。

   var timeline = Timeline {
       // INDEFINITE にすることで無限に繰り返す
       repeatCount: Timeline.INDEFINITE

       keyFrames: [
           KeyFrame {
               time: 0s
               values: [
                   x => 0
               ]
           },
           KeyFrame {
               time: 4s
               values: [
                   x => 700
               ]
           }
       ]
   };

動き続けている設定なのでイーズイン、イーズアウトを設定していません。

またTimelineクラスの変数autoReverseをtrueにした場合、アニメーイションが反転します。
変数xが0からスタートし4秒後に700の値になったら次は700から4秒かけてxの値が0に変わります。

    var timeline = Timeline {
      // INDEFINITE にすることで無限に繰り返す
       repeatCount: Timeline.INDEFINITE
      //反転
      autoReverse:true
      <<省略>>
   };

一時停止

Timelineクラスのpause関数をコールすると一時停止になります。再開するには、play関数をコールします。

   SwingButton {
       var run = false;
       translateX: 22
       translateY: 10
       text: bind if (run) "Stop" else "Start"
       action: function() {
           if (run) {
               // アニメーション中であれば一時停止
               timeline.pause();
               run = false;
           } else {
               // アニメーションを一時停止していたら,再開
               timeline.play();
               run = true;
           }
       }
   }

ボタン用のフラグ、Blooean型の変数runを用意しました。

  • trueの場合、pause関数コール。
  • falseの場合、play関数コール。

タイムラインで処理を行う

値を変更するのだけでなく、処理を行うときTimelineクラスの変数actionを使用すします。
変数actionに実行したい処理を行う関数を代入します。

   var timeline = Timeline {
       repeatCount: Timeline.INDEFINITE

       keyFrames: [
           KeyFrame {
               // 10ミリ秒ごとにactionをコール
               time: 10ms
               action: function() {
                   // 処理
               }
           }
       ]
   };
   // アニメーションの開始
   timeline.play();

この場合10ミリ秒ごとにaction関数がコールされます。

アニメーション_2

javafx.animation.transitionクラスを使用してアニメーションを作成しましたが、他のクラスを使用してアニメーションを作成できます。
移動のアニメーションはよく使われるアニメーションの1つです。その他にも拡大・縮小と回転がよく使用されています。これら3種類のアニメーションは,簡単に実現できるように専用のクラスが提供されています。

  • TranslateTransition?クラス
    移動
  • ScaleTransition?クラス
    拡大・縮小
  • RotateTransition?クラス
    回転
    これら3つのクラスの使い方は共通しているので,RotateTransition?クラスを紹介します。

移動、拡大縮小、回転

RotateTransition?クラスのスーパークラスのTransitionクラスは変数nodeを持ちこのnodeが回転、移動、拡大縮小の対象になります。

   //Node作成
   var node: Node = Group {};

   var rotateTransition = RotateTransition {
       // 回転の対象ノード
       node: node
       // 0度から1080度回転させる
       fromAngle: 0
       byAngle: 1080
       // これらのアトリビュートは Timeline クラスに準ずる
       duration: 7s
       repeatCount:5
       interpolate: Interpolator.EASEBOTH
       autoReverse: true
   };
   // 回転の開始
   rotateTransition.play();

回転の角度の設定

回転の角度を設定するには次の2つの方法があります。

  • 開始角度と回転角度を指定します。
    • 変数fromAngle
      開始角度
    • 変数byAngle
      回転角度
  • 開始角度と終了角度を指定
    • 変数fromAngle
      開始角度
    • 変数toAngle
      終了角度

回転の中心はノードの中心になります。ノード中心以外の点を回転の中心にしたい場合は、ダミーの透明なノードで中心を調整するか、RotateTransition?クラスを使用しないでTimelineクラスを使用します。
変数durationや変数repeatCountなどはTimelineクラスを使用した時と同じです。
補間方法はKeyFrame?クラスではtween演算子を使用しましたが,ここでは変数interpolateで指定します。
最後にアニメーションを開始させるため,play関数をコールします。
ノードを表示させるには変数contentの配列に変数nodeを入れます。

   Stage {
       title: "Rotate Sample"
       scene: Scene {
           width: 200
           height: 200
           content: [
               node
           ]
       }
   }

下記のコードはアニメーションは、Circlを作成し回転させています。

   var rnd:Random  = new Random();

   var node: Node = Group {
       translateX: 80
       translateY: 80
       // 円
       content: [
           for (i in [0..12]) {
               Circle {
                   opacity:0.7
                   centerX: 20.0 * rnd.nextInt(8);
                   centerY: 20.0 * rnd.nextInt(8);
                   radius: 20
                   fill: Color.RED
                   stroke: Color.BLACK
               }
           }
       ]
   };

   var rotateTransition = RotateTransition {
       // 回転の対象ノード
       node: node
       // 0度から1080度回転させる
       fromAngle: 0
       byAngle:1080
       //時間設定
       duration: 7s
       //リピート回数
       repeatCount:5
       interpolate: Interpolator.EASEBOTH
       //反転
       autoReverse: true
   };
   // 回転の開始
   rotateTransition.play();

   Stage {    
       title: "Rotate Sample"
       scene: Scene {
           width: 300
           height: 300
           content: [
               node
           ]
       }
   }
  • Randomクラスを使用して円の座標を指定してます。実行するたびに座標が変わります。
  • 不透明度を0.7に設定しています。
  • 0から1080度回転しています。
  • アニメーション時間は時間は7秒です。
  • リピート回数は5を設定してます。
  • 反転を設定しています。
    animation_01.JPG

Fade Transition

FadeTransition?クラスを使用することでフェードアウト、フェードインが表現できます。

  • FadeTransition?クラス
    • 変数fromValue
      始まりの不透明度
    • 変数toValue
      終りの不透明度

値が0で透明,1で不透明です。変数fromValueの方が値が小さい場合はフェードインになり,大きい場合はフェードアウトになります。
FadeTransition?クラスもRotateTransition?クラスと同じように変数nodeがフェードイン,フェードアウトの対象となります。

   var fadeTransition = FadeTransition {
       // 対象となるノード
       node: node
       // 不透明度を 0.0 から 1.0 まで変化させる
       fromValue: 0.2
       toValue: 1.0
       duration: 1.0s
       repeatCount: Timeline.INDEFINITE
       autoReverse: true
   };
   fadeTransition.play();

下記のコードは円の図形をフェードイン、フェードアウトを繰り返しているコードです。

   var rnd:Random  = new Random();

   var node: Node = Group {
       translateX: 60
       translateY: 60
       // 円
       content: [
           for (i in [0..10]) {
               Circle {
                   centerX: 10.0 * rnd.nextInt(10);
                   centerY: 10.0 * rnd.nextInt(10);
                   radius: 20
                   fill: Color.RED
                   stroke: Color.BLACK
               }
           }
       ]
   };

   var fadeTransition = FadeTransition {
       // 対象となるノード
       node: node
       // 不透明度を 0.0 から 1.0 まで変化させる
       fromValue: 0.2
       toValue: 1.0
       duration: 1.0s
       repeatCount: Timeline.INDEFINITE
       autoReverse: true
   };
   fadeTransition.play();

   Stage {
       title: "FadeTransition"
       scene: Scene {
           width: 200
           height: 200
           fill:Color.BLACK
           content: [node]
       }
   }
fade_00.JPG

↑フェードイン、フェードアウトを繰り返しています。

Path Transition

曲がった軌跡をたどって移動するアニメーションを作成ができます。
アニメーションのガイドとなるパスは、javafx.animation.transition.AnimationPath?クラスで表します。しかし,nimationPathクラスのオブジェクトを直接生成することはできません。AnimationPath?オブジェクトを生成するにはcreateFromPath?関数を使用します。引数の型はPathクラスです。

   // パスに沿って移動するノード
   var node: Node = {} 
   // ガイドとなるパス
   var path = Path {} 
   var pathTransition = PathTransition {
       node: node 
       path: AnimationPath.createFromPath(path)
   }
   // アニメーションの開始
   pathTransition.play();

ここでは円の集団をpath沿って移動させてます。
ガイドとなるパスはらせんにしました。一様らせんはx=αθsinθ, y=αθcosθで表すことができます。下記に螺旋を作成してい部分を記述します。角度を15度で分割し,その間の弧を直線で近似させてます。

   // node パス
   var path = Path {
       elements: [
           MoveTo { x: 100 y: 100 },
           for (i in [0.0..1800.0 step 10.0]) {
               //ラジアンに変換
               var rad = i * radian;
               LineTo {
                   x: 2.0 * rad * Math.sin(rad) + 100
                   y: 2.0 * rad * Math.cos(rad) + 100
               }
           }
       ]
   }

ノードを表示するStageオブジェクト作成します。

   Stage {
       title: "PathTransition"
       scene: Scene {
           width: 200
           height: 200
           content: node
       }
   }

アニメーションを行う。

   //ラジアンへの変換係数
   var radian = Math.PI/180.0;
   var rnd:Random  = new Random();
   //円
   var node: Node = Group {
       content: [ for (i in [0..10]) {
                Circle {
                   centerX: 5.0 * rnd.nextInt(5);
                   centerY: 5.0 * rnd.nextInt(5);
                   radius: 5
                   fill: Color.RED
                   stroke: Color.BLACK
               }
           }
       ]
   }
   // node パス
   var path = Path {
       elements: [
           MoveTo { x: 100 y: 100 },
           for (i in [0.0..1800.0 step 10.0]) {
               //ラジアンに変換
               var rad = i * radian;
               LineTo {
                   x: 2.0 * rad * Math.sin(rad) + 100
                   y: 2.0 * rad * Math.cos(rad) + 100
               }
           }
       ]
   }

   Stage {
       title: "PathTransition"
       scene: Scene {
           width: 200
           height: 200
           content: node
       }
   }

   var pathTransition = PathTransition {
       //移動するノード
       node: node
       // パスから AnimationPath オブジェクトを作成
       path: AnimationPath.createFromPath(path)
       // パスに沿って回転
       orientation: OrientationType.ORTHOGONAL_TO_TANGENT
       duration: 10s
       repeatCount:5
       autoReverse: true
   }
   pathTransition.play();

変数orientationはノードがパスに沿って移動する時に,パスの傾きに応じて回転するかどうかを示します。
デフォルトでは回転を行わないOrientationType?.NONEとなっています。
パスに沿って回転させる場合は,OrientationType?.ORTHOGONAL_TO_TANGENTを指定します。
これを実行するとランダムに作成された複数の小さな円が回転しながら外側に向かっていきます。

#ref(): File not found: "path.JPG" at page "JavaFXについて/アニメーション"

複数のアニメーション

複数のアニメーションを扱うためには次のクラスを使用する。、

  • SequentialTransition?クラス
    複数のクラスを順々に実行。
  • ParallelTransition?クラス、
    複数のアニメーションを同時に実行。

Sequential Transition

SequentialTransition?クラスは、変数contentを持ちます。変数contentはTransitionの配列で、順番に実行するアニメーションを記述します。SequentialTransition?オブジェクトのplay関数で最初のアニメーション実行→終了→次のアニメーションの実行→終了の順番で実行されます。

   var seqTransition = SequentialTransition {
       // アニメーションの対象となるノード
       node: node    
       // シーケンシャルに実行するアニメーション
       content: [
           TranslateTransition {},
           RotateTransition {},
           ScaleTransition {}
       ]
   }
   seqTransition.play();

この場合だと、移動、回転、拡大の順番で実行されます。
SequentailTransition?クラスの変数nodeが,変数contentに指定されたアニメーションの対象になります。
変数contentの要素となる個々のアニメーションで変数nodeを指定していた場合,個々のアニメーションのnodeが優先されます。

  • PauseTransition?クラス
    特別なアニメーションとして,指定した時間なにも行わないPauseTransition?クラスがあります。順番にアニメーションを実行しているとき、途中に休止時間を必要な時に使用できます。
    下記のコードはイメージを移動し角に来ると回転するようにしてあります。
   var image: Node = {
       ImageView {
           image: Image {
               url: "{__DIR__}aza.jpg"
           }
       }
   };

   Stage {
       title: "sequentialTransition"
       scene: Scene {
           width: 300
           height: 300
           fill: Color.BLACK
           content: [
               image
           ]
       }
   }

   var sequentialTransition = SequentialTransition {
       // 対象となるノード
       node: image
       // 実行されるアニメーション
       content: [
           //移動
           TranslateTransition {
               duration: 4s
               fromX: 20
               fromY: 20
               toX: 180
               toY: 180
           },
           //ポーズ
           PauseTransition {
               duration: 1s
           },
           //回転
           RotateTransition {
               duration: 1s
               fromAngle: 0
               byAngle: 360
           },
           //移動
           TranslateTransition {
               duration: 2s
               fromX: 180
               fromY: 180
               toX: 20
               toY: 180
           },
           //ポーズ
           PauseTransition {
               duration: 1s
           },
           //回転
           RotateTransition {
               duration: 1s
               fromAngle: 0
               byAngle: 720
           },
           //移動
           TranslateTransition {
               duration: 1s
               fromX: 20
               fromY: 180
               toX: 180
               toY: 20
           },
           //ポーズ
           PauseTransition {
               duration: 1s
           },
           //回転
           RotateTransition {
               duration: 1s
               fromAngle: 0
               byAngle: 360
           },
           //移動
           TranslateTransition {
               duration: 2s
               fromX: 180
               fromY: 20
               toX: 20
               toY: 20
           },
           //ポーズ
           PauseTransition {
               duration: 1s
           },
           //回転
           RotateTransition {
               duration: 1s
               fromAngle: 0
               byAngle: 1080
           }
       ]
   };
   Timeline {
       repeatCount: Timeline.INDEFINITE
       keyFrames : [
           KeyFrame {
               time : 0s
               action : function() {
                   sequentialTransition.playFromStart();
               }
           },
           KeyFrame {
               time : 18s
           }
       ]
   }.play();

イメージを移動,休止,回転させることを繰り返しています。
SequentialTransition?クラスの変数duration,repeatCountおよびautoReverseは使用できないので繰り返し実行したいときは、Timelineオブジェクトを作成し,KeyFrame?オブジェクトの変数actionの中でSequentialTransition?オブジェクトのplayFromStart?関数を繰り返しコールするようにします。

sequentialTransition.JPG

Parallel Transition

SequentialTransition?を使用してアニメーションを順番に複数のアニメーションを同時に行いましたが、同時にアニメーションを実行するには、ParallelTransition?クラスを使用します。
変数content[]に記述した、アニメーションが同時に実行されます。

   var image: Node = {
       ImageView {
           image: Image {
               url: "{__DIR__}aza.jpg"
           }
       }
   };       
   var parTransition = ParallelTransition {
       node: image
       content: [
        //移動
           TranslateTransition {
               duration: 10s
               fromX: 20
               fromY: 20
               toX: 180
               toY: 150
               autoReverse: true
               interpolate: Interpolator.EASEBOTH
           },
           // 回転
           RotateTransition {
               fromAngle: 0
               byAngle: 1800
               duration: 10s
               repeatCount: 2
               autoReverse: true
               interpolate: Interpolator.EASEBOTH
           },
           // 拡大
           ScaleTransition {
               byX: 1.5
               byY: 1.5
               duration: 10s
               repeatCount: 2
               autoReverse: true
               interpolate: Interpolator.EASEBOTH
           }
       ]
   };
   parTransition.play();
   Stage {
       title: "ParallelTransition"
       scene: Scene {
           width: 400
           height:300
           fill: Color.BLACK
           content: [
               image
           ]
       }
   }

移動しながら回転、拡大をしています。autoReverseを設定しているので、反転します。移動、回転、拡大が同時に実行しているのが確認できます。

ParallelTransition.JPG

ParallelTransition?クラスもSequentialTransition?クラスと同様変数duration,変数autoReverse,変数repeatCountは使用することができません。しかし,同時に実行するアニメーションの時間がすべて同じであれば,個々のアニメーションの変数autoReverseをtrueにすることでアニメーションを反転させるように見せることができます。

モーフィング

モーフィングとは2つの形状を自然に変形させことです。
モーフィングを使用するには、javafx.scene.shape.DelegateShape?クラスを使用します。DelegateShape?クラスは単独で使用するのではなく,Timelineクラスと共に使うことでモーフィングを行います。

   //四角形
   var rectangle = Rectangle {
       x: 0 y: 0 width: 100 height: 50
   };
   //テキスト
   var text = Text {
       font : Font {size: 24}
       x: 0, y: 0
       content: "delegateShape"
   };
   //シェイプ
   var shape: Shape = rectangle;
   //カラー
   var color: Color = Color.RED;
   Stage {
       title: "delegateShape"
       scene: Scene {
           width: 200 height: 100
           content: DelegateShape {
               // モーフィングする対象
               shape: bind shape
               translateX: 30 translateY: 30
               fill: bind color
               onMouseClicked: function( e: MouseEvent ):Void {
                   timelLine.playFromStart();
               }
           }
       }
   }
   //アニメーション
   var timelLine = Timeline {
       autoReverse:true
       keyFrames: [
           KeyFrame {
               time: 0s values: [
                   shape => rectangle,
                   color => Color.RED
               ]            
           },
           KeyFrame {
               time: 5s values:[
                   shape => text,
                   color => Color.BLUE
               ]
           }
       ]
   };
   //timelLine.play();

DelegateShape?クラスは変数shapeを持ち,ここに変形させるシェイプを指定します。

  • DelegateShape?クラスを使う時の注意点
    変形させるシェイプオブジェクトでは変数translateXや変数transformなどの移動,回転,拡大・縮小はすべて無視されるということがあります。そのため,(0, 0)を中心にシェイプを定義するようにするようにいてくださ。また,シェイプオブジェクトでは色も無視されます。これらの変数はDelegateShape?オブジェクトで指定された値が適用されます。
    このコードを実行すると、四角形から色を変えながら文字列にモーフィングしています。
    DelegateShape.JPG

アクセス総数7056件

最終更新日: 2009-09-03 (木) 22:46:12 (2791d)

このページをブックマーク:

このページのURL(コピペして利用下さい):

TOP