0

Right now I'm experimenting with some basic game concepts in Java. At the moment, all it really does is display two boxes: one that the player can move with the arrow keys, and an "enemy" that just jitters around randomly. Right now, I'm fixing up the player's ability to shoot little squares in the direction of the mouse whenever they click the left mouse button. As it's structured right now, I have four classes - a JPanel that holds the "game" logic, a JFrame that holds that panel, an Entity class which is just a simple representation of a physical object with a position, size, and speed with methods for moving it, and a Projectile class that extends the Entity class with a special move method that moves it one step along a path calculated from the initial and destination points given to the Projectile's constructor.

The problem I'm having is trying to update the position of the projectiles. I have a timer running to update the positions of non-player controlled objects, and the actionPerformed() method of the JPanel has to call every existing projectile's move() method. Right now, when a projectile is created I just put it into a Projectile array with an arbitrarily large size, making sure to start back at [0] when the array is full. The actionPerformed() method can safely act on this array concurrent with the mouse action listener, but since I'm working on this more to learn than to settle with a simple solution that works, I'm wondering if there's a better way to do this than just having an array with size [999]. I tried using an ArrayList at first, but obviously ended up with concurrent access errors. I tried queueing projectiles in an array and then adding them to the ArrayList in the actionPerformed() method, but this gave me null pointer errors.

(TLDR) So my question: Do any of the Java containers (set, map, queue, etc) support concurrent access? I don't think I need a container where order matters, since I have to iterate over every element in the container, I just need a container of a dynamic size that allows one thread to add objects and another to remove/call objects concurrently.

drm
  • 1
  • 1
  • You can use a `CopyOnWriteArrayList` for that – fge Mar 23 '14 at 01:17
  • 2
    Check out all the classes in the [java.util.concurrent](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/package-summary.html) package. – jaco0646 Mar 23 '14 at 01:18
  • That's what I was thinking about, but I wasn't sure if that was a popular choice for this problem or not. Is the performance cost the Java documentation points out ever noticeable? – drm Mar 23 '14 at 01:20
  • 2
    Look to the _Concurrent_ collections rather than the _CopyOn_ collections, for performance. – jaco0646 Mar 23 '14 at 01:29

2 Answers2

0

"I'm wondering if there's a better way to do this than just having an array with size [999]. I tried using an ArrayList at first, but obviously ended up with concurrent access errors."

You can use an ArrayList. You are probably getting a ConcurrentModificationException because you may be trying to remove an object from the ArrayList while looping through it. You can see a similar question here.

The solution would be to use an Iterator instead of a loop, to iteration through the objects.

From Iterator API:

  • Iterators allow the caller to remove elements from the underlying collection during the iteration with well-defined semantics.

Then you can use the Iterator.remove() method, when you want to remove an object from the ArrayList. So say you have Projectiles you have in an ArrayList, you could do this

List<Projectile> projectiles = new ArrayList<>();
...
Iterator it = projectiles.iterator();
while (it.hasNext()) {
    Projectile projectile = (Projectile)it.next();
    if (projectile.hitEnemy()) {
        it.remove();
    }
}

The it.remove() remove the current projectile in the iteration. Something that can't be done in a for each loop, as you would get the ConcurrentModificationException.

You can see more How to use Iterators in The Collection Interface tutorial. You can read more about ConcurrentModificationException in this thread


See this answer where, while iterating through the List in the Timer, if an Asteroid is off the screen, it is removed from the List dynamically through iterator.remove() method.

enter image description here

Community
  • 1
  • 1
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
0

If you're looking for concurrency safe containers, try ConcurrentLinkedQueue or ConcurrentHashMap.

If you find later that you need some inherent ordering to the way you process the entities in the game, you might want to use a PriorityQueue.

BillRobertson42
  • 12,602
  • 4
  • 40
  • 57