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

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

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

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Eclipse

Eclipseは、IBM社で開発された統合開発環境のひとつです。2001年11月にオープンソース化されました。 たくさんのプラグインがあり自由に機能を追加をすることができるため、開発ツールにおける共通プラットフォームとして位置づけられています。 Eclipse自体は、Javaで実装されています。

Q&A

解決済

2回答

1068閲覧

ボール跳ね返り処理について

eamons

総合スコア12

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Eclipse

Eclipseは、IBM社で開発された統合開発環境のひとつです。2001年11月にオープンソース化されました。 たくさんのプラグインがあり自由に機能を追加をすることができるため、開発ツールにおける共通プラットフォームとして位置づけられています。 Eclipse自体は、Javaで実装されています。

0グッド

0クリップ

投稿2017/12/04 08:19

編集2017/12/04 10:26

###ヘディングのテキスト###前提・実現したいこと
アクティブエリアを考慮してBallクラスのmoveメソッドでの跳ね返り処理のどこが不完全であるかを見つけ,ボールの跳ね返り処理正しく行われるように修正したいのですがどうしたらいいかわかりません

###発生している問題・エラーメッセージ

ボールが動かない

###該当のソースコード

// BlockMain.java import javax.swing.JFrame; @SuppressWarnings("serial") public class BlockMain extends JFrame{ public static void main(String[] args) { BlockMain w = new BlockMain(); w.setTitle("ブロック崩し?"); w.setSize(300, 400); //Window のサイズをセット BlockCanvas bc = new BlockCanvas(); w.add(bc); w.setVisible(true); //表示する } } // BlockCanvas.java import java.awt.Canvas; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Image; @SuppressWarnings("serial") public class BlockCanvas extends Canvas implements Runnable { Ball ball = new Ball(); Thread thread; // スレッドを使うためのインスタンスを宣言 Dimension dim; // 描画領域の大きさ BlockCanvas() { dim = getSize(); // 描画領域の大きさを調べる thread = new Thread(this); // スレッドを生成 thread.start(); // スレッドを開始 (run()が呼ばれる) } // ダブルバッファリング public void paint(Graphics g) { Dimension dim = getSize(); // 描画領域の大きさを調べる Image m_image = createImage(dim.width, dim.height);// 裏画面の画像イメージ Graphics m_g = m_image.getGraphics(); // 裏画面に付随するグラフィックスオブジェクト m_g.setColor(Color.white); m_g.fillRect(0, 0, dim.width, dim.height); ball.draw(m_g, dim); g.drawImage(m_image, 0, 0, this); // 裏画面を表画面にコピー } @Override public void run() { while (true) { // このアプリの実行中は無限ループ try { Thread.sleep(50); } catch (InterruptedException e) {} // 例外は受け流す ball.move(dim); repaint(); // 再描画要求 } } public class Ball { int x = 50, y = 100; // ボール中心の座標 int vx = 4, vy = 5; // ボールの速度ベクトル static final double RADIUS = 0.02; // ボールの半径はウインドウの2% int radius; // ボールの半径 public void draw(Graphics g, Dimension dim) { radius = (int)(RADIUS * dim.width); g.setColor(Color.black); g.fillOval(x - radius, y - radius, radius + radius, radius + radius); } public void move(Dimension dimension) { x += vx; if (x < 0) { x = 0; vx = -vx; } else if (x > dimension.width) { x = dimension.width; vx = -vx; } y += vy; if (y < 0) { y = 0; vy = -vy; } else if (y > dimension.height) { y = dimension.height; vy = -vy; } } } }

###試したこと
課題に対してアプローチしたことを記載してください

###補足情報(言語/FW/ツール等のバージョンなど)
Eclipse Luna

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

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

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

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

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

LouiS0616

2017/12/04 08:23

タグに『Java』を追加した方が回答付きやすいと思いますよ。普通IDEそのものより言語の方に関心があるので。
eamons

2017/12/04 08:36

分かりました。ありがとうございます。
guest

回答2

0

ベストアンサー

原因はmasaya_ohashiさんのおっしゃる通りと思います。

対処として別の方法をコメントしてみます。

BlockCanvasの大きさは上位コンポーネントもしくはBlockCanvas自身のいずれかで決める(定義する)でしょうからそれを元に処理を書いてもよいと思います。例えば上位でBlockCanvasのコンストラクターへ大きさを指定するなら以下のようにすると簡単です。

java

