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

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

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

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

Processing

Processingは、オープンソースプロジェクトによるCGのためのプログラミング言語です。Javaをベースにしており、グラフィック機能に特化しています。イメージの生成やアニメーションなど、視覚的なフィードバックを簡単に得ることが可能です。

Q&A

解決済

1回答

3751閲覧

javaで当たり判定のついたシューティングゲームを作りたい。

wotuyu

総合スコア2

Java

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

Processing

Processingは、オープンソースプロジェクトによるCGのためのプログラミング言語です。Javaをベースにしており、グラフィック機能に特化しています。イメージの生成やアニメーションなど、視覚的なフィードバックを簡単に得ることが可能です。

1グッド

0クリップ

投稿2021/08/04 01:23

Processingを使用してシューティングゲームを制作しています。
当たり判定を実装したいのですが、うまくいきません。
自機から放った弾(SHOT)が、敵(ENEMY)の当たり判定範囲内に入った時に、弾と敵が描画されなくなるようにしたいです。

【試したこと】
boolean でhitflagを立てて、衝突範囲内に入った時にtrueを返すようなプログラムを作っていますが、うまくいきません。
加えて、敵や弾の速度が不安定になってしまっています。

ENEMY enemy[]; HIKOU hikou; HAIKEI haikei[]; ArrayList<SHOT> shotList = new ArrayList<SHOT>(); PImage png; int N = 100; int n = 5; float ey, ex; float sx, sy; boolean hitflag; void setup() { size(300, 600); frameRate(30); rectMode(CENTER); noCursor(); png = loadImage("hikou.png"); png = loadImage("enemy.png"); hikou = new HIKOU(); haikei = new HAIKEI[N]; for (int i = 0; i < N; i++) { haikei[i] = new HAIKEI(); } enemy = new ENEMY[n]; if(!hitflag){  //ここにhitflagを立てて、falseの時だけ描画しようとしています。 for (int i = 0; i < n; i++) { enemy[i] = new ENEMY(); } } } void draw() { background(0); for (int i = 0; i < N; i++) { haikei[i].draw(); } if(!hitflag){ //ここもfalseの時だけ描画しようとしています。 for (int i = 0; i < n; i++) { enemy[i].draw(); } } for (int i=shotList.size ()-1; i>=0; i--) { SHOT t = shotList.get(i); if (t.isAlive()) { t.move(); t.display(); } else { shotList.remove(i); } } hikou.move(mouseX, mouseY); hikou.display(); PImage hikoupng = loadImage("hikou.png"); image(hikoupng, mouseX - 15, mouseY - 32); } void mousePressed() { shotList.add(new SHOT(hikou.x, hikou.y)); } class HIKOU {  //自機 float x, y; float size; HIKOU() { size = 10; } void move(float _x, float _y) { x = _x; y = _y; } void display() { } } public class SHOT {  //弾 float size; float speed; SHOT(float _x, float _y) { sx = _x; sy = _y; size = 6; speed = 15; } void move() { sy -= speed; } void display() { stroke(0); fill(255, 0, 0); rect(sx, sy, size, size); } boolean isAlive() { if (sx+size/2<0 || width<sx-size/2 || sy+size/2<0 || height<sy-size/2) { return false; } return true; } } class HAIKEI {  //背景 float y; float x; float vy = 10; float len; HAIKEI() { init(); y = random(-height, height); } void init() { y = random(-2*height, -1); x = random(0, width); vy = random(10, 18); len = random(15, 25); } void draw() { stroke(200);//color line(x, y, x, y+len); update(); } void update() { y += vy; if (height < y+len) { init(); } } } public class ENEMY {  //敵 float vy = 5; float len; ENEMY() { init(); ey = random(-2 * height, -height); } void init() { ey = random(-20); ex = random(20, width - 20); len = random(20, 35); } void draw() { PImage enemypng = loadImage("enemy.png"); image(enemypng, ex, ey); update(); } void update() { ey += vy; if (height + 40 < ey + len) { init(); } } public boolean hitflag;{  //ここがhitflagです。 if(ex + 20 > sx && ex - 20 > sx && ey + 20 > sy && ey > sy + 20){ hitflag = true; } else { hitflag = false; } } }

修正点が多く、拙い内容で申し訳ないのですが、ご教授いただければ幸いです。

enemy.png
hikou.png

TN8001👍を押しています

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

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

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

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

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

jimbe

2021/08/04 02:48

> 衝突範囲内に入った時にtrueを返すようなプログラム というのはコードの最後にある hitflag でしょうか。 これはメソッドなのでしょうか、それともフィールド(プロパティ)なのでしょうか。いつ if 文が実行されるのでしょう。
stdio

2021/08/04 05:18

jimbeさんの指摘している通り、hitflag の存在があやふやです。使い方は普通の変数に見えますが、当たり判定だというなら各キャラクターがいている座標ぐらい取得できるようにしないと、判定が上手くいくわけありません。 かなり上から目線の文章になってしまいましたが、ゲームを作る前にもう少しJavaという言語を勉強した方がいいかも知れません。
guest

回答1

0

ベストアンサー

Java - シューティングゲームで、当たり判定を実装したい|teratail
から1週間だいぶ試行錯誤しておられるようですね。
しかし残念ながら方向が違うような気がします。

Processingは仕組み上クラス内からグローバル変数にアクセスし放題なのですが、そのせいでスパゲッティコードにもなりやすいです(ありがたい時もあるんですが^^;
例えばENEMYxyが外に出てしまって(exey)、前回より退化してしまっています。

敵や弾の速度が不安定になってしまっています。

ちゃんとは追っていませんが、おそらくexeysxsyのせいです。

boolean でhitflagを立てて、衝突範囲内に入った時にtrueを返すような

敵が複数いるのですから、フラグも複数あるべきでは?
ひとつでもできないことはないでしょうが、ややこしくなるしすでにクラスがあるんですからそっちに定義すればいいと思います。

個人的に気になった点を変更しました。

  • 命名規則を標準的なものに
    Javaではクラス名は通常パスカルケース(例:PascalCase)です。
    大文字だけ(例:UPPER_SNAKE_CASE)は定数に使用します。
    (まあ「個人で作っているものは好きにつけりゃいいじゃん」と思っていますが、標準のもの(ArrayList等)と混じると読みにくいので^^;

  • 同じような意味のmovedisplayと、updatedrawがあるのは気持ち悪いので統一
    2つのプログラムを合体させた感じ?(いろいろ参考にされていると思いますが

  • つどloadImageしてしまっているのは大変無駄
    せっかくクラスを作ったのだから、メンバ変数に入れときましょう。

  • Nnはわかりにくいので、lengthや拡張for文に置き換える
    特にグローバル変数は多いほど読みにくくなるので、使わずに済む場合は積極的に減らします。

Processing

1Player player; 2Enemy[] enemies = new Enemy[5]; 3Star[] stars = new Star[100]; 4ArrayList<Shot> shotList = new ArrayList<Shot>(); 5 6 7void setup() { 8 size(300, 600); 9 frameRate(30); 10 rectMode(CENTER); 11 imageMode(CENTER); 12 noCursor(); 13 14 player = new Player(loadImage("hikou.png")); 15 16 PImage png = loadImage("enemy.png"); 17 for (int i = 0; i < enemies.length; i++) { 18 enemies[i] = new Enemy(png); 19 } 20 21 for (int i = 0; i < stars.length; i++) { 22 stars[i] = new Star(); 23 } 24} 25 26void draw() { 27 background(0); 28 29 player.update(); 30 31 for (Star star : stars) { 32 star.update(); 33 star.draw(); 34 } 35 36 boolean gameOver = false; 37 for (Enemy enemy : enemies) { 38 enemy.update(); 39 40 // 弾に当たっているか確認のため全弾ループ 41 for (int i = shotList.size () - 1; i >= 0; i--) { 42 Shot shot = shotList.get(i); 43 if (enemy.isHit(shot.x, shot.y)) { // shotの座標と接触していれば... 44 enemy.isDead = true; // フラグで管理するならこう 45 //enemy.init(); // でも敵がいなくなってしまうので単に初期化でいい気が^^; 46 shotList.remove(i); 47 println("hit"); 48 } 49 } 50 51 // ついでに自機との接触も 52 if (enemy.isHit(player.x, player.y)) { // playerの座標と接触していれば... 53 gameOver = true; 54 } 55 56 enemy.draw(); 57 } 58 59 for (int i = shotList.size () - 1; i >= 0; i--) { 60 Shot shot = shotList.get(i); 61 shot.update(); 62 if (shot.isAlive()) { 63 shot.draw(); 64 } else { 65 shotList.remove(i); 66 } 67 } 68 69 player.draw(); 70 71 if (gameOver) { 72 fill(255); 73 textSize(40); 74 textAlign(CENTER, CENTER); 75 text("GAME OVER", width / 2, height / 2); 76 noLoop(); 77 } 78} 79 80void mousePressed() { 81 shotList.add(new Shot(player.x, player.y)); 82} 83 84 85class Player { 86 PImage image; 87 float x; 88 float y; 89 90 Player(PImage _image) { 91 image = _image; 92 } 93 94 void update() { 95 x = mouseX; 96 y = mouseY; 97 } 98 99 void draw() { 100 image(image, x, y); 101 } 102} 103 104class Enemy { 105 PImage image; 106 float x; 107 float y; 108 float vy = 5; 109 float size = 40; 110 boolean isDead; // フラグを作るならココ 111 112 Enemy(PImage _image) { 113 image = _image; 114 init(); 115 y = random(-2 * height, -height); 116 } 117 118 void init() { 119 isDead = false; 120 y = random(-20); 121 x = random(20, width - 20); 122 } 123 124 void draw() { 125 if (isDead) return; 126 127 image(image, x, y); 128 } 129 130 void update() { 131 if (isDead) return; 132 133 y += vy; 134 if (height + size < y) { 135 init(); 136 } 137 } 138 139 // Shot#isAliveと同じような感じで指定座標(_x・_y)との接触判定 140 boolean isHit(float _x, float _y) { 141 if (isDead) return false; 142 143 float r = size / 2; 144 return x - r < _x && _x < x + r && y - r < _y && _y < y + r; 145 } 146} 147 148class Star { 149 float x; 150 float y; 151 float vy; 152 float len; 153 154 Star() { 155 init(); 156 y = random(-height, height); 157 } 158 159 void init() { 160 y = random(-2 * height, -1); 161 x = random(0, width); 162 vy = random(10, 18); 163 len = random(15, 25); 164 } 165 166 void update() { 167 y += vy; 168 if (height < y + len) { 169 init(); 170 } 171 } 172 173 void draw() { 174 stroke(200); 175 line(x, y, x, y + len); 176 } 177} 178 179class Shot { 180 float x; 181 float y; 182 float vy = -15; 183 float size = 6; 184 185 Shot(float _x, float _y) { 186 x = _x; 187 y = _y; 188 } 189 190 void update() { 191 y += vy; 192 } 193 194 void draw() { 195 stroke(0); 196 fill(255, 0, 0); 197 rect(x, y, size, size); 198 } 199 200 boolean isAlive() { 201 float r = size / 2; 202 return 0 <= x + r && x - r <= width && 0 <= y + r && y - r <= height; 203 } 204}

別にこれが正解というわけではありません。
10人いたら10通りのコードになるでしょうし、あまりいじらないようにしたので「ちょっとどうかな?」という部分もあります。

投稿2021/08/04 11:14

編集2023/07/28 15:00
TN8001

総合スコア9862

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

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

wotuyu

2021/08/04 12:33

とても丁寧なご回答本当にありがとうございます。 理解が難しかった点などが、詳しい解説でとても分かりやすかったです。 フラグの立て方や、細かい点(意味が同じコードの統一等)までご指摘いただき、大変勉強になりました。 これを今後の学習に役立て、より一層プログラミングを頑張りたいと思います。 本当にありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問