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

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

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

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

Swing

SwingはJavaに標準で付属するグラフィック関連のクラスライブラリを指します。

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

Q&A

解決済

1回答

1133閲覧

衝突回数のカウントの仕様を改善したい

Ryuuse

総合スコア27

Java

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

Swing

SwingはJavaに標準で付属するグラフィック関連のクラスライブラリを指します。

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

0グッド

0クリップ

投稿2021/01/12 12:03

編集2021/01/12 12:49

ボールのアニメーションで、2つのボールが衝突したときに回数をカウントし、画面上に表示させるプログラムを作りました。カウント自体はうまくいきましたが、ボールが長時間接触している時に衝突回数がカウントされ続けてしまうので、最終時には衝突回数が無限に増え続けてしまいます(その時の状況を画像として載せました)。このような欠陥をどうにかする方法が分かれば、ぜひ教えてください。
イメージ説明

PinBall

1import java.awt.BorderLayout; 2import java.awt.FlowLayout; 3import java.awt.Graphics; 4import java.awt.event.ActionEvent; 5import java.awt.event.ActionListener; 6import java.awt.Container; 7 8import javax.swing.JFrame; 9import javax.swing.JPanel; 10import javax.swing.Timer; 11import javax.swing.JButton; 12import javax.swing.JLayeredPane; 13 14public class PinBall { 15 public static void main(String[] args) { 16 JFrame window = new JFrame("PinBall"); 17 window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 18 window.setSize(650, 400); 19 20 21 PanelGameBoard panel = new PanelGameBoard(); 22 window.add(panel); 23 window.setVisible(true); 24 25 panel.animationStart(); 26 27 28 } 29} 30 31class PanelGameBoard extends JPanel implements ActionListener { 32 private final Ball ball; 33 private final Timer timer; 34 private Ball ballEx; 35 private int count = 0;//衝突回数のカウンタ 36 37 JButton button = new JButton("上から落とす"); 38 // 再描画タイミング 39 private static final int INTERVAL = 50; 40 41 public PanelGameBoard() { 42 timer = new Timer(INTERVAL, this); 43 ball = new Ball(this); 44 ballEx = new Ball(this); 45 ballEx.setX(150); 46 ballEx.setY(130); 47 this.add(button); 48 button.addActionListener(this); 49 } 50 51 public void animationStart() { 52 ball.goHome(); 53 timer.start(); 54 } 55 56 @Override 57 public void paintComponent(Graphics graphics) { 58 super.paintComponent(graphics); 59 ball.draw(graphics); 60 ballEx.draw(graphics); 61 graphics.drawString("ボールの衝突回数:"+count+"回", 500, 300); 62 if((ball.getX()-ballEx.getX())*(ball.getX()-ballEx.getX())+(ball.getY()-ballEx.getY())*(ball.getY()-ballEx.getY())<=(double)2*ball.getR()*ball.getR()) 63 count++; 64 } 65 66 @Override 67 public void actionPerformed(ActionEvent event) { 68 ball.next(); 69 ballEx.next(); 70 repaint(); 71 if(event.getSource() == button){ 72 ball.setY(0); 73 ballEx.setY(0); 74 } 75 if((ball.getX()-ballEx.getX())*(ball.getX()-ballEx.getX())+(ball.getY()-ballEx.getY())*(ball.getY()-ballEx.getY())<=(double)2*ball.getR()*ball.getR()){ 76 ball.setVx(((1+ball.getE())*ball.getVx()+(1-ball.getE())*ballEx.getVx())/(double)2); 77 ball.setVy(((1+ball.getE())*ball.getVy()+(1-ball.getE())*ballEx.getVy())/(double)2); 78 ballEx.setVx(((1-ball.getE())*ball.getVx()+(1+ball.getE())*ballEx.getVx())/(double)2);//2つのボールにおける中心間の距離が直径より小さくなれば 79 ballEx.setVy(((1-ball.getE())*ball.getVy()+(1+ball.getE())*ballEx.getVy())/(double)2);//衝突したと判定として運動量保存則に基づき速度を変える 80 81 } 82 83 } 84 85 86}

Ball

1import java.awt.Color; 2import java.awt.Graphics; 3 4import javax.swing.JPanel; 5 6public class Ball { 7 // ボールの半径 8 private double r = 10.0; 9 10 // ボールの中心座標 11 private double x = 0.0; 12 private double y = 0.0; 13 14 // ボールの速度(1フレーム当たりの移動距離) 15 private double vx = 15.0; 16 private double vy = -15.0; 17 18 // ボールの色 19 private Color color = Color.BLACK; 20 21 // y軸 正の方向の加速度(1フレーム当たりの上記「速度」の変化量) 22 private double g = 0.5; 23 24 // 反発係数 25 private double e = 0.8; 26 27 // ボールを描画するパネル 28 private JPanel panel; 29 30 public Ball(JPanel panel) { 31 this.panel = panel; 32 } 33 34 public Ball(double r, double x, double y, double vx, double vy, Color color, JPanel panel) { 35 this.r = r; 36 this.x = x; 37 this.y = y; 38 this.vx = vx; 39 this.vy = vy; 40 this.color = color; 41 this.panel = panel; 42 } 43 44 /*--- アクセサメソッド ---*/ 45 // getter 46 public double getR() { return r; } 47 public double getE() { return e; } 48 49 public double getX() { return x; } 50 public double getY() { return y; } 51 52 public double getVx() { return vx; } 53 public double getVy() { return vy; } 54 55 // setter 56 public void setR(double r) { this.r = r; } 57 58 public void setX(double x) { this.x = x; } 59 public void setY(double y) { this.y = y; } 60 public void setXY(double x, double y) { this.x = x; this.y = y; } 61 62 public void setVx(double vx) { this.vx = vx; } 63 public void setVy(double vy) { this.vy = vy; } 64 public void setVxVy(double vx, double vy) { this.vx = vx; this.vy = vy; } 65 66 public void setG(double g) { this.g = g; } 67 public void setE(double e) { this.e = e; } 68 public void setColor(Color color) { this.color = color; } 69 70 // ボールを描画 71 public void draw(Graphics graphics) { 72 Color prevColor = graphics.getColor(); 73 graphics.setColor(color); 74 graphics.fillOval((int) (x - r), (int) (y - r), (int) (2 * r), (int) (2 * r)); 75 graphics.setColor(prevColor); 76 } 77 78 // ボールを左下隅へ移動 79 public void goHome() { 80 x = r; 81 y = panel.getHeight() - r; 82 } 83 84 // 座標、速度更新 85 public void next() { 86 // 画面の幅と高さ取得 87 int width = panel.getWidth(); 88 int height = panel.getHeight(); 89 90 x = x + vx; 91 y = y + vy; 92 93 /*--- 衝突判定 ---*/ 94 if (x < r) { 95 x = r; 96 vx = -vx * e; 97 } 98 99 if (x + r > width) { 100 x = width - r; 101 vx = -vx * e; 102 } 103 104 if (y < r) { 105 y = r; 106 vy = -vy * e; 107 } 108 109 if (y + r > height) { 110 y = height - r; 111 vy = -vy * e; 112 } 113 114 // 画面下向きの加速度 115 vy = vy + g; 116 } 117} 118

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

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

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

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

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

guest

回答1

0

ベストアンサー

ボールが長時間接触している時に衝突回数がカウントされ続けてしまうので、

ボールが衝突していることを検出した後、次にチェックしたときにも同じ状態、つまり衝突中であれば+1しなければよいわけです。ご提示のコードで言えば以下のような修正を加えることで無限に+1し続けることは無くなります。boolean inCollisionフィールドが衝突中であるか否かを示すフラグです。最初の状態はfalse、つまりボールが離れていることを示すので、シミュレーションを再び開始する場合など、適切なタイミングで再初期化してください。

Java

1// 衝突中か否かを示すフラグ 2private boolean inCollision = false; 3 4@Override 5public void paintComponent(Graphics graphics) { 6 super.paintComponent(graphics); 7 ball.draw(graphics); 8 ballEx.draw(graphics); 9 graphics.drawString("ボールの衝突回数:"+count+"回", 500, 300); 10 11 boolean r = ((ball.getX()-ballEx.getX())*(ball.getX()-ballEx.getX())+(ball.getY()-ballEx.getY())*(ball.getY()-ballEx.getY()) 12 <= ball.getR()*ball.getR()); 13 14 if (r) { 15 // 衝突 16 if (!inCollision) { 17 // 前回までに衝突していなければ +1 18 inCollision = true; 19 count++; 20 } 21 } else { 22 // 離れている 23 inCollision = false; 24 } 25}

投稿2021/01/12 12:51

dodox86

総合スコア9183

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

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

Ryuuse

2021/01/12 13:09

booleanを使うという考え方は無かったので、回答者様の発想は非常に参考になりました。回答、どうもありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問