views:

67

answers:

3

In Java (Swing), say I've got a 2D game where I have various types of entities on the screen, such as a player, bad guys, powerups, etc. When the player moves across the screen, in order to do efficient checking of what is in the immediate vicinity of the player, I would think I'd want indexed access to the things that are near the character based on their position.

For example, if player 'P' steps onto element 'E' in the following example...

| | | | | |
| | | |P| |
| | |E| | |
| | | | | |

... would be to do something like:

if(player.getPosition().x == entity.getPosition().x && 
              entity.getPosition.y == thing.getPosition().y)
{
    //do something
}

And thats fine, but that implies that the entities hold their positions, and therefor if I had MANY entities on the screen I would have to loop through all possible entities available and check each ones position against the player position. This seems really inefficient especially if you start getting tons of entities.

So, I would suspect I'd want some sort of map like

Map<Point, Entity> map = new HashMap<Point, Entity>();

And store my point information there, so that I could access these entities in constant time. The only problem with that approach is that, if I want to move an entity to a different point on the screen, I'd have to search through the values of the HashMap for the entity I want to move (inefficient since I dont know its Point position ahead of time), and then once I've found it remove it from the HashMap, and re-insert it with the new position information.

Any suggestions or advice on what sort of data structure / storage format I ought to be using here in order to have efficient access to Entities based on their position, as well as Position's based on the Entity?

A: 

inefficient since I dont know its Point position ahead of time
Am I correct, that entity object doesn't have position information in it? I would suggest adding it. Or, otherwise, you can have map of current entity positions Map<EntityIdType, Point> and fetch position first. Nothing fancy.

Nikita Rybak
Either you've just restated the problem at hand, or you didn't understand the question fully, because there's no solution provided here. Based on the 2 proposed methods in the original post, the object either does or does not contain the position information. Similarly, the Map depends on which approach was taken. Either way the original problem of finding middle ground is nowhere in your answer.
byte
+1  A: 

Space partitioning could be effective.

You can either do fixed divisions, such as a uniform grid, or a weighted grid if you except there to be hot spots on your map where things gets unusually clustered. For each occupied partition, create a container of all entities it contains.

Insertion is constant time. Removal is a practically infinitesimal fraction of n (your total number of entities) assuming n is very large and you've set up your partitions efficiently. Proximity looksups share the same runtime as removals. Still technically O(n) however small the fraction, though. This would become apparent if a partition ever become unusually crowded.

To get a list of all entities within x units of an entity, you must first get a list of all partitions spanned by a 2x wide square square centered on your entity. If you use a grid partition, this is fairly trivial. Next, you loop through all entities in those partitions and return each one with a distance of x or less to the entity in question.

A more complicated method of partitioning is to dynamically partition space in a tree, ensuring that no partition can contain more than a given number of entities. If a partition becomes full, you divide it along the spacial mean and create two two space partitions such that each one holds half of the original partition's entities. This makes insertions and lookups have logarithmic runtime since you can no longer discover the desired partitions in constant time, but removals become constant time given the capped partition populations.

Gunslinger47
Thanks for the tips, I'll research space partitioning more.
byte
I types up two game board implementions for holding 1,000,000 entities randomly added to a 1920x1080 area. Using a 1080x1920 array of containers, I had 0.004 ms for insertion, 0.003 ms on removal and 0.004 ms to request a list of all containers in a 3x3 area. Using dynamic binary space partitioning, I had 0.007 ms inserts, 0.003 ms removals and 0.007 ms queries for partitions intersecting a 3x3 region. Performance and memory usage on the BSP should be even better for non-uniformly distributed entities.
Gunslinger47
+3  A: 

If there is a one-to-one mapping between Entity and Point, and you want to be able to map in both directions, then a bimap is the most natural data structure.

Guava has a BiMap<K,V> implementation, which supports a BiMap<V,K> inverse() view operation. It's only a view, so it's not costly at all.

Alternatively you can manage your own Map<Entity,Point> and Map<Point,Entity>, but that'd be reinventing the wheel.

polygenelubricants