sfml碰撞检测的一个思路(像素点检测)

发布时间 2023-07-18 14:17:05作者: wegret

  因为贴图不一定是一个规则图形,所以抽象出边框、然后用图形边框检测的思路有点困难。

  对于不规则的贴图,我的主要思路是$spriteA$和$spriteB$先判断矩形边框是否重叠,如果重叠,取相交矩形进入像素检测。

 

初步判断重叠

  用sfml的函数 spriteA.intersects(spriteB) 即可,返回一个bool值表示是否重叠。

 

计算相交矩形

  从边出发,很显然交矩形$A\cap B$的边是$A$、$B$八条边中的其中四条。$A\cap B$的顶边是$A$、$B$顶边中的最低一条,$A\cap B$的左边是$A$、$B$左边中的最右一条,剩下两条边同理,因此可以假设存在相交矩形然后计算,之后再计算矩形是否合法(因为已经判断重叠了,所以不需要这一步)。

sf::IntRect getIntersectionInt(sf::FloatRect A, sf::FloatRect B) {
    int top = max((int)A.top, (int)B.top);
    int left = max((int)A.left, (int)B.left);  
    int down = min((int)(A.top + A.height), (int)(B.top + B.height));
    int right = min((int)(A.left + A.width), (int)(B.left + B.width));
    sf::IntRect(sf::Vector2i(left, top), sf::Vector2i(right - left, down - top));
}

 

像素点检测  

  遍历一遍所有像素点,提取出像素点的颜色,可以用 color.Transparent 判断(返回bool值,表示是否透明),也可以用 color.a 判断(返回透明度,颜色的alpha值)。这里我选择用后者:

bool Weapon::isHit(Monster& monster) {
    sf::FloatRect weaponBounds = GetBoundingRect();
    sf::FloatRect monsterBounds = monster.GetBoundingRect();
    if (weaponBounds.intersects(monsterBounds) == false)    // 如果矩形不重叠
        return false;
    sf::Image weaponImage = GetSprite().getTexture()->copyToImage();
    sf::Image monsterImage = monster.GetTexture()->copyToImage();

    sf::IntRect intersection = getIntersectionInt(weaponBounds, monsterBounds);        // 计算两个矩形的交叠矩形
    for (int x = intersection.left; x <= intersection.left + intersection.width; x++)    // 遍历交叠矩形的像素点
        for (int y = intersection.top; y <= intersection.top + intersection.height; y++) {
            // 注意:Image本身没有position,因此要用相对位置
            sf::Color colorA = weaponImage.getPixel(x - GetSprite().getPosition().x, y - GetSprite().getPosition().y);    
            sf::Color colorB = monsterImage.getPixel(x - monster.GetPosition().x, y - monster.GetPosition().y);
            if (colorA.a > 0 && colorB.a > 0)    // 如果该点两个sprite都不透明,即为重叠,碰撞成立
                return true;
        }
    return false;
}