PathTransition

ITpro の Java 技術最前線で、ずっと JavaFX 連載をしていたのですが、それも次の月曜でおしまい。

というのも JavaFX 2.0 で JavaFX Script がサポートされなくなってしまうためです。JavaFX Script を中心に解説をしてきたので、しかたないのですが...

で、12/6 の原稿が最終回です。

途中で打ちきりということで、解説していないことがまだいっぱいあります。できるだけ最終回にいれようと思っていたのですが、分量オーバー。なくなく削ったわけです。

でも、せっかく書いたものなので、ここで公開してしまいます。

よく使用するアニメーション

XTransition というクラス群は、よく使うアニメーションを簡単に記述できるようにしたクラス群です。

合計 8 種類ありますが、詳細 JavaFX では TranslateTransition、FadeTransition、SequentialTransition、ParallelTransition、PauseTransition の 5 つのクラスについて解説しています。

残ったのが PathTransition と ScaleTransition、RotateTransition の 3 つです。

今回は PathTransition クラスについて。

PathTransition

PathTransition クラスは TranslateTransition クラスと同様にノードを移動させるアニメーションを記述できます。

TranslateTransitionクラスは 2点間を直線で結んだ移動しかサポートしていません。つまり、複雑な軌道をえがく移動はできません。

このような場合に使用するのが、PathTransitionクラスです。

PathTransitionクラスでは、ノードの軌跡を曲線で指定します。

JavaFXで曲線を表すにはjavafx.scene.shape.Pathクラスを使用します。PathTransitionクラスではPathオブジェクトから生成するAnimationPathオブジェクトを使用してノードの軌跡を指定します。

Pathによる曲線の記述

では、Pathクラスはどのように曲線を表すのでしょうか。たとえば、以下の図に表す曲線をPathクラスで表してみます。

f:id:skrb:20101203233701j:image

曲線を表すには、曲線を表す関数が分らなければいけません。しかし、一般化した曲線の関数を表すのはたいへんです。

そこで、曲線を短い部分に分割します。たとえば、図2の曲線は(70, 120)から(70, 20)は(70, 70)を中心とした半径50の円弧、(70, 20)から(170, 20)までの直線と、(170, 20)から(170, 120)までの曲線に分割できます。

短い部分であれば、曲線部分に2次曲線もしくは3次曲線を当てはめて補間することができます。この補間を行なう2次曲線をB-スプライン曲線、3次曲線をベジェ曲線と呼びます。

B-スプライン曲線は端点と、端点の接線を伸ばして交わった点を使用すれば表すことができます。この接線を伸ばして交差した点を制御点と呼びます。

一方のベジェ曲線の場合、端点の接線上の任意の点を制御点とします。つまり制御点が2つとなります。端点と制御点の距離が長くなれば長くなるほど、曲線は接線に隣接していきます。

Adobe Illustratorなどのベクタ形式のドローツールもベジェ曲線を使用して曲線を構成するものが多いので、ご存じの方も多いのではないでしょうか。

上図の場合、端点が(170, 20)、(170, 120)、制御点が(270, 20)と(90, 120)になります。
では、この曲線をPathクラスで表してみましょう。Pathクラスは曲線を分割した部分をPathElementクラスのサブクラスで表していきます。

var path = Path {
    elements: [
        // 開始点
        MoveTo { x: 70  y: 120 },
        // 円弧 
        // 右回りなのでsweepFlagをtrueに設定
        ArcTo {
            x: 70  y: 20
            radiusX: 50  radiusY: 50 sweepFlag: true
        },
        // 直線
        LineTo { x: 170, y: 20 },
        // ベジェ曲線
        CubicCurveTo {
            x: 170  y: 120
            controlX1: 270 controlY1: 20
            controlX2: 80 controlY2: 120
        }
    ]
}

PathElementクラスのサブクラスには点を移動させるMoveToクラス、直線を表すLineToクラス、楕円弧を表すArcToクラスなどがあります。B-スプライン曲線にはQuadCurveToクラス、ベジェ曲線にはCubicCurveToクラスを使用します。

なお、ArcToオブジェクトは、デフォルトでは開始点から反時計回りで円を描きます。ここでは時計回りに円を描きたいためsweepFlagプロパティをtrueにしています。

PathTransitionによるノードの移動

では、このパスを四角が移動するようにしてみましょう。

// 移動対象の四角
var rectangle = Rectangle {
    x: 0 y: 0
    width: 20 height: 10
    fill: Color.RED
} 
 
// パスに沿った移動
var transition = PathTransition {
    node: rectangle
    duration: 10s
    path: AnimationPath.createFromPath(path)
}
// 移動の開始
transition.play();

PathTransitionクラスは、TranslateTransitionと同様、移動させるノードをnodeプロパティ、移動にかける時間をdurationプロパティで表します。

異なるのは、パスを指定する部分です。前述したようにパスにはAnimationPathクラスを使用します。PathオブジェクトからAnimationPathオブジェクトへの変換は、赤字で示したようにcreateFromPathメソッドを使用します。

後は四角を表示する部分です。ここでは分りやすいようにパスも一緒に表示させることにしました。

Stage {
    title: "Path Animation"
    scene: Scene {
        width: 220 height: 140
        content: [
            path,  // パスも表示する
            rectangle
        ]
    }
}

実行すると次のようになります。

f:id:skrb:20101122192630j:image

下のリンクから実際にサンプルを動作させることができます。

http://javainthebox.net/javafx/samples/pathtranslate/pathtranslate.html

このようにパス上を移動できるようになりました。しかし、ちょっともの足りません。というのも、ノードが曲線の接線方向を向かないからです。

たとえば、車や船などのイメージをPathTransitionクラスで移動させたとしましょう。車や船などは移動方向を向いていないと、走っているように見えません。これを行なうには次のようにPathTransitionクラスのorientationプロパティにOrientationType.ORTHOGONAL_TO_TANGENTを設定します。

// パスに沿った移動
var transition = PathTransition {
    node: rectangle
    duration: 20s
    orientation: OrientationType.ORTHOGONAL_TO_TANGENT
    path: AnimationPath.createFromPath(path)
}

では、これで実行してみましょう。実行結果を以下にに示します。

f:id:skrb:20101122193604j:image

これで、四角が回転して、パスの接線方向を向くようになりました。

なお、このサンプルは以下のページからダウンロードできます。

http://javainthebox.net/javafx/samples/pathtranslate/pathtranslate.html