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

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

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

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

Q&A

解決済

3回答

2026閲覧

衝突判定

nakamura-

総合スコア48

Java

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

0グッド

0クリップ

投稿2016/07/04 02:40

シューティングゲームのようなものを作っています
(上から降ってくる桜の花びらを撃つ)
下のプログラムはその途中のものです。

コード public class Part01 extends JApplet{ /*初期メソッド*/ public void init(){ setSize(1000, 700); MyPanel mp = new MyPanel(); getContentPane().add(mp); } }
コード public class MyPanel extends JPanel implements Runnable{ Player player; int gunCount = 0; Gun gun; ArrayList<Gun> gunList = new ArrayList<Gun>(); Sakura sakura; ArrayList<Sakura> sakuraList = new ArrayList<Sakura>(); Thread loopPaint; Random rnd = new Random(); /*MyPanelのコンストラクタ*/ public MyPanel(){ setBackground(Color.BLACK); /*再描画ループスレッド*/ loopPaint = new Thread(this); loopPaint.start(); /*画像読み込み、切り取り*/ try{ player = new Player("jiki.gif", 0, 0, 32, 32); } catch(IOException ioe){ System.out.println("画像がありません"); } loopGunThread(); loopCreateSakuraThread(); loopSakuraThread(); } /*キー入力処理*/ @Override protected void processKeyEvent(KeyEvent ke){ if(ke.getID() == KeyEvent.KEY_PRESSED){ player.updata(ke.getKeyCode()); if(ke.getKeyCode() == KeyEvent.VK_ENTER){ gun = new Gun(10000, 10000); gunList.add(gun); gunList.get(gunCount).startLine(player.m_x, player.m_y); gunCount++; } } } /*描画メソッド*/ @Override protected void paintComponent(Graphics g){ super.paintComponent(g); requestFocusInWindow(); //キー入力有効化 player.draw(g); if(gun != null){ //gunがインスタンス化されている場合(Enter押された場合) for(int i = 0; i < gunList.size(); i++){ //弾の数だけ繰り返し gunList.get(i).draw(g); } } if(sakura != null){ for(int i = 0; i < sakuraList.size(); i++){ sakuraList.get(i).draw(g); } } if(gun != null && sakura != null){ for(int i = 0; i < gunList.size(); i++){ for(int k = 0; k < sakuraList.size(); k++){ if( sakuraList.get(k).Screen_vData[0][0] > gunList.get(i).m_x && sakuraList.get(k).Screen_vData[1][0] < gunList.get(i).m_x && sakuraList.get(k).Screen_vData[0][1] > gunList.get(i).m_y && sakuraList.get(k).Screen_vData[1][1] < gunList.get(i).m_y ){ System.out.println("-----衝突-----"); } } } } } /*runメソッド(loopPaintスレッド)*/ public void run(){ while(true){ repaint(); } } /*弾ループスレッド作成*/ public void loopGunThread(){ Thread loopGun = new Thread(new Runnable(){ public void run(){ while(true){ try{ Thread.sleep(50); } catch(InterruptedException e){ } if(gun != null){ //gunがインスタンス化されている場合(Enter押された場合) for(int i = 0; i < gunList.size(); i++){ //弾の数だけ繰り返し if(gunList.get(i).m_y > -10){ gunList.get(i).updata(); } } } } } }); loopGun.start(); } /*桜作成ループスレッド作成*/ public void loopCreateSakuraThread(){ Thread createSakura = new Thread(new Runnable(){ public void run(){ while(true){ try{ Thread.sleep((long)(Math.random() * 1000)); } catch(InterruptedException e){ } sakura = new Sakura( 1, 1, 1, -1, -1, 1, -1, 1, 0, 1, -1, 0, 400, -100, rnd.nextInt(6) + 5); sakuraList.add(sakura); } } }); createSakura.start(); } /*桜ループスレッド作成*/ public void loopSakuraThread(){ Thread loopSakura = new Thread(new Runnable(){ public void run(){ while(true){ try{ Thread.sleep(20); } catch(InterruptedException e){ } if(sakura != null){ for(int i = 0; i < sakuraList.size(); i++){ sakuraList.get(i).updata(); } } } } }); loopSakura.start(); } }
コード public class Player{ BufferedImage m_bi; int m_x = 485; int m_y = 640; /*Playerのコンストラクタ*/ public Player(BufferedImage bi){ m_bi = bi; } public Player(BufferedImage bi, int x, int y, int w, int h){ m_bi = bi.getSubimage(x, y, w, h); } public Player(File file, int x, int y, int w, int h) throws IOException{ BufferedImage bi = ImageIO.read(file); m_bi = bi.getSubimage(x, y, w, h); } public Player(String str, int x, int y, int w, int h) throws IOException{ File file = new File(str); BufferedImage bi = ImageIO.read(file); m_bi = bi.getSubimage(x, y, w, h); } /*位置更新メソッド*/ public void updata(int keyCode){ if(keyCode == KeyEvent.VK_RIGHT){ m_x += 32; } if(keyCode == KeyEvent.VK_LEFT){ m_x -= 32; } } /*描画メソッド*/ public void draw(Graphics g){ g.drawImage(m_bi, m_x, m_y, null); } }
コード public class Gun{ int m_x; int m_y; /*Gunのコンストラクタ*/ public Gun(int x, int y){ m_x = x; m_y = y; } /*攻撃開始位置設定メソッド*/ public void startLine(int x, int y){ m_x = x; m_y = y; } /*位置更新メソッド*/ public void updata(){ m_y -= 10; } /*描画メソッド*/ public void draw(Graphics g){ g.setColor(Color.WHITE); g.fillRect(m_x, m_y, 2, 2); } }
コード public class Sakura{ double Vertex_data[][] = new double[2][3]; //頂点データ double Screen_vData[][] = new double[2][3]; //表示頂点データ double Control_data[][] = new double[2][3]; //曲線描くときのコントロールデータ double Screen_cData[][] = new double[2][3]; //表示コントロールデータ double pointX; //表示開始位置のx座標 double pointY; //表示開始位置のy座標 int scale; //描画倍数 double phi; //x軸周りの回転角 double theta; //y軸周りの回転角 Random rnd = new Random(); /*Sakuraクラスのコンストラクタ*/ public Sakura( double Vertex_data00, double Vertex_data01, double Vertex_data02, double Vertex_data10, double Vertex_data11, double Vertex_data12, double Control_data00, double Control_data01, double Control_data02, double Control_data10, double Control_data11, double Control_data12, double pointX, double pointY, int scale){ this.Vertex_data[0][0] = Vertex_data00; this.Vertex_data[0][1] = Vertex_data01; this.Vertex_data[0][2] = Vertex_data02; this.Vertex_data[1][0] = Vertex_data10; this.Vertex_data[1][1] = Vertex_data11; this.Vertex_data[1][2] = Vertex_data12; this.Control_data[0][0] = Control_data00; this.Control_data[0][1] = Control_data01; this.Control_data[0][2] = Control_data02; this.Control_data[1][0] = Control_data10; this.Control_data[1][1] = Control_data11; this.Control_data[1][2] = Control_data12; this.pointX = pointX; this.pointY = pointY; this.scale = scale; phi = 0; theta = 0; } /*位置変更メソッド*/ public void updata(){ pointX += (Math.random() * 1); phi += Math.PI / (rnd.nextInt(201) + 30); theta += Math.PI / (rnd.nextInt(151) + 30); pointY += (Math.random() + 2); setRotPosition(); } /*回転・落下後の座標を求めるメソッド*/ public void setRotPosition(){ double Xsin = Math.sin(phi); double Xcos = Math.cos(phi); double Ysin = Math.sin(theta); double Ycos = Math.cos(theta); for(int i = 0; i < Vertex_data.length; i++){ double rvx = Vertex_data[i][0] * Ycos + Vertex_data[i][2] * Ysin; double rvy = Vertex_data[i][0] * Xsin * Ysin + Vertex_data[i][1] * Xcos - Vertex_data[i][2] * Xcos * Ycos; double rvz = - Vertex_data[i][0] * Xcos * Ysin + Vertex_data[i][1] * Xsin + Vertex_data[i][2] * Xcos * Ycos; Screen_vData[i][0] = (float)(pointX + (rvx * scale)); Screen_vData[i][1] = (float)(pointY - (rvy * scale)); Screen_vData[i][2] = (float)(rvz * scale); } for(int i = 0; i < Control_data.length; i++){ double rcx = Control_data[i][0] * Ycos + Control_data[i][2] * Ysin; double rcy = Control_data[i][0] * Xsin * Ysin + Control_data[i][1] * Xcos - Control_data[i][2] * Xcos * Ycos; double rcz = - Control_data[i][0] * Xcos * Ysin + Control_data[i][1] * Xsin + Control_data[i][2] * Xcos * Ycos; Screen_cData[i][0] = (float)(pointX + (rcx * scale)); Screen_cData[i][1] = (float)(pointY - (rcy * scale)); Screen_cData[i][2] = (float)(rcz * scale); } } /*描画メソッド*/ public void draw(Graphics g){ Graphics2D g2D = (Graphics2D)g; GeneralPath path = new GeneralPath(); path.moveTo(Screen_vData[0][0], Screen_vData[0][1]); path.quadTo(Screen_cData[0][0], Screen_cData[0][1], Screen_vData[1][0], Screen_vData[1][1]); path.quadTo(Screen_cData[1][0], Screen_cData[1][1], Screen_vData[0][0], Screen_vData[0][1]); path.closePath(); g2D.setColor(Color.pink); g2D.fill(path); } }

MyPanelクラスのpaintComponentメソッドで衝突判定をしているのですが、桜を描画しているxとyの幅の中に弾が存在すれば(桜と弾が重なれば)「衝突」と表示するようにしているのですが、弾が桜を通り抜けても表示されませんでした。
衝突判定方法がなにか間違っているのでしょうか?
それとも他に何か原因があるのでしょうか?
よろしくお願いします

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

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

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

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

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

guest

回答3

0

ベストアンサー

3D的な座標管理、描画されていますので、当たり判定も3D的に考えなければいけません。しかし、3Dの当たり判定をやるにはハードルが高すぎます。そこで簡単なのが「だいたいの大きさで当たり判定をとる」という考え方です。実際のゲームでも労力、処理の複雑さとを天秤にかけ、アバウトな当たり判定を行うことはよくあります。
今回の場合、Sakuraの基準座標xyを中心としたscale分の大きさの円、そして弾のxyの当たり判定を取るのが一番それっぽいかつ簡単でしょう。

Java

1// Sakuraの基準位置をx1,y1とする。 2double x1 = sakuraList.get(k).Screen_vData[0][0]; 3double y1 = sakuraList.get(k).Screen_vData[0][1]; 4 5// gunの基準位置をx2,y2とする。 6double x2 = gunList.get(i).m_x; 7double y2 = gunList.get(i).m_y; 8 9// ベクトルの計算を使い、基準位置同士の距離を計算する。 10double length = Math.sqrt(Math.pow(x1-x2,2) + Math.pow(y1-y2,2)); 11 12// 距離がSakuraの大きさ(scale)より小さければ衝突とする 13if(length < sakuraList.get(k).scale){ 14 System.out.println("-----衝突-----"); 15}

Sakuraの基準位置が微妙に感じると思うのでしたら、vData[1][0]、[1][1]との中間位置を計算してそこを基準にしたらよいかもしれません。

投稿2016/07/05 02:07

masaya_ohashi

総合スコア9206

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

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

nakamura-

2016/07/08 07:50

回答ありがとうございます。 中間位置を基準にするときれいにできました! ありがとうございました。
guest

0

衝突判定からみたデータの持ち方ってこれであってますか?

座標(x,y)=(0,0)が左上とした場合
左上座標(Screen_vData[1][0], Screen_vData[1][1])
この間に弾座標(m_x, m_y)があれば衝突判定
右下座標(Screen_vData[0][0],Screen_vData[0][1])

感覚的なものだけど、Screen_vData[0]とScreen_vData[1]の大小関係が怪しそう。

投稿2016/07/04 07:03

kopio

総合スコア487

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

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

nakamura-

2016/07/08 07:49

回答ありがとうございます。 確かに回転もしているので大小関係がおかしいかもしれません。 確認したいと思います。 ご指摘ありがとうございます!
guest

0

コードをざっと眺めただけですが、桜の花びらの大きさは2×2なのに、弾丸は毎ステップ10ピクセル移動していきますので、重なる瞬間が一回もないまま向こう側へ行ってしまいそうです。
重なる瞬間が発生しないのに当たり判定をする方法、熱力学シミュレーションなんかだと厳密な方法があるのですがゲームだからそれっぽく見えればいいわけで、花びらの当たり判定を上方向に10ピクセル延ばせば十分ではないかと。

投稿2016/07/04 06:05

yuba

総合スコア5568

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

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

nakamura-

2016/07/04 06:15

回答ありがとうございます。 花びらの大きさは5~10のランダムで設定して弾を2×2にしています。 目視でも重なっているのは確認できます。 当たり判定を上方向に10ピクセル延ばすというのはどういうことでしょうか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問