曲線のアニメーション
このエントリーは、2013 年の JavaFX Advent Calendar の初日のエントリーです。
明日は tomo_taka01 さんです。
JavaFX で曲線というと CubicCurve か、QuadCurve です。これらのクラスをアニメーションさせることを考えてみます。
もちろん、トランジションでもいいのですが、PathTransition 以外はあまりおもしろくないので (おもしろくない = 簡単に使えるです)、今日は扱いません。
となると、Timeline か AnimationTimer でアニメーションさせます。せっかくだからグネグネ動くようなアニメーションがいいですね ^ ^;;
Timeline でも AnimationTimer でも、クラスのプロパティが定義してあれば、その値を時間で変化させるということが可能です。
CubicCurve などのクラスのプロパティといえば、端点と制御点です。これらのプロパティを変化させてあげれば、グネグネ動かすことも可能です!
ということで、ここでは制御点をアニメーションさせてみましょう。
ちなみに、制御点というのは端点の接線上にある点で、端点から離れていればいるほど曲線は接線に近づいていきます。
ITpro で以前、端点と制御点の関係を図に描いたので、それを参照してみてください。
まず、アニメーションさせる 2 本の CubicCurve を作っておきます。
// ベジェ曲線 1本目 final CubicCurve curve1 = new CubicCurve(); curve1.setStartX(40.0); curve1.setStartY(100.0); curve1.setEndX(360.0); curve1.setEndY(100.0); curve1.setStroke(Color.BLACK); curve1.setStrokeWidth(10.0); curve1.setStrokeLineCap(StrokeLineCap.ROUND); curve1.setFill(null); parent.getChildren().add(curve1); // ベジェ曲線 2本目 final CubicCurve curve2 = new CubicCurve(); curve2.setStartX(40.0); curve2.setStartY(100.0); curve2.setEndX(360.0); curve2.setEndY(100.0); curve2.setStroke(Color.BLACK); curve2.setStrokeWidth(10.0); curve2.setStrokeLineCap(StrokeLineCap.ROUND); curve2.setFill(null); parent.getChildren().add(curve2);
アニメーションで制御点の値を変化させるので、この時点では設定していません。
では、制御点をアニメーションさせてみましょう!!
ここでは、AnimationTimer を使用して、制御点を円運動させてみます。まず、円運動させるためのサインとコサインを決めておきます。
// ベジェ曲線の制御点を円運動させるアニメーション AnimationTimer timer = new AnimationTimer() { @Override public void handle(long t) { double sin1 = 150 * Math.sin(t/400_000_000.0); double cos1 = 150 * Math.cos(t/400_000_000.0); // もう一方の制御点は180度ずらす double sin2 = 150 * Math.sin(t/400_000_000.0 + Math.PI); double cos2 = 150 * Math.cos(t/400_000_000.0 + Math.PI);
端点の一方を sin1/cos1 にしたら、もう一方の端点を sin2/cos2 にすると 8 の字になります。2 つの端点をどちらも sin1/cos1 にすると楕円になります。もちろん、この場合、もう一方の CubicCurve を sin2/cos2 にします。
ここでは 8 の字にしてみます。
double controlX11 = 40.0 + sin1; double controlY11 = 100.0 + cos1; curve1.setControlX1(controlX11); curve1.setControlY1(controlY11); double controlX12 = 360.0 + sin2; double controlY12 = 100.0 + cos2; curve1.setControlX2(controlX12); curve1.setControlY2(controlY12);
(40, 100) と (360, 100) は端点の座標です。
もう一方の CubicCurve はこれと逆にします (同じだとくっついてしまうので)。
double controlX21 = 40.0 + sin2; double controlY21 = 100.0 + cos2; curve2.setControlX1(controlX21); curve2.setControlY1(controlY21); double controlX22 = 360.0 + sin1; double controlY22 = 100.0 + cos1; curve2.setControlX2(controlX22); curve2.setControlY2(controlY22); } };
後は AnimationTimer をスタートさせるだけです。
timer.start();
これでグニグニ動きます。
これと同じ動きをトランジションでも作ることができます。それは円運動のアニメーションをするダミーのノードを作ります (このノードは表示させません)。円運動をさせるには PathAnimation で path に Circle を指定します。
そして、CubicCurve の端点の座標をこのノードの座標にバインドします。
こうすることで、トランジションでも同じ動きを実現できます。そこら辺も ITpro の連載で書いたので、参照してみてください。
ソースは gist にアップしてあります。