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

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

ただいまの
回答率

89.13%

敵と自機の当たり判定時におきるエラーを解決したい

解決済

回答 1

投稿

  • 評価
  • クリップ 1
  • VIEW 847
退会済みユーザー

退会済みユーザー

前提・実現したいこと
javaで敵を複数体出すプログラムを作ったのですが
敵と自機が当たる部分で以下のエラーが出てしまいます。

発生している問題・エラーメッセージ

エラーメッセージ

    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
    at java.util.ArrayList$Itr.next(ArrayList.java:851)
    at Rousakuten.runGameMain(Rousakuten.java:177)
    at GameHoneGumi$MyTimerTask.run(GameHoneGumi.java:119)
    at java.util.TimerThread.mainLoop(Timer.java:555)
    at java.util.TimerThread.run(Timer.java:505)

言語
java

実行したソースコード(抜粋)

    public void keyPressedGameMain(int keycode) {
        switch(keycode){
        case KeyEvent.VK_UP : keyup = true;break;
    case KeyEvent.VK_DOWN : keydown= true; break;
    case KeyEvent.VK_LEFT : keyleft = true; break;
    case KeyEvent.VK_RIGHT : keyright = true; break;
    case KeyEvent.VK_SPACE: keySpace = true; break;
    case KeyEvent.VK_ENTER: keyEnter = true; break;
    }
    }

    @Override
    public void keyReleasedGameMain(int keycode) {
        switch(keycode){
        case KeyEvent.VK_UP : keyup = false;break;
    case KeyEvent.VK_DOWN : keydown= false; break;
    case KeyEvent.VK_LEFT : keyleft = false; break;
    case KeyEvent.VK_RIGHT : keyright = false; break;
    case KeyEvent.VK_SPACE: keySpace = false; break;
    case KeyEvent.VK_ENTER: keyEnter = false; break;
    }



    }

    public void runStartGamen(Graphics g) {
        g.setColor(Color.BLUE);
        g.fillRect(0, 0, this.width, this.height);
    }

    @Override
    public void runStageStart(Graphics g) {
        // TODO 自動生成されたメソッド・スタブ

    }

    @Override
    public void runStageClear(Graphics g) {
        // TODO 自動生成されたメソッド・スタブ

    }

    @Override
    public void runGameMain(Graphics g) {
        // TODO 自動生成されたメソッド・スタ
        if(keyup){
            y-=6;
            if(y<0) y = 0;
        }
        if(keydown){
            y+=6;
            if(y>675) y=675;            }
        if (keyleft) {
            x -= 6;
            if (x < 0) x = 0;
        }
        // 右移動
        if (keyright) {
            x += 6;
            if (x >860) x = 860;
        }
        //弾発射
        if (keySpace && rensya == 0) {
            jikitamas.add(new Jikitama(x+12, y));

            rensya = 28;
        }

        if(rensya > 0) rensya--;
        //弾消滅
        if (!jikitamas.isEmpty()) {
            Iterator<Jikitama> itr = jikitamas.iterator();
            while(itr.hasNext()) {
                Jikitama jt = itr.next();
                if (jt.y < 0) itr.remove();
                else jt.y -= 8;
            }
        }
        //enemy delete, update
        if(!tekis.isEmpty()){
            Iterator<Teki> itr = tekis.iterator();
            while (itr.hasNext()) {
                Teki t = itr.next();
                if (t.ey >= 675)
                    itr.remove();
                else
                    t.ey += 3;
            }
        }
        //
        if(tekis.size() < 4 && tekideru <= 0){
            int ex = (int)(Math.random()*420)+200;
            int ey = (int)(Math.random()*32);
            Teki t = new Teki(ex, ey);
            tekis.add(t);

            tekideru = 30;
        }
        if(tekideru > 0) tekideru--;

        if(!jikitamas.isEmpty()) {
            Iterator<Jikitama> itr = jikitamas.iterator();
            boolean isHit = false;
            while (itr.hasNext()) {
                Jikitama jt = itr.next();
                isHit = false;
                Iterator<Teki> itrE = tekis.iterator();
                while (itrE.hasNext()) {
                    Teki t= itrE.next();
                    if(jt.x +0> t.ex && jt.x< t.ex +40 && jt.y +8 > t.ey&& jt.y < t.ey + 32) {
                        score+=50;
                        itrE.remove();
                        tflag = false;
                        score+=50;
                        isHit = true;
                    }
                }
                if (isHit) itr.remove();
            }
        }
//自分はこの部分に問題があると思っています
        if (!tekis.isEmpty()) {
            for (Teki t: tekis) {
                if (x +32 >t.ex && x < t.ex +32 && y +32 > t.ey && y < t.ey +32){
                    goGameOver();
                }
            }
        }

        g.clearRect(0, 0, 900, 700);
        g.drawImage(back, 0, 0,  frame1);
        g.drawImage(jiki, x, y, frame1);
        if (!jikitamas.isEmpty()) {
            Iterator<Jikitama> itr = jikitamas.iterator();
            while(itr.hasNext()){
                Jikitama jt = itr.next();
                g.drawImage(tama, jt.x, jt.y, frame1);
            }

        }
        for(Teki t: tekis){
            g.drawImage(teki, t.ex, t.ey, frame1);
        }
        g.setColor(Color.pink);
        g.drawString("SCORE:" + String.valueOf(score),50,50);

            bstrategy.show();
            g.dispose();

    }

    @Override
    public void runGameOver(Graphics g) {
         g.setColor(Color.RED);
         g.setFont(new Font("Sanserif" , Font.BOLD,80));
         g.drawString("GAMEOVER", 230, 365);
         bstrategy.show();
         g.dispose();
         return;
    }

    @Override
    public void initStageStart() {
        // TODO 自動生成されたメソッド・スタブ

    }

    @Override
    public void initStageClear() {
        // TODO 自動生成されたメソッド・スタブ

    }

    @Override
    public void initGameOver() {
        x = 440;
        y = 660;
        rensya = 0;
        score = 0;
        jikitamas.clear();
        keysClear();
        tekis.clear();
    }

    private void keysClear() {
        keyup = false;
        keydown = false;
        keyright = false;
        keyleft = false;
        keyEnter = false;
        keyP = false;
    }

    public static void main(String[] args) {
        Rousakuten r = new Rousakuten(900, 700, "test");
    }

}

