質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
JavaFX

JavaFXとは、Java仮想マシン上で動作するリッチインターネットアプリケーション (RIA) のGUIライブラリです。Swingとは異なり、FXMLと呼ばれる XMLとCSSを併用してデザインを記述します。

Q&A

解決済

1回答

4357閲覧

JavaFXでImageを回転させたい

unasenohkoku

総合スコア11

JavaFX

JavaFXとは、Java仮想マシン上で動作するリッチインターネットアプリケーション (RIA) のGUIライブラリです。Swingとは異なり、FXMLと呼ばれる XMLとCSSを併用してデザインを記述します。

0グッド

0クリップ

投稿2017/07/14 14:47

###だめぽ
JavaFX8でゲームを作ろうと思い立ったはいいんですが、DirectXで言うDrawRotaGraphが見当たらずひぃひぃ言ってます。

1時間ほどリファレンスとにらめっこして、どうやらGraphicsContextごと回せばいいらしいことはわかりましたがこれでは「複数の画像を表示して1枚だけ傾ける」といった実装ができません。

そこで「GraphicContextが2つあればいんじゃね?」と安易な発想でImageを2つ表示してみましたが2枚の画像は一緒に回ってしまいました。お手上げです。誰か助けてください……。

Java

1//抜粋 2 3 Canvas canvas = new Canvas( 1500, 800 ); 4 root.getChildren().add( canvas ); 5 Image image=new Image("file:C:\\Users\\Admin\\Pictures\\test.png"); 6 7 GraphicsContext gc = canvas.getGraphicsContext2D(); 8 GraphicsContext gc2= canvas.getGraphicsContext2D(); 9 10 final long startNanoTime = System.nanoTime(); 11 12 new AnimationTimer() 13 { 14 public void handle(long currentNanoTime) 15 { 16 double t = (currentNanoTime - startNanoTime) / 1000000000.0; 17 18 Affine af=gc.getTransform(); 19 af.appendRotation(t,500,300); 20 gc.setTransform(af); 21 gc.drawImage(image,500,300); 22 23 Affine af2=af.clone(); 24 af2.appendRotation(0); 25 gc2.setTransform(af2); 26 gc2.drawImage(image,800,500); 27 } 28 }.start(); 29 theStage.show();


抜粋

全文

Java

1//全文 2 3package sample; 4import javafx.animation.AnimationTimer; 5import javafx.application.Application; 6import javafx.scene.*; 7import javafx.scene.canvas.Canvas; 8import javafx.scene.canvas.GraphicsContext; 9import javafx.scene.image.Image; 10import javafx.scene.transform.Affine; 11import javafx.stage.Stage; 12 13 14public class Main extends Application { 15 16 17 int ScreeenFlg=0; 18 public static Main singleton; 19 public Stage stage; 20 21 22 public static void main(String[] args) { 23 Application.launch(args); 24 } 25 26 @Override 27 public void start(Stage theStage) throws Exception { 28 29 theStage.setTitle("画像回転テスト"); 30 Group root = new Group(); 31 Scene theScene = new Scene( root ); 32 theStage.setScene( theScene ); 33 34 Canvas canvas = new Canvas( 1500, 800 ); 35 root.getChildren().add( canvas ); 36 Image image=new Image("file:C:\\Users\\Admin\\Pictures\\test.png"); 37 38 GraphicsContext gc = canvas.getGraphicsContext2D(); 39 GraphicsContext gc2= canvas.getGraphicsContext2D(); 40 41 final long startNanoTime = System.nanoTime(); 42 43 new AnimationTimer() 44 { 45 public void handle(long currentNanoTime) 46 { 47 double t = (currentNanoTime - startNanoTime) / 1000000000.0; 48 49 Affine af=gc.getTransform(); 50 af.appendRotation(t,500,300); 51 gc.setTransform(af); 52 gc.drawImage(image,500,300); 53 54 Affine af2=af.clone(); 55 af2.appendRotation(0); 56 gc2.setTransform(af2); 57 gc2.drawImage(image,800,500); 58 } 59 }.start(); 60 theStage.show(); 61 } 62} 63

