The problem I see with your approach is that it doesn't scale very well. For every object, you are storing relations with all the objects that collide with it. If you only have 2 players and a 10 proyectiles, it will work ok. But when that number increases to, say, 20 players and 100 proyectiles, then the number of relations increases exponentially. It'll gradually run more slowly and consume more memory when the number of players increases.
You would be better off by organizing your objects into "groups". And then adding collision/non-collision relationships between each object and those groups. The memory consumption will be slower, and the checks will be faster.
Box2D has a fairly flexible system set up for that.
First, there's categories and masks:
- Shapes can have up to 16 "categories" (it's really a 16-bit mask). By default, they are on category "1"
- Shapes can also have a "mask" that defines with what categories they can collide. By default, they collide with category "1" only.
Then, there's also groups. A group is an integer.
- Two shapes with the same group will always collide, if the group is positive.
- Two shapes with the same group will never collide, if the group is negative.
- Group rules override mask and category rules.
With these two things, the question "do these two objects collide?", filtering is very fast (a bitmask operation and an integer comparison) and has a very small memory footprint (4 bytes per object).
In your example:
- Players would have category 1, and mask {1,2} (so they collide with all projectiles by default)
- Projectiles would have category 2, and mask {1} (they only collide with players)
- Players and projectile of team 1 would all be in group -1, and team 2 would have the group -2. This way, friendly fire would not happen.
The most recent tutorial that I could find is from 2009 - here it is:
http://www.emanueleferonato.com/2009/10/01/introducing-box2d-filtering/
You can also browse the box2d manual - scroll down until it says "Filtering"