views:

134

answers:

3

Hi all. I am developing a 2D grid based sim game. Progress is good. Been cracking out code for the last few days really well, and I've been having some issues today.

I build two rooms, set the door position, and spawn a person. The person has the 2 room types that they must visit in order to be cured (It's a remake of Theme Hospital). I click the spawn button, Person moves onto the grid from off screen, and then when the spawn is finished, they get their first path to the first room, then second, and then back to the ending spawn point.

When I say the spawn point, I mean the point off screen / off grid, when I say the ending spawn point, I mean the point where the person is when the spawn cycle is finished, and they are fully on screen / grid.

The problem now comes, what to do with the "person" (which is an object in its own right), is finished with? Should I simple set a boolean so they are no longer "active" but data on them remains? I wasn't sure, so I tried to just remove them from the ArrayList of people objects they were being held in.

I did this by assigning a number value to each person on creation which was the same as their new position in the ArrayList, and then when removing them, using that number. I know that in itself is floored, but I'm only testing with 1 person right now. If anyone can give me some help on that, fantastic! But I suppose that is more a sub question.

When the person is to be removed, they are, and I check the size of the arraylist, and then I get the following error... "Exception in thread "AWT-EventQueue-0" java.util.ConcurrentModificationException"

I did some researching and I understand this is to do with synchronisation of objects in different threads, but I'm not sure that I have more than one thread. I do have a single timer, and I don't think the people ArrayList is accessed elsewhere.

Any Thoughts? Ideas? Suggestions? Comments on this?

Thanks in advance!

(I will soon post a video and update this question with a link to it)

A: 

One of the more common reasons for this problem is because you can not modify an ArrayList while you are iterating over it.

Also, since you have a GUI, you have at least two threads. Swing and AWT run on a separate thread. So if the GUI is directly accessing the ArrayList, there might be some problems there.

But without code, it's not possible to tell for sure what the problem is or might be.

Thomas Owens
What? I thought both Swing and AWT work off of the Event Dispatch Thread.
Chris Jester-Young
Ah yeh. Hum.What I was doing was on each "tick" of the game, calling repaint after the data manipulation calls, which would then cycle through each of the people and re drawing them with the new position.I would past some code, but there is a lot, and I don't really know how much I should put up or not. Plus the section in question is rather messy and needs a clean up... once I get the last bit to work!
Relequestual
Chris: They do. However, everything else is on a separate thread.
Thomas Owens
+1  A: 

Just a wild guess due to the lack of any code excerpts, but most probably your rendering is iterating through the ArrayList on Swing's thread, while you another thread (the timer I guess?) tries to remove the person from the list.

If that's the case, one way to go is to have Swing remove the person from the list (between two renderings) as:

// peopleArray and personInstance should be final
Runnable removePersonTask = new Runnable() {
     public void run() {
         peopleArray.remove(personInstance).
     }
 };

SwingUtilities.invokeLater(removePersonTask).
Zed
I wasn't really sure how much code to put up. Sorry.Your guess is right though. I shall indeed try this out.Now you say that, could I in effect set a boolean value for the person to be removed, and then during the swing thread, check if that boolean is true, and if so remove the person from the list?
Relequestual
You could, but then still you would have to start a removeInvalidatedPersonTask to remove that element. Also then you will have to change all your person related code to not only iterate through the list but also check if the person is valid...
Zed
Ah, good point. It's already rather crazy as it is!I shall be back in a day or so if I have any problems with this. Thanks
Relequestual
+2  A: 

Typically I give every person or entity or whatever a boolean field called isMarkedForDeletion. Then during the main loop, they will either be told to update(), or if they are marked for deletion their index will be added to a deletion list. Once you have the deletion list all populated, you can iterate through the deletion list and remove those objects from the main list. Alternatively you can just iterate backwards and pull from the tail end of the list.

This may or may not explain your ConcurrentModificationException - I've never gotten them when working with ArrayList's before. However, I've gotten them from LinkedList's and it was precisely for the reason you described and had nothing to do with threads. The actual cause was using an Iterator. The following will cause a ConcurrentModificationException:

for (Iterator i = list.iterator(); i.hasNext();)
{
    Person o = i.next();

    o.update();

    if (list.isMarkedForDeletion())
    {
        list.remove(o);
    }
}

This will not cause an Exception:

ArrayList deletedObjects = new ArrayList();
for (Iterator i = list.iterator(); i.hasNext();)
{
    Person o = i.next();

    o.update();

    if (list.isMarkedForDeletion())
    {
        deletedObjects.add(o);
    }
}

for (int i = 0; i < deletedObjects.size(); i++)
{
    list.remove(deletedObjects.get(i));
}

Perhaps the simplest way to do it, will not cause an Exception:

for (int i = list.size()-1; i >= 0; i--)
{
    Person o = list.get(i);

    if (o.isMarkedForDeletion())
    {
        list.remove(i);
    }
    else
    {
        o.update();
    }
}
Eli
Thankyou. I now think I understand why I have the error. I was trying to remove an item from the ArrayList while iterating through it. I don't know why I didn't see this as a problem before! I shall try correct my code and let you know.
Relequestual
Great, I'm glad that worked. Same problem boggled me for a while, because the explanation of the ConcurrentModificationException totally points you in the wrong direction.
Eli