Java-Gaming.org    
Featured games (81)
games approved by the League of Dukes
Games in Showcase (495)
Games in Android Showcase (114)
games submitted by our members
Games in WIP (563)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Inconsistent IndexOutOfBounds Exceptions  (Read 722 times)
0 Members and 1 Guest are viewing this topic.
Offline tyeeeee1
« Posted 2013-11-16 00:05:52 »

Hey,

I've been working on a simple space invaders clone since noon and I keep running into inconsistent errors that I have trouble replicating every game that I test. The most common error is with the following line in the loop that follows it.

1  
if(projectiles.get(i).getColissionBox().intersects(entities.get(j).getColissionBox())


1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
// Check if any bullet has collided with any alien entity. If a bullet has then remove it and remove the entity.
     for(int i=0;i<projectiles.size();i++) {
         for(int j=0;j<entities.size();j++) {
            if(projectiles.get(i).getColissionBox().intersects(entities.get(j).getColissionBox())) {
               playerScore += entities.get(j).getSpeed() * 10;
               entities.remove(j); // Remove dead entities.
              projectiles.remove(i); // Remove the projectile that was used to kill the entity.
           }
         }
      }


Below here is the entire class.
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
114  
115  
116  
117  
118  
119  
120  
121  
122  
123  
124  
125  
126  
package level;

import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;

import core.KeyboardInputHandler;
import entity.Alien;
import entity.Entity;
import entity.Player;
import entity.projectile.Bullet;
import entity.projectile.Projectile;

public class Level {
   private int playerScore = 0;
   private int levelsCompleted = 0;
   private int playerShootTimer = 100;
   //private BufferedImage background;
  private Player playerEntity;
   private List<Entity> entities = new ArrayList<Entity>();
   private List<Projectile> projectiles = new ArrayList<Projectile>();
   
   public Level() {
      playerEntity = new Player("Player", 512, 448);
   }
   
   public void update(final KeyboardInputHandler KEY_INPUT) {
      if(entities.size() == 0) {
         // Remove all projectiles from the level before spawning new entities.
        int projectilesSize = projectiles.size();
         if(projectilesSize > 0) {
            for(int i=0;i<projectiles.size();i++) {
               projectiles.remove(i);
            }
         }
         
         // Spawn new entities.
        for(int i=0;i<10;i++) {
            for(int j=0;j<5;j++) {
               entities.add((levelsCompleted > 0 ?  new Alien("Creature - "+i, i * 64 , j * 64, levelsCompleted) : new Alien("Creature - "+i, i * 64 , j * 64)));
            }
         }
         
         // Increase the level counter.
        if(playerScore > 0) {
            levelsCompleted++;
         }
      }
     
      // Check if any bullet has collided with any alien entity. If a bullet has then remove it and remove the entity.
     for(int i=0;i<projectiles.size();i++) {
         for(int j=0;j<entities.size();j++) {
            if(projectiles.get(i).getColissionBox().intersects(entities.get(j).getColissionBox())) {
               playerScore += entities.get(j).getSpeed() * 10;
               entities.remove(j); // Remove dead entities.
              projectiles.remove(i); // Remove the projectile that was used to kill the entity.
           }
         }
      }
           
      // Update the player.
     playerEntity.update(KEY_INPUT);
     
      // Update all entities.
     for(int i=0;i<entities.size();i++) {
         entities.get(i).update();
      }
     
      // Remove projectiles if they're off-screen, if it's not off-screen then update it.
     for(int i=0;i<projectiles.size();i++) {
         if(projectiles.get(i).getIsVisible()) {
            projectiles.get(i).update();
         } else {
            projectiles.remove(i);
         }
      }
     
      // If the user presses the space bar and if the timer is at 10 or above then create a new projectile.
     if(KEY_INPUT.isKeyPressed(KeyEvent.VK_SPACE) && playerShootTimer >= 40) {
         // This requires that the player entity be at index 0 of the entities list.
        projectiles.add(new Bullet(playerEntity.getXPosition() + (playerEntity.getSprite().getWidth () / 2), playerEntity.getYPosition(), true, (2 + levelsCompleted)));
         playerShootTimer = 0;
      } else {
         playerShootTimer++;
      }
   }
   
   public void render(final Graphics g) {
      // Draw the background.
     //g.drawImage(background, 0, 0, background.getHeight(), background.getWidth(), null);
           
     
      // Render player.
     playerEntity.render(g);
     
      // Render entities.
     for(int i=0;i<entities.size();i++) {
         entities.get(i).render(g);
      }
     
      // Render projectiles.
     for(int i=0;i<projectiles.size();i++) {
         projectiles.get(i).render(g);
      }
   }
   
   public boolean isGameOver() {
      boolean tempVar = false;
     
      // Check if the game is over yet.
     for(int i=0;i<entities.size();i++) {
         if(entities.get(i).getYPosition() >= 448) {
            tempVar =  true;
            break;
         }
      }
     
      return tempVar;
   }
   
   // Get methods:
  public int getPlayerScore() {
      return playerScore;
   }
}


Thanks in advance if anyone can see some error that I've made with the loop or something.
Offline bilznatch

Senior Member


Medals: 8
Projects: 2
Exp: 1 year


I'm bad, I'm bad, I'm really... really bad T_T


« Reply #1 - Posted 2013-11-16 00:48:24 »

You're removing the projectile while still checking other entities for collision with it, you need to make sure you move back out to your outer loop after the projectile collides, because it's no longer there, so checking if it collides with other entities crashes it.
rewrite it as:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
// Check if any bullet has collided with any alien entity. If a bullet has then remove it and remove the entity.
     for(int i=0;i<projectiles.size();i++) {
         for(int j=0;j<entities.size();j++) {
            if(projectiles.get(i).getColissionBox().intersects(entities.get(j).getColissionBox())) {
               playerScore += entities.get(j).getSpeed() * 10;
               entities.remove(j); // Remove dead entities.
              projectiles.remove(i); // Remove the projectile that was used to kill the entity.
              break;
            }
         }
      }

there's no chance that projectile will hit any entities, so you break back to your outer loop.
Offline Danny02
« Reply #2 - Posted 2013-11-16 00:58:00 »

also the code is wrong, because everytime you delete a projectile you skip the next
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline bilznatch

Senior Member


Medals: 8
Projects: 2
Exp: 1 year


I'm bad, I'm bad, I'm really... really bad T_T


« Reply #3 - Posted 2013-11-16 01:13:39 »

Yeah, you should always iterate backward through arraylists. Although, isn't it bad practice to remove objects while iterating through arrayLists in general?
Totally didn't even notice that.
Offline opiop65

JGO Kernel


Medals: 154
Projects: 7
Exp: 3 years


JumpButton Studios


« Reply #4 - Posted 2013-11-16 02:20:46 »

Why would it be bad practice? Also, why would you iterate backwards? Never once in my life have I seen anyone do that. ArrayLists are built to be dynamic, you don't need to worry about simple things like that.

Offline bilznatch

Senior Member


Medals: 8
Projects: 2
Exp: 1 year


I'm bad, I'm bad, I'm really... really bad T_T


« Reply #5 - Posted 2013-11-16 02:48:49 »

No, because arraylists lose size when you iterate through forward, and it gets compressed so your list looks like:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
[0]0
[1]1
[2]2
[3]3
[4]4
[5]5
[6]6
[7]7
[8]8
[9]9

so if you remove say, index 6 it'd look like:
1  
2  
3  
4  
5  
6  
7  
8  
9  
[0]0
[1]1
[2]2
[3]3
[4]4
[5]5
[6]7
[7]8
[8]9

so you're effectively skipping the 7, because it's now index 6, instead of index 7.
Offline Jimmt
« League of Dukes »

JGO Kernel


Medals: 131
Projects: 4
Exp: 3 years



« Reply #6 - Posted 2013-11-16 02:51:43 »

If you don't want the size to decrease when removing elements, you should be using an array.
Offline opiop65

JGO Kernel


Medals: 154
Projects: 7
Exp: 3 years


JumpButton Studios


« Reply #7 - Posted 2013-11-16 02:57:49 »

I thought the whole idea of the Arraylist was to be flexible and so you wouldn't have to worry about size constraints. If you're using them to hold a list that is order sensitive, then you shouldn't be. You should be using an array.

Offline namrog84

JGO Ninja


Medals: 46
Projects: 4


Keep programming!


« Reply #8 - Posted 2013-11-16 03:34:06 »

I've run into this issue before and the best solution I've had is instead of calling "remove" inside the for loop, simply add it to
a separate arraylist, such as
ArrayList<entity> removeEntities;

then inside your for loop, just do
removeEntities.add(entities.get(j));


then when you are done with both for loop, immediately afterwards call
entities.removeAll(removeEntitities);
removeEntities.clear();



Some people in thread seem to be confused, in general about arraylist and remove, and moving backwards

imagine we have 4 badguys  (size() is 4)
badguy1 at i = 0;
badguy2 at i = 1;
badguy3 at i = 2;
badguy4 at i = 3;

Then lets say when you are at i = 1; you want to remove badguy2,  sure thats fine, he goes poof he goes away
now because hes gone, we now have
badguy1 at i = 0;
badguy3 at i = 1;
badguy4 at i = 2;
but then you move to end up for loop, and you do i++
so now you are looking at i=2
Which the for loop worked correctly,  the for loop will exit correctly at the end, when i < size() is false.
However now you never had a chance to look at badguy3

So thats why if you call remove() on something that is reflecting the .size() then you need ot call an extra --i; so you look at that i=1 case a 2nd time, because there is a different badguy there

or alternatively, do what bilznatch said and do something like
for(int i = entities.size() - 1; i >= 0; i--)  and thatd fix a lot of the issues.

"Experience is what you get when you did not get what you wanted"
Offline trollwarrior1
« Reply #9 - Posted 2013-11-18 14:24:59 »

Make something like an array of interface called "Action" or something. It should have method called "doAction()" or something. When you want to remove something, add that Action to your arraylist. After you go through all the bullets and aliens, go through all the actions and do what you wanted.

In the other words, remove bullets and/or aliens after you go through entities and bullets lists.

You should also try to put stuff more organized or something. Put the code where you check for collision between bullet and entites into bullet class, so it is more organized.

EDIT:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
public class GameClass {
   
   public static ArrayList<Action> actions = new ArrayList<Action>();
   
   public static ArrayList<Entity> entities = new ArrayList<Entity>();
   
   public void tick() {
     
      for(int i=0;i<entities.size();i++) {
         Entity entity = entities.get(i);
         entity.tick();
      }
     
      for(Action action : actions) {
         action.doAction();
      }
      actions.clear();
     
   }
   
}

public class Entity {
   
   public void remove() {
     
      GameClass.actions.add(new Action() {
         
         public void doAction() {
            GameClass.entities.remove(this);
         }
         
      });
   }
   
   public void tick() {
      // update this entity to your liking. Position, HP or something?
  }
   
}

public interface Action {
   public void doAction();
}
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

Dwinin (23 views)
2014-09-12 09:08:26

Norakomi (56 views)
2014-09-10 13:57:51

TehJavaDev (69 views)
2014-09-10 06:39:09

Tekkerue (34 views)
2014-09-09 02:24:56

mitcheeb (56 views)
2014-09-08 06:06:29

BurntPizza (40 views)
2014-09-07 01:13:42

Longarmx (26 views)
2014-09-07 01:12:14

Longarmx (32 views)
2014-09-07 01:11:22

Longarmx (31 views)
2014-09-07 01:10:19

mitcheeb (39 views)
2014-09-04 23:08:59
List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06

List of Learning Resources
by SilverTiger
2014-07-31 11:54:12

HotSpot Options
by dleskov
2014-07-08 01:59:08
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!