1public class BlockCanvas extends Canvas implements Runnable { 2 ... 3 Dimension dim; 4 5 public BlockCanvas(int w, int h) { 6 dim = new Dimension(w, h); 7 // awt/swingがレイアウトを決める際にこのCanvasの大きさの推奨サイズが加味される 8 setPreferredSize(dim); 9 ... 10 } 11}

ただしこの方法は「swingの通常のレイアウト手法に従って実装する」ことが前提です。下記の(1)を参照ください。


わかりにくいバグの原因となりそうな点をいくつかコメントします。

(1) JFrame#pack
質問者さんのコードではJFrameのインスタンスに対しpack()を呼び出してません。これをしないと初期レイアウト計算が行われないためせっかくのswingの自動レイアウト機構がうまくはたらきません。自前で各々のコンポーネントのサイズを一々setSizeで設定することもできなくはないですが、それは往々にしてレイアウトが意図通りにならないという大変混乱するバグの元になると自分は思います。setSizeを使うのではなくsetPreferredSize, setMinimumSize, setMaximumSizeおよびJFrame#packを使う方法をお勧めします。

(2) SwingUtilities#invokeLater
moveは描画結果の元になる情報を保持しています。この情報を「バックグラウンドスレッドで更新」するとともに「EDT(Event Dispatch Thread)で再描画の際に参照」するのを同期を取らずに行うと予期せぬバグの原因になりがちです。バックグラウンドスレッドでは次のようにしておいた方が無難だと思います。

java

1@Override public void run() { 2 // InterruptedExcepton発生時にスレッドを終わらせるなら 3 // try-catchは無限ループの外側にあった方がスッキリ書けます。 4 try { 5 while (true) { 6 Thread.sleep(50); 7 // ballはEDTでの再描画時に参照する情報なので、 8 // 同期をとらずに更新するなら 9 // runLaterを通じてEDTで実行するようにするのが無難 10 SwingUtilities.invokeLater(() -> { 11 ball.move(dim); 12 repaint(); // 再描画要求 13 }); 14 } 15 } catch (InterruptedException e) { 16 // sleep中に割り込まれたらこの例外が起きるので行儀よくループを終了する. 17 // 割り込まれているにもかかわらず強情にループを継続するのは良くない。 18 } 19}

なおInterruptedException無視するのはこのプログラムでは問題ないかも知れませんが、いつかもっと複雑な制御を書いた際に問題になると思います。なるべき行儀よく書く習慣にした方がよいと思います。

投稿2017/12/04 12:22

編集2017/12/04 13:24
KSwordOfHaste

総合スコア18392

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

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

eamons

2017/12/04 13:42

回答ありがとうございました。javaをはじめて2ヶ月ほどなのでわからないことだらけですが、わかりやすく説明していただきありがとうございます。おかげさまで解決できました。
guest

0

Java

1 BlockCanvas() { 2 dim = getSize(); // 描画領域の大きさを調べる

おそらくこの時点で取れるgetSizeはあなたの想定している大きさではないです。なぜなら大きさを決めるためのJFrameにaddされるのはBlockCanvasのコンストラクタの「後」だからです。dimを得るのはサイズが確定したタイミングにしなければならないかと思います。
BlockCanvasのコンストラクタでresizeイベントを受け取れるようにして、resize発生時にdimを取るようにしてみてはどうでしょう(以下のコードは動作テストしていません)。

Java

1BlockCanvas() { 2 this.addComponentListener(new ComponentListener() { 3 public void componentResized(ComponentEvent e) { 4 dim = getSize(); // 描画領域の大きさを調べる 5 } 6 // 他のインタフェースメソッドは中略 7 }); 8 thread = new Thread(this); // スレッドを生成 9 thread.start(); // スレッドを開始 (run()が呼ばれる) 10}

投稿2017/12/04 08:37

masaya_ohashi

総合スコア9206

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

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

eamons

2017/12/04 08:57

訂正していただいたとおりにして import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; を追加したのですが、ComponentListener()がエラーになってしまうのはなぜでしょうか
masaya_ohashi

2017/12/04 09:24

中略の部分が書かれていないのが原因かと思います。componentResizedだけが必要ですが、他にもcomponentMove等が必要なのでエラーが起きます。 ComponentListenerではなくComponentAdapterなら必要なメソッドだけオーバーライドして使えるので、こちらのほうが使いやすいかもしれないです。 https://docs.oracle.com/javase/jp/8/docs/api/java/awt/event/ComponentAdapter.html
eamons

2017/12/04 13:45

回答していただきありがとうございました。私の理解が薄くすみません。参考にさせていただき、解決することができました。ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問