0

I'm creating a top-down 2D game.
Classes in question are Level and Entity.

In Level I have a Map, but let's just think of that class as a list of items like walls and other stuff you can imagine will have a body, which is actually a XNA's Rectangle.

Now, in Level's Update function, I'll be putting Entity's function that will resolve all collisions (walls, pickups, other entities, traps, etc), and I am questioning the best way of letting each Entity know what's around him. By doing that I want to achieve the freedom of creating different Entityes such as different players, enemies, bosses... Goal is a good parent class for everything that should feel alive to the player playing the game.

So, I want to get a good performance for this function (that'll resolve collisions), because I plan on making maps that'll have around 1000 different items and many entities, and can't decide how to go about it.
The structure is something like this: Level has a list of items (walls, pickups, traps...) and a list of entities (players, enemies, bosses, pets, mounts, whatever...), and in each update of level I loop trough entities and do Update for each.

Question Do I:
1) send whole list of items to each entity('s update method) and calculate distances from each item and resolve collision
2) calculate closest items to the entity in level's update method and then send smaller list of items to the entity, which will then resolve collision
3) (this I just thought of) pass list of XNA's Rectangles and type of item (that could mean I must make a new class or new function for map class that will return 2 lists: rectangles and item types)
4) pass the whole map, but in a matix (because map will be a grid, not items nor player's rectangles will rotate) of integers that'll have something like "1 for wall, 0 for nothing, 2 for trap, 3 for health-pack, etc). But this will resolve only the map, because other entities won't all be in grid coordinates (wall's positions will be like 32x32, 0x64, etc, and all will be 32x32, but entities won't. They'll be 32x16, and their position may vary. That also crossed my mind just now.

Note that both entities and items will most likely have much more than Rectangle for body. There will be textures, animations, and other basic types of variables for different purpose, and most of them won't be needed for entities collision resolution with that item. When colliding with a wall, entity won't need that items image to resolve collision, but it will need items (lets say) X value if that item is a healt potion.

How would you resolve this so the code is efficient, or how did you resolve this in your game?
I am looking for simpicity and efficiency, and that's what I will be looking for in your answer.

Monset
  • 648
  • 5
  • 25
  • 2
    Obviously computing the pairwise distances won't scale, so you could give a loot at some [spatial indexes](https://en.wikipedia.org/wiki/Spatial_database#Spatial_index). Quad-trees are pretty straightforward (they would map to option 2, I think) – BlackBear May 10 '16 at 17:37
  • 1
    As @BlackBear already pointed out, you need some kind of acceleration data structure. QuadTrees are on option, but might not be the best. A simple grid is probably the easiest and most flexible way. So store a grid (array of grid cells) in your map and add new entities to the according grid cell (they do not need to be grid-aligned). Implement some kind of `GetNeighborsInDistance(position, radius)` in your map that uses this grid and returns a list (or possibly enumerator via `yield return ) of all objects in the given area. Each player can then ask the map for their surrounding entities. – Nico Schertler May 11 '16 at 06:33
  • I will see some tutorials on both topics. If you'd answer my question in answer I'd be happy to mark it as an answer – Monset May 11 '16 at 11:34

1 Answers1

1

I haven't tested this code at all, so if it doesn't work, thats why.

Given that Entity is a struct with the following code,

struct Entity{

Rectangle pos;
Texture2D tex;
bool hasAgency;

public Entity(Rectangle pos, Texture2D tex, bool hasAgency){
this.pos = pos;
this.tex = tex;
this.hasAgency = hasAgency;
}
}

then this should work.

List<Entity> entityList = new List<Entity>//your entities are here

for(int testIndex=0; testIndex<entityList.Count; testIndex++){
    for(int entityBeingTested = 0; entityBeingTested<entityList.Count; entityBeingTested++){
        if(testIndex!=entityBeingTested && entityList[testIndex].hasAgency)
          {
          if(entityList[testIndex].pos.Intersects(entityList[entityBeingTested.pos]))
           //hit logic here
          }
    }
}
Epic
  • 61
  • 1
  • 4
  • This is what I tried first. And it does work, but not fast enough. If I test it on 100 entities vs 1000 walls (its similar to entityclass), game is unplayable ecause it takes too long to do the Intersect function. So I need to reduce number of times that I call that function – Monset May 19 '16 at 22:31
  • @Monset thats the point of the hasAgency field. Agency means that the entity can act or move (such as an enemy). That way, you're only testing every entity that can move against every other entity. You could also try to reduce your entity list by only rendering entities in your field of view. – Epic May 22 '16 at 18:04
  • I don't see how you used *hasAgency* in your code where you are looping trough all entities. – Monset May 22 '16 at 21:45
  • @Monset Sorry, I must have forgotten to add it. The code has been fixed. – Epic May 23 '16 at 00:25
  • +1 for the idea, but still not the best way because the only thing I don't need to check is wall-wall collision, and that is easy because I have wall list and entities list. Also, I need to check all entities because all of them move accept powerups/healt potions/ items on the ground that can be picked up. And your way, I'd chek all of them vs all of them minus one, but with one extra variable that won't do me any good. – Monset May 23 '16 at 11:45
  • @Monset tbh if you're gunna be dealing with 1000 entities, you're gunna get lag. If you find a better way to handle entity collisions, please let me know, because now I'm kind of interested. – Epic May 24 '16 at 22:00
  • 1
    Just a quick one here. How about time share (it works with holidays) .. Do you need to process all your entities at once? If your logic loop is running at 100 frames per second - process half each frame, your entities would get checked every 50 frames per second - still smooth to the eye! – Neil May 24 '16 at 23:30
  • That, I didn't think of... I see the setback there, but, it could work in some wierd way... – Monset May 25 '16 at 12:33