###駄目元でCanvasを2つにしてみる

Java

1 GraphicsContext gc2= canvas2.getGraphicsContext2D();

にしても駄目でした。ひーん。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

GraphicContextが2つあれば

CanvasインスタンスにはGraphicContextインスタンスは1つしか生成されないと思います。そのためアフィン変換を繰り返し適用すると、その効果がどんどん蓄積されるわけで、複数のオブジェクトに違う変換を施したり、刻々と位置や向きが変化するアニメーションを表現するには扱いづらいですね。

こうした場合はGraphicContext#save/restoreメソッドを用いて、次のような3ステップで個々の描画を行うとよいと思います。

(1) GraphicContextの状態をsave
(2) アフィン変換を適用して描画
(3) GraphicContextの状態をrestore

ご質問のコードで言えば以下のような感じでしょうか。

diff

1+ gc.save(); 2 Affine af=gc.getTransform(); 3 af.appendRotation(t,500,300); 4 gc.setTransform(af); 5 gc.drawImage(image,500,300); 6+ gc.restore(); 7 8 gc2.drawImage(image,800,500);

ところで、個々の描画で一々save/restoreすると煩わしいですし、saveかrestoreをし忘れたとたん惨憺たる結果になるため、メソッド化しておくのがよいかも知れません。例えばDirectXのDrawRotaGraphの汎用版みたいな関数は次のように書けます。(蛇足ですが、ここでのtranslate/rotate/scaleは、描画オブジェクトに対する変換ではなく、座標系に対する変換ですので、呼び出す順番にご注意ください)

java

1static void draw(GraphicsContext gc, Consumer<GraphicsContext> operation, 2 double tx, double ty, double scale, double angle, double alpha, boolean turn) { 3 gc.save(); 4 gc.translate(tx, ty); 5 gc.rotate(angle); 6 gc.scale(scale * (turn ? -1 : 1), scale); 7 gc.setGlobalAlpha(alpha); 8 operation.accept(gc); 9 gc.restore(); 10}

これを利用すれば以下のようにできます。

java

1// 原点が画像の中心となるよう画像を描画 2static void drawImageAtOrigin(GraphicsContext gc, Image image) { 3 gc.drawImage(image, -0.5 * image.getWidth(), -0.5 * image.getHeight()); 4} 5 6... 7GraphicsContext gc = canvas.getGraphicsContext2D(); 8draw(gc, gc2 -> drawImageAtOrigin(gc2, image), 500, 300, 1.0, angle, 1.0, false); 9draw(gc, gc2 -> drawImageAtOrigin(gc2, image), 800, 500, 0.5, 0, 1.0, false);

save/restoreは入れ子にできますので、例えば「動きのあるオブジェク1の周りをさらに回っているオブジェクト2」といったものも書きやすくなると思います。以下のtx2, ty2, scale2, angle2はそれぞれオブジェクト1に対するオブジェクト2のアフィン変換ですから、より単純な計算式で表現できます。この考え方は階層的な関係を持つオブジェクトグループを描画する際によく用いられるものだと思います。

java

1draw(gc, 2 gc2 -> { 3 オブジェクト1を描画; 4 draw(gc2, gc3 -> { 5 オブジェクト2を描画; 6 }, tx2, ty2, scale2, angle2, 1.0, false); 7 }, tx1, ty1, scale1, angle1, 1.0, false);

投稿2017/07/14 23:14

編集2017/07/15 02:36
KSwordOfHaste

総合スコア18392

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

unasenohkoku

2017/07/15 02:33

うおおおおおおおおおおおおおお動いた動いたぜ動きました!!!!!!!! ありがとうございます!!!!! 丁寧にDirectXと似たような書き方までできるようしにていただき本当に助かりました!ありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問