使用最小位数从冲突对列表创建冲突位掩码

时间:2018-03-01 03:59:17

标签: c++ compression bitmask

要确定一对对象 - ab - 是否可以相互碰撞,大多数物理引擎(例如引用12)使用以下内容公式: -

((a.m1 & b.m2) !=0) && ((a.m2 & b.m1) !=0)

上述公式中的& "和" 位掩码操作。

如果我有各种类型的实体,为它们创建位掩码的简单方法是定义碰撞对列表

碰撞对列表的示例: -

  • player可能会与另一个player
  • 发生冲突
  • tree可能会与bullet
  • 发生冲突
  • tree可能会与另一个tree
  • 发生冲突
  • bullet可能会与另一个bullet
  • 发生冲突

要计算m1m2,我会将m1指定为1,2,4,8,...到每种类型的实体。
最后,我为每对执行 "或" 操作(请参阅下面的makeItCollide())。

以下是代码(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
}

有效。 但是,我非常浪费地使用比特。 (1种1位)
如果我有64种++类型,那就有问题了。

问题:
如何计算m1&amp;来自任何一般碰撞对列表m2来实现最小位数?

解决方案不需要拥有完整的代码 换句话说,只是一个粗略的指南可能非常有用。

编辑(根据dempzorz的评论澄清)
上例中的一个更好的解决方案可以是: -

  • air.m1 = 0,air.m2 = 0
  • player.m1 = 1,player.m2 = 1
  • tree.m1 = 2,tree.m2 = 3
  • bullet.m1 = 2,bullet.m2 = 3

此解决方案仅使用m1的2位和m2的2位 这也证明了我的算法有多差(4 + 4位)。

1 个答案:

答案 0 :(得分:1)

你有一个(对称的)碰撞矩阵:

在代码中使用std::vector<std::bitset>进行简化,而不是使用位域:

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 removed\n";
            return;
        }
        ++index;
    }
    std::cout << "No more simplications\n";
}

让我们测试一下你的样本:

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

Demo