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

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

ただいまの
回答率

87.59%

弾の当たり判定の書き方,NullPointerの対処がわかりません。

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 1,026

score 11

前提・実現したいこと

Processing3でシューティングゲームを作っているのですが当たり判定の条件文でNullPointerExceptionとエラーが出てどう対処すればよいかわかりません。
80行目の
if(b.isAlive())
の中に

{敵のx座標<弾のx座標+弾の幅 && 
{弾のx座標<敵のx座標+敵の幅 && 
{敵のy座標<弾のy座標+弾の高さ &&
{弾のy座標<敵のy座標+敵の高さ

のように判定文を入れてるのですが、この書き方でいいのかもわかりません。
検索していろいろ調べたのですが結局わかりませんでした。どのようにすれば直るでしょうか。

該当のソースコード

import ddf.minim.*;
import ddf.minim.analysis.*;

Minim minim;
AudioPlayer BGM;
AudioSample laser;
FFT fft;
int fftSize;

PImage img,img_s,img_ss,pl,en;

float mx = mouseX;
float my = mouseY;
int level = 0;
ME me;
ENEMY e;
ArrayList<BEAM> beamList = new ArrayList<BEAM>();
ArrayList<ENEMY> enemyList = new ArrayList<ENEMY>();
float bvel;
float bx;
float by;
float myGain;
float bGain;
int flag;
boolean right;

void setup(){
  size(1280, 720);
  frameRate(90);
  colorMode(RGB);
  rectMode(CENTER);
  me = new ME();
  textAlign(CENTER);
  imageMode(CENTER);
  img = loadImage("hosi.png");
  img_s = loadImage("hosi_s.png");
  img_ss = loadImage("hosi_ss.png");
  pl = loadImage("onpu.png");
  en = loadImage("enemy.png");
  minim = new Minim(this);
  fftSize = 512;
  laser = minim.loadSample("laser1.mp3");
  BGM = minim.loadFile("BGM.mp3");
  BGM.loop();
  myGain = BGM.getGain();
  bGain  = laser.getGain();
  myGain = myGain - 20;
  bGain  = bGain - 40;
  BGM.setGain(myGain);
  laser.setGain(bGain);
  fft = new FFT(BGM.bufferSize(), BGM.sampleRate());
  enemyList.add(new ENEMY());
}

void draw(){
  if(level == 0){
    background(0); 
    fade(false);
    textSize(32);
    noFill();
    text("MouseRightButton is clicked to start", width/2, height/2);
  }

  if(level == 1){
    background(0);
    fade(false);
    me.move(mouseX,mouseY);
    me.display();
    for(int i = enemyList.size()-1; i >= 0; i--){
      ENEMY e = enemyList.get(i);
      if(e.isAlive()){
        e.move();
        e.display();
      }else{
        enemyList.remove(i);
      }
    }
    for(int i = beamList.size()-1; i >= 0; i--){
      BEAM b = beamList.get(i);
      if(b.isAlive()){
        b.move();
        b.display();
        if(e.ex < b.bx+b.bwi/2 && b.bx < e.ex+e.ewi/2 &&
           e.ey < b.by+b.bhe/2 && b.by < e.ey+e.ehe){
           beamList.remove(i);  
        }
      }else{
        beamList.remove(i);
      }
    }
    if(right){
      if(frameCount % 8 == 0){
        laser.trigger();
        beamList.add(new BEAM(me.mx, me.my));
      }
    }
    if(frameCount % 3 == 0){
      enemyList.add(new ENEMY());
    }
  }
}

void mousePressed(){
  if(level == 0){
    if(mouseButton == RIGHT){
      level = 1;
    }
  }
  if(level == 1){
    if(mouseButton == LEFT){
      right = true;
    }
  }
}

void mouseReleased(){
  if(level ==1 ){
    if(mouseButton == LEFT){
      right = false;
    }
  }
}


class ME{
  float mx = width/2, my = height/2;

  void move(float x,float y){
    mx = x;
    my = y;
  }
  void display(){
    fft.forward(BGM.left);
    for (int i = 0; i < fft.specSize(); i++) {
      float rectSize = map(fft.getBand(i), 0, fftSize, 0, width/4);

      fill(260, 131, 40);
      noStroke();
      image(pl, mx, my);


      noFill();
      strokeWeight(1);
      stroke(255, 187, 0);
      rect(mx, my, rectSize, rectSize, 10);
      }
    fft.forward(BGM.right);
    for (int i = 0; i < fft.specSize(); i++) {
      float rectSize = map(fft.getBand(i), 0, fftSize, 0, width/4);

      fill(260, 131, 40);
      noStroke();
      image(pl, mx, my);

      noFill();
      strokeWeight(1);
      stroke(255, 187, 0);
      rect(mx, my, rectSize, rectSize);
    }
  }
}

class ENEMY{
  float ex;
  float ey;
  float evel;
  float ewi;
  float ehe;
  float swei;

  ENEMY(){
  ex = random(0, width);
  ey = 0;
  evel = random(5,15);
  ehe = 50;
  ewi = 50;
  }

  void move(){
    ey += evel;
  }
  void display(){
    image(en, ex, ey);
  }
  boolean isAlive(){
    if (ex+ewi/2 < 0 || width < ex-ewi/2 || ey+ehe/2 < 0 || height < ey-ehe/2){
      return false;
    }
    return true;
  }
}

class BEAM{
  float bx;
  float by;
  float bvel;
  float bwi;
  float bhe;
  float ex;
  float ey;
  float ehe;

  BEAM(float x, float y){
    bx = x;
    by = y;
    bwi = 5;
    bhe = 50;
    bvel = 15;
  }

  void move(){
    by -= bvel;
  }
  void display(){
    noFill();
    strokeWeight(1);
    stroke(37, 149, 199);
    rect(bx, by, bwi, bhe);
  }
  boolean isAlive(){
    if (bx+bwi/2 < 0 || width < bx-bwi/2 || by+bhe/2 < 0 || height < by-bhe/2){
      return false;
    }
    return true;
  }
}

void fade(boolean _fadeFlag){
  if(_fadeFlag){
    fill(0);
    rect(width/2, height/2, width, height);
    fill(0);
  }else{
    image(img_ss, width/2, (frameCount*8)%height);
    image(img_s, width/2, (frameCount*12)%height);
    image(img, width/2, (frameCount*16)%height);
  }
}

void stop(){
  BGM.close();
  minim.stop();
  super.stop();
}

試したこと

敵やビームをArrayListにした
色々な場所に条件分を置いてみた

補足情報(FW/言語など)

Processing

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

+2

画像や音声ファイルを用意しないといけないプログラムって他人デバッグが面倒ですね。
あと、「いろいろやってみましたがダメでした」は情報ゼロ。あなたが何をやったか私にはわかりません。その結果何が起こったかもわかりません。結局、何も書いていないのと一緒です。あなたが「頑張ったんだ」と主張するのはいいですけれど、それは解決に何も寄与しません。「これをやった->何が起こった」という「事実」が、変化があったにしてもなかったにしても情報というもの。

    for (int i = enemyList.size()-1; i >= 0; i--) {
      ENEMY e = enemyList.get(i); /////eの宣言...?
      if (e.isAlive()) {
        e.move();
        e.display();
      } else {
        enemyList.remove(i);
      }
    }
    for (int i = beamList.size()-1; i >= 0; i--) {
      BEAM b = beamList.get(i);
      if (b.isAlive()) {
        b.move();
        b.display();
        if (e.ex < b.bx+b.bwi/2 && b.bx < e.ex+e.ewi/2 && /////ERROR: eがnull
          e.ey < b.by+b.bhe/2 && b.by < e.ey+e.ehe) {
          beamList.remove(i);
        }
      } else {
        beamList.remove(i);
      }
    }


コメントで入れたERRORのところでeがnullだと怒られているわけですね。ではこのeはどこで宣言されている変数でしょう? もしかして、その上の「eの宣言...?」とコメントを入れたところ? でも、ここのスコープはfor文の範囲内ですから、エラー箇所は名前はeでも別の実体のはずです。
プログラムを上から見ていくと、グローバル変数として
ENEMY e;
というのが16行目にあります。これのようですね。このeは、宣言されたあと値を設定されることもなく、件の判定で使用されています。当然、nullです。
ここは全ての敵と全ての弾の総当たりチェックをするべきところですか? なら、ちゃんと考えてプログラムを組み直して下さい。当たり判定と移動、描画などの前後関係もちゃんと整理して考えないといけないでしょう。

判定の式がそれでいいかどうかは全く別の話ですね。全然難しい話ではありませんから「検索」に頼るのでなく図でも書いてよく考えてみて下さい。理解できずに検索で出てきたままを使うなら「大抵は希望する結果がでているけど、もしかしたら違う結果になる時もあるかも知れない」です。あなたが「あっている」と説明出来るならあっています。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/01/13 13:46

    私の拙い質問文を指摘して頂き、なおかつ質問の返答までしていただいて申し訳ありません。
    このアドバイスをもとにプログラムのeの宣言と順序関係を把握しながら組みなおしていこうと思います。
    本当にありがとうございました。

    キャンセル

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

  • ただいまの回答率 87.59%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

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