You can optimize this using spatial partitioning. The basic idea ist that you only compare those objects with each other which are within areas which are close enought to have a chance to collide.
- Divide your game world into sections.
- Store those sections in a data-structure optimized for directly accessing a section at a specific location. When your sections are a square grid, then you can use a 2-dimensional array. When your sections are irregular, then you might want to use something like a BSP tree.
- Add a list of objects to each section which represents the units which currently occupy it.
- When an object moves across a section boundary, remove it from the list of the old section and add it to the list of the new section. If your objects are large enough to overlap multiple areas, then it might make sense to allow it to be on the lists of multiple areas.
- If you want to get all objects in a given attack area:
- Determine which sections are completely overlapped by the area. All objects on their lists are potential targets. Accurate collision detection for these objects is unnecessary. You already know that they are affected, because anything which touches this section is affected.
- Determine which sections are only partially overlapped. You have to do a proper collision detection with the objects on their lists to determine whether or not they are affected.
- Any sections not touched by the area can be ignored. This is where most of the performance savings come from.
- If you allow objects to be in multiple sections at once, remove duplicate from the list of potential targets.