試したこと
何を試せばよいのか分からず行っていません

補足情報(言語/FW/ツール等のバージョンなど)
このプログラムの完成形はシューティングゲームにしようと思っています。
上記のプログラムはスーパークラスから継承したものも含まれているので一応スーパークラスも載せておきます。
コードが長く申し訳ありません
回答よろしくお願いします。
また、この情報が足りないからほしいという意見がありましたら言ってくださると助かります。

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.image.BufferStrategy;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.JFrame;

public abstract class GameHoneGumi {
    public static final int GS_STARTGAMEN = 0;
    public static final int GS_STAGESTART = 1;
    public static final int GS_STAGECLEAR = 2;
    public static final int GS_GAMEOVER = 3;
    public static final int GS_GAMEMAIN = 4;
    private int gamestate;
    private int waittimer;
    JFrame frame1;
    BufferStrategy bstrategy;

    GameHoneGumi(int w, int h, String title){
        frame1 = new JFrame(title);
        frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame1.setBackground(Color.WHITE);
        frame1.setResizable(false);

        frame1.setVisible(true);
        Insets insets = frame1.getInsets();
        frame1.setSize(w + insets.left + insets.right, h + insets.top + insets.bottom);
        frame1.setLocationRelativeTo(null);

        frame1.createBufferStrategy(2);
        bstrategy = frame1.getBufferStrategy();
        frame1.setIgnoreRepaint(true);

        frame1.addKeyListener(new MyKeyAdapter());

    }
    public abstract void keyPressedGameMain(int keycode);
    public abstract void keyReleasedGameMain(int keycode);
    public abstract void runStartGamen(Graphics g);
    public abstract void runStageStart(Graphics g);
    public abstract void runStageClear(Graphics g);
    public abstract void runGameMain(Graphics g);
    public abstract void runGameOver(Graphics g);
    public abstract void initStageStart();
    public abstract void initStageClear();
    public abstract void initGameOver();

    public void goStartGamen(){
        gamestate = GS_STARTGAMEN;
        Timer t = new Timer();
        t.schedule(new MyTimerTask(),  10, 10);
    }
    public void goStageStart(){
        initStageStart();
        waittimer = 100;
        gamestate = GS_STAGESTART;
    }
    public void goStageClear(){
        initStageClear();
        waittimer = 100;
        gamestate = GS_STAGECLEAR;

    }
    public void goGameMain(){
        gamestate = GS_GAMEMAIN;

    }
    public void goGameOver(){
        initGameOver();
        gamestate = GS_GAMEOVER;

    }
    class MyKeyAdapter extends KeyAdapter{
        public void keyPressed(KeyEvent ev){
            if(gamestate == GS_GAMEMAIN){
                keyPressedGameMain(ev.getKeyCode());
            }
        }
        public void keyReleased(KeyEvent ev){
            int keycode = ev.getKeyCode();
            switch(gamestate){
            case GS_GAMEMAIN:
                keyReleasedGameMain(keycode);
                break;
            case GS_STARTGAMEN:
                if(keycode== KeyEvent.VK_P) goStageStart();
                break;
            case GS_GAMEOVER:
                if(keycode == KeyEvent.VK_R) goStageStart();
            }
        }
    }
    class MyTimerTask extends TimerTask{
        public void run(){
            Graphics g = bstrategy.getDrawGraphics();
            if(bstrategy.contentsLost() == false){
                Insets insets = frame1.getInsets();
                g.translate(insets.left, insets.top);

                switch(gamestate){
                case GS_STARTGAMEN:
                    runStartGamen(g);
                    break;
                case GS_STAGESTART:
                    runStageStart(g);
                    waittimer = waittimer-1;
                    if(waittimer<0)   goGameMain();
                    break;
                case GS_STAGECLEAR:
                    runStageClear(g);
                    waittimer = waittimer-1;
                    if(waittimer<0)  goStageStart();
                    break;
                case GS_GAMEMAIN:
                    runGameMain(g);
                    break;
                case GS_GAMEOVER:
                    runGameOver(g);
                    break;
                }
            }
        }
    }

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • LouiS0616

    2017/08/18 00:16

    エラーメッセージがちょん切れています。全体を再掲してください。

    キャンセル

回答 1

checkベストアンサー

0

ゲーム作り大変ですよね。苦労します。

さて、質問者様の予想は正しいです。
まさしく

       if (!tekis.isEmpty()) {
            for (Teki t: tekis) {
                if (x +32 >t.ex && x < t.ex +32 && y +32 > t.ey && y < t.ey +32){
                    goGameOver();
                }
            }
        }


の部分が問題です。他にも問題があるかもしれませんが、同じエラーであれば、今回の回答を参考にして修正して頂ければ問題ないでしょう。

僕は質問者のコードを次のように修正致します。

  if (!tekis.isEmpty()) {            
           boolean flag = false;
         for (Teki t: tekis) {
                if (x +32 >t.ex && x < t.ex +32 && y +32 > t.ey && y < t.ey +32){
                      flag = true;
                      break;
                }
             }
            if(flag)  goGameOver();
   }
//イテレーターを使うやり方もあります。お好みでどうぞ。


変化したことは、
x +32 >t.ex && x < t.ex +32 && y +32 > t.ey && y < t.ey +32
trueとなったときにbreak;でforループを抜けてgoGameOver();を実行していることです。
どうしても、goGameOver();をforループの外に出したかったのです。
その理由は、このメソッドは'initGameOver()'を経由して'tekis.clear();'を実行しているからです。
つまり、
tekisがループされてる中、tekisの要素数が修正されたからです。
javaの仕様上、次の時ConcurrentModificationExceptionを出します。

この例外は、オブジェクトが別のスレッドによって並行して更新されていないことを必ずしも示しているわけではありません。単一のスレッドが、オブジェクトの規約に違反する一連のメソッドを発行した場合、オブジェクトはこの例外をスローします。たとえば、フェイルファストイテレータを持つコレクションの繰り返し処理を行いながら、スレッドがコレクションを直接修正する場合、イテレータはこの例外をスローします。
通常、非同期の並行変更がある場合、確かな保証を行うことは不可能なので、フェイルファストの動作を保証することはできません。フェイルファストオペレーションは最善努力原則に基づき、ConcurrentModificationException をスローします。したがって、正確を期すためにこの例外に依存するプログラムを書くことは誤りです。ConcurrentModificationException は、バグを検出するためにのみ使用してください。

「イテレータを持つコレクションの繰り返し処理を行いながら、スレッドがコレクションを直接修正する場合、イテレータはこの例外をスローします。」とあります。
この仕様を原因として、今回エラーがでました。

ゲーム作り諦めないでください。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/08/18 16:08

    回答ありがとうございます!
    おかげで解決することができました!
    自分はエラーを修正してプログラム上に表すことがまだまだ未熟なので、文章でエラーの直し方を書いてあって助かりました!
    ゲーム作り頑張ります!!

    キャンセル

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

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

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