今まで使用してきたアニメーションは基本的には動きがほとんどありませんでした。しかし、
たとえば、
もちろん、
そこで、
アニメーションの基礎
アニメーションというのはもともとは複数の静止画像を時間に沿って切り替えることによって、
つまり、
![図1 Adobe Flash Professionalの編集画面 図1 Adobe Flash Professionalの編集画面](/assets/images/dev/serial/01/javafx/0008/01.jpg)
1秒間のアニメーションを作成するには、
図2はFlashで作成した2秒のアニメーションをループさせています。2秒ですから24枚の描画が必要です。しかし、
実際にFlashが補間した描画を図3に示します。緑線で表されているのがFlashが補間した部分です。このように単純なアニメーションであれば、
![図3 Flashによるアニメーションの補間 図3 Flashによるアニメーションの補間](/assets/images/dev/serial/01/javafx/0008/03.jpg)
JavaFX Scriptの場合、
では、
簡単なアニメーションの作成
一番はじめのサンプルとして、
まず、
はじめにアニメーションのことを考えずにノードを表示するスクリプトを作成します。ここでは、
リスト1に、
Stage {
title: "Simple Animation Sample"
scene: Scene {
width: 600
height: 100
content: [
// 車のイメージ
ImageView {
x: 20
y: 45
image: Image {
url: "{__DIR__}car.png"
}
},
SwingButton {
translateX: 270
translateY: 10
text: "Start"
action: function() {
// ボタンが押されたら
// アニメーションをスタートさせる予定
}
}
]
}
}
車のイメージはソースと同じディレクトリに配置しました。この状態で実行したのが図4です。
![図4 simpleAnimation1.fxの実行結果 図4 simpleAnimation1.fxの実行結果](/assets/images/dev/serial/01/javafx/0008/thumb/TH800_04.jpg)
では、
// 車の位置を表す変数
var x = 0;
<<省略>>
// 車のイメージ
ImageView {
// 移動量を x にバインドする
translateX: bind x
x: 20
y: 45
image: Image {
url: "{__DIR__}car.png"
}
},
<<以下、省略>>
後は、
var timeline = Timeline {
keyFrames: [
KeyFrame {
// はじめは 0 の位置
time: 0s
values: x => 0
},
KeyFrame {
// 2 秒後に 450 まで進む
time: 2s
values: x => 450
}
]
};
KeyFrameクラスは経過時間を表すtimeアトリビュートと、
valuesアトリビュートでは、
valuesアトリビュートはアトリビュート名が複数形になっていることから分るように、
Timelineオブジェクトは生成しただけではアニメーションは始まりません。play関数がアニメーションの開始、
SwingButton {
translateX: 270
translateY: 10
text: "Start"
action: function() {
// ボタンが押されたら
// アニメーションをスタート
timeline.play();
}
}
これで完成です。ボタンを押したら、
実際に実行してみると、
この結果だけだと、
SwingButton {
translateX: 270
translateY: 10
text: "Start"
action: function() {
// ボタンが押されたら
// アニメーションをストップさせてからスタート
timeline.stop();
timeline.play();
}
}
もしくは、
SwingButton {
translateX: 270
translateY: 10
text: "Start"
action: function() {
// ボタンが押されたら
// アニメーションをスタート
timeline.playFromStart();
}
}
これで、
自然に動かす
simpleAnimation1.
simpleAnimation1.
![図5 線形補間 図5 線形補間](/assets/images/dev/serial/01/javafx/0008/thumb/TH800_05.jpg)
しかし、
ある程度の速度が出た後、
これを図5と同じようにグラフで表したのが図6です。図6のように、
![図6 イーズイン 図6 イーズイン](/assets/images/dev/serial/01/javafx/0008/thumb/TH800_06.jpg)
次に減速を考えてみましょう。先ほどの例であれば、
この場合も、
グラフで表すと図7のようになります。このような変化をイーズアウトといいます。
![図7 イーズアウト 図7 イーズアウト](/assets/images/dev/serial/01/javafx/0008/thumb/TH800_07.jpg)
アニメーションを行う場合でも、
実をいうと、
それでは、
var timeline = Timeline {
keyFrames: [
KeyFrame {
// はじめは 0 の位置
time: 0s
values: x => 0
},
KeyFrame {
// 2 秒後に 450 まで進む
// イーズイン、イーズアウトを指定
time: 2s
values: x => 450 tween Interpolator.EASEBOTH
}
]
};
Interpolatorクラスには定数としてEASEIN、
定数ではなく、
たとえば、
![図8 ベジェ曲線による補間 図8 ベジェ曲線による補間](/assets/images/dev/serial/01/javafx/0008/thumb/TH800_08.jpg)
SPLINE関数の引数は制御点の座標です。引数の順番は最初の制御点のx座標、
var timeline = Timeline {
keyFrames: [
KeyFrame {
// はじめは 0 の位置
time: 0s
values: x => 0
},
KeyFrame {
// 2 秒後に 450 まで進む
// イーズイン、イーズアウトを指定
time: 2s
values: x => 450 tween Interpolator.SPLINE(0.5, 0.1, 0.5, 0.9)
}
]
};
これで自然な動きに見えるはずです。図9はアプレットページへのリンクになっています。ぜひ、
繰り返し、そして一時停止
simpleAnimation1.
では、
var timeline = Timeline {
// INDEFINITE にすることで無限に繰り返す
repeatCount: Timeline.INDEFINITE
keyFrames: [
KeyFrame {
time: 0s
values: [
x => 0
]
},
KeyFrame {
time: 2s
values: [
x => 710
]
}
]
};
左側から車が表れるようにするため、
ここでは使用しませんでしたが、
次に行うのが、
ここでは、
SwingButton {
var running = false;
translateX: 270
translateY: 10
text: bind if (running) "Stop" else "Start"
action: function() {
if (running) {
// アニメーション中であれば一時停止
timeline.pause();
running = false;
} else {
// アニメーションを一時停止していたら、再開
timeline.play();
running = true;
}
}
}
ボタンをトグルにするため、
では、
タイムラインで処理を行う
今までのサンプルでは単純に値を変えるだけのアニメーションでした。しかし、
そのような場合、
var timeline = Timeline {
repeatCount: Timeline.INDEFINITE
keyFrames: [
KeyFrame {
// 50ミリ秒ごとにactionをコール
time: 50ms
action: function() {
// 処理
}
}
]
};
// アニメーションの開始
timeline.play();
では、
マウスポインタを追いかけているように見せるには、
マウスポインタの位置はx座標、
// マウスポインタの位置を保持するシーケンス
var previousX: Number[] = [-10000, -10000, -10000, -10000, -10000];
var previousY: Number[] = [-10000, -10000, -10000, -10000, -10000];
// マウスポインタを追いかけるイメージ群
var images: ImageView[] = for (i in [4..0 step -1]) {
println("I {i}");
ImageView {
x: bind previousX[i]
y: bind previousY[i]
image: Image {
url: "{__DIR__}duke{i}.gif"
}
}
};
previousXとpreviousYの各要素に-10000を代入しているのは、
次に、
var stage = Stage {
title: "Animated Cursor Sample"
scene: Scene {
width: 300
height: 300
content: [
Rectangle {
// カーソルを表示しない
// カーソルの代わりにイメージを使用
cursor: Cursor.NONE
x: 20 y: 20
width: 260 height: 260
fill: Color.AQUAMARINE
onMouseExited: function(event: MouseEvent) {
// 領域から出たらイメージを消す
for (image in images) {
image.visible = false;
}
}
onMouseEntered: function(event: MouseEvent) {
// 領域に入ったらイメージを描画する
for (image in images) {
image.visible = true;
}
}
},
images
]
}
}
JavaFXでは任意のマウスカーソルを設定することができません。Preview SDKまでは可能だったのですが、
また、
最後にタイムラインの部分を示します。
var timeline = Timeline {
repeatCount: Timeline.INDEFINITE
keyFrames: [
KeyFrame {
// 100ミリ秒ごとにactionをコール
time: 100ms
action: function() {
// 1. マウスポインタの位置を取得
var point:PointerInfo = MouseInfo.getPointerInfo();
var x: Number = point.getLocation().x;
var y: Number = point.getLocation().y;
// 2. マウスポインタの位置がルートウィンドウに対する座標なので
// ローカル座標に変換
x = x - stage.x - stage.scene.x;
y = y - stage.y - stage.scene.y;
// 3. 直近の位置を先頭にし、最後の位置を廃棄する
insert x before previousX[0];
delete previousX[5];
insert y before previousY[0];
delete previousY[5];
}
}
]
};
// アニメーションの開始
timeline.play();
100ミリ秒ごとにactionアトリビュートにセットした関数がコールされます。
関数の中ではまずマウスポインタの位置を取得します。マウスポインタの位置を取得するには、
MouseInfoクラスのgetPointerInfoメソッドで取得できるマウスポインタの座標はルートウィンドウに対する座標です。そのため、
最後に、
では、
なお、
![図11 マウスカーソルを追いかけるイメージ 図11 マウスカーソルを追いかけるイメージ](/assets/images/dev/serial/01/javafx/0008/11.jpg)
おまけ
とくに解説はしませんが、
図12はクリックすると、
他のサンプルと同じように、
もう1つはフェードイン、
フェードイン、
図13はJava Web Startでアプリケーションが起動するページへのリンクがあります。スクリプトも示しましたので、