The question is published on by Tutorial Guruji team.
To determine whether a pair of object – a
and b
– can collide with each other, most physics engine (e.g. reference 1,2) uses the following formula :-
((a.m1 & b.m2) !=0) && ((a.m2 & b.m1) !=0)
The &
in the above formula is “and” bit mask operation.
If I have various types of entity, an easy way to create bit mask for them is defining Collision Pair List.
An example of Collision Pair List:-
player
can collide with anotherplayer
tree
can collide withbullet
tree
can collide with anothertree
bullet
can collide with anotherbullet
To calculate m1
and m2
, I assign m1
as 1,2,4,8,...
to every type of entity.
Finally, I do the “or” operation for each pair (see makeItCollide()
below).
Here is the code (coliru demo):-
#include <iostream> #include <string> class Mask{ public: int m1=0; public: int m2=0; }; void makeItCollide(Mask& mask1,Mask& mask2){ mask1.m2=mask1.m2|mask2.m1; mask2.m2=mask2.m2|mask1.m1; } int main(){ Mask player; Mask tree ; Mask bullet; Mask air ; int run=1; player.m1=run;run*=2; //1 tree .m1=run;run*=2; //2 bullet.m1=run;run*=2; //4 air .m1=run;run*=2; //8 makeItCollide(player,player); makeItCollide(tree ,bullet); makeItCollide(tree ,tree); makeItCollide(bullet,bullet); //test : //(tree.m1 & bullet.m2 != 0) && (tree.m2 & bullet.m1 != 0) --> true //(player.m1 & air.m2 != 0) && (player.m2 & air.m1 != 0) --> false }
It works.
However, I use bits very wastefully. (1 bit for 1 type)
It would be problematic if I have 64++ types.
Question:
How to calculate m1
& m2
from any general Collision Pair List to achieve minimum amount of bits?
A solution doesn’t need to have full code.
In other words, just a rough guide could be very useful.
Edit: (clarify according to dempzorz’s comment)
One of a better solution in the above example can be :-
air.m1
=0 , andair.m2
=0player.m1
=1 , andplayer.m2
=1tree.m1
=2 , andtree.m2
=3bullet.m1
=2 , andbullet.m2
=3
This solution uses just 2 bits for m1
and 2 bits for m2
.
It is also an evidence of how poor my algorithm is (4+4 bits).
Answer
You have a (symmetrical) matrix of collision:
Let use std::vector<std::bitset>
in code for simplification and instead of bitfield:
template <std::size_t N> void Simplify(const std::vector<std::bitset<N>>& m) { int index = 1; for (const auto& b : m) { std::bitset<4> res; for (std::size_t i = 0; i != b.size(); ++i) { if (b[b.size() - 1 - i]) { res |= m[i]; } } if (res == b && b.count() != 1) { std::cout << index << "th type can be removedn"; return; } ++index; } std::cout << "No more simplicationsn"; }
Let’s test it with your sample:
const std::vector<std::bitset<4>> m4 = { std::bitset<4>{"1000"}, // player std::bitset<4>{"0110"}, // tree std::bitset<4>{"0110"}, // bullet std::bitset<4>{"0000"}, // air }; Simplify(m4); // 2th type can be removed const std::vector<std::bitset<4>> m3 = { std::bitset<4>{"100"}, // player std::bitset<4>{"010"}, // tree/bullet std::bitset<4>{"000"}, // air }; Simplify(m3); // 3th type can be removed const std::vector<std::bitset<4>> m2 = { std::bitset<4>{"10"}, // player std::bitset<4>{"01"}, // tree/bullet }; Simplify(m2); // No more simplifications