Consider that I have a symmetrical relationship matrix, similar to this: 
Except that each “outcome” is a small piece of code.
My scenario: I have a bunch of Entity objects that “collide” with eachother. Each entity has a CollisionType value (an enum). In the design, a relationship matrix exists which describes how the entities behave when different CollisionTypes meet each other.
I’m wondering: How would I represent the relationships, and also implement logic on top of it, in an clean and high-performance manner which is easy to add new CollisionTypes to? In my mind it looks something like a 2D Switch statement.
Example (poor) solution:
void CollideEntities( Entity e1, Entity e2 ) {
CollisionType t1 = e1.GetCollisionType();
CollisionType t2 = e2.GetCollisionType();
// perform basic logic based on t1 & t2
if ( (t1 == COL_SOLID && t2 == COL_SQUISHY) || (t1 == COL_SQUISHY && t2 == COL_SOLID) ) {
// do stuff..
} else if ( (t1 == COL_SOLID && t2 == COL_DAMAGE) || (t1 == COL_DAMAGE && t2 == COL_SOLID) ) {
// do other stuff..
} // and so on...
}
Many potential solutions are apparent to me, but none of them strike me as particularly clean or efficient or easy to add new types to…
Try this:
Your question is an interesting one. As you have observed, one need only store the upper or the lower triangle of the matrix, not both.
But what’s the
(b*(b-1))/2about, you ask? Answer: it comes of the curious arithmetical fact that 0 + 1 + 2 + … + (b-1) == (b*(b-1))/2 (try it).Of course, my sample code could stand some improvement. For one thing, for some reason (advice is requested), my code fails when it uses a
std::vector<bool>, so I have used astd::vector<int>as a workaround. For another, it does not include proper handling for the casei == j. What it does do however is to convey the essential technique. You can fill out details at your discretion.(Update: It has later occurred to my why the
std::vector<bool>fails. It fails becausestd::vector<bool>is implemented as an array of bits, whereas a single bit cannot be an lvalue because it has no address of its own. With clever coding, by having theoperator()()return a manipulator of some specially defined type, one could probably finesse the problem without alteringmain(), but it is probably easiest just to define and use aset()member function if the<bool>is what we want to use.)