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

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

ただいまの
回答率

91.35%

  • Java

    10483questions

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

  • Eclipse

    1287questions

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

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

解決済

回答 2

投稿 2017/12/04 17:19 ・編集 2017/12/04 19:26

  • 評価
  • クリップ 0
  • VIEW 105

eamons

score 2

ヘディングのテキスト###前提・実現したいこと

アクティブエリアを考慮して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

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • LouiS0616

    2017/12/04 17:23

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

    キャンセル

  • eamons

    2017/12/04 17:36

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

    キャンセル

回答 2

checkベストアンサー

+1

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

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

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

public class BlockCanvas extends Canvas implements Runnable {
  ...
  Dimension dim;

  public BlockCanvas(int w, int h) {
    dim = new Dimension(w, h);
    // awt/swingがレイアウトを決める際にこのCanvasの大きさの推奨サイズが加味される
    setPreferredSize(dim);
    ...
  }
}


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


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

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

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

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

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

投稿 2017/12/04 21:22

編集 2017/12/04 22:23

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/12/04 22:42

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

    キャンセル

+1

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


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

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

投稿 2017/12/04 17:37

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/12/04 17:57

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

    キャンセル

  • 2017/12/04 18:24

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

    キャンセル

  • 2017/12/04 22:45

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

    キャンセル

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

ただいまの回答率

91.35%

関連した質問

同じタグがついた質問を見る

  • Java

    10483questions

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

  • Eclipse

    1287questions

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