首页 > 解决方案 > 在 C++ 中检测二维碰撞

问题描述

我需要创建一个函数,如果两个精灵之间没有碰撞,则返回一个布尔值,如果有,则返回一个布尔值,我想了很长时间,但找不到确切的解决方案,目的是检测是否存在是每个像素的碰撞,也就是说,如果 alpha 值(来自 rgba)不同于 0(可见)的两个像素在空间中的同一位置重合,则该函数具有以下签名:

bool checkPixelCollision(
    const Vector2& pixelPos1, 
    const Vector2& pixelSize1, 
    const vector<uint8_t> pixel1, 
    const Vector2& pixelPos2, 
    const Vector2& pixelSize2, 
    const vector<uint8_t> pixel2);

Vector2 是具有以下形式的结构:

struct Vector2
{
  float x;
  float y;
};

pixelPos1 是包含精灵 1 的矩形左上角的位置,pixelSize1 是包含精灵 1 的矩形的大小(x = 宽度;y = 高度),pixel1 是具有 rgba 值的向量精灵的每个像素,它们从 4 到 4 存储,以便 i 包含像素 i 的 r 量;i + 1 像素 i 的 g 数量;i + 2 像素 i 的 b 数量;i + 3 像素 i 的 alpha 量,因此如果 i + 3 不同于 0 是可见像素,则 pixel1 的大小由 pixelSize1.x * pixelSize1.y * 4 给出。其他三个参数header 是对应于 sprite 2 的那些。因此,目标是检查何时发生碰撞(在侧面或角落)并从那里建立两个矩形之间的碰撞矩形(重合区域),并设置两个通过pixel1和pixel2的索引(因为每个索引都必须从其对应向量中的不同位置开始)。问题是我找不到最佳和/或简单的方法来做到这一点并且它有效。如果有人知道任何方法,我将不胜感激。

编辑 这是我的代码(它不起作用)

#include <algorithm>
#include <stdint.h>
#include <vector>

struct Vector2
{
  float x;
  float y;
};

float clamp(float val, float min, float max) {
    return std::max(min, std::min(max, val));
}

bool checkPixelCollision(const Vector2& pixelPos1, const Vector2& pixelSize1, const vector<uint8_t> pixel1, const Vector2& pixelPos2, const Vector2& pixelSize2, const vector<uint8_t> pixel2) {
    return check(pixelPos1,pixelSize1,pixel1,pixelPos2,pixelSize2,pixel2)||check(pixelPos2,pixelSize2,pixel2,pixelPos1,pixelSize1,pixel1);
}

bool check(const Vector2& pixelsPos1, const Vector2& pixelsSize1, const vector<uint8_t> pixels1, const Vector2& pixelsPos2, const Vector2& pixelsSize2, const vector<uint8_t> pixels2){
    bool res = false;
    if (pixelsPos1.x <= pixelsPos2.x + pixelsSize2.x && pixelsPos1.y <= pixelsPos2.y + pixelsSize2.y && pixelsPos1.x >= pixelsPos2.x && pixelsPos1.y >= pixelsPos2.y) {
        float i = pixelsSize2.x - (pixelsSize1.y*((pixelsPos1.x - pixelsPos2.x + pixelsSize2.x) / pixelsSize1.x));
        float j = pixelsSize2.y - (pixelsSize1.y*((pixelsPos1.y - pixelsPos2.y + pixelsSize2.y) / pixelsSize1.y));
        float ifin = fmin(pixelsSize1.x - pixelsSize2.x, pixelsSize1.x);
        float jfin = fmin(pixelsSize1.y - pixelsSize2.y, pixelsSize1.y);
        float i2 = 0;
        float j2 = 0;
        while (j<jfin-1) {
            int k = floor((pixelsSize2.x*j) + i) * 4 - 1;
            int k2 = floor((pixelsSize1.x*j2) + i2) * 4 - 1;
            if (pixels1[k2 + 3] != 0 && pixels2[k + 3] != 0) {
                res = true;
            }
            if (i < ifin) {
                i = i + 1;
                i2 = i2 + 1;
            }
            else {
                i2 = 0;
                i = pixelsSize2.x - (pixelsSize1.x*((pixelsPos1.x - pixelsPos2.x + pixelsSize2.x) / pixelsSize1.x));
                j = j + 1;
                j2 = j2 + 1;
            }
        }
    }
    else if (pixelsPos1.x <= pixelsPos2.x + pixelsSize2.x && pixelsPos1.y + pixelsSize1.y >= pixelsPos2.y && pixelsPos1.x >= pixelsPos2.x && pixelsPos1.y + pixelsSize1.y <= pixelsPos2.y + pixelsSize2.y) {
        float i = clamp(pixelsSize2.x - (pixelsSize1.x*((pixelsPos1.x - pixelsPos2.x + pixelsSize2.x) / pixelsSize1.x)), 0.0f, pixelsSize2.x);
        float jfin = clamp(pixelsSize1.y*((pixelsPos2.y - pixelsPos1.y+pixelsSize1.y) / pixelsSize1.y), 0.0f, pixelsSize1.y);
        float ifin = fmin(pixelsSize1.x - pixelsSize2.x, pixelsSize1.x);
        float j = 0;
        float i2 = 0;
        float j2 = clamp(pixelsSize1.y - pixelsSize1.y*((pixelsPos2.y - pixelsPos1.y + pixelsSize1.y) / pixelsSize1.y),0.0f, pixelsSize1.y);
        while (j<jfin-1) {
            int k = floor((pixelsSize2.x*j) + i) * 4 - 1;
            int k2 = floor((pixelsSize1.x*j2) + i2) * 4 - 1;
            if (pixels1[k2 + 3] != 0 && pixels2[k + 3] != 0) {
                res = true;
            }
            if (i < ifin) {
                i = i + 1;
                i2 = i2 + 1;
            }
            else {
                i2 = 0;
                i = clamp(pixelsSize2.x - (pixelsSize1.x*((pixelsPos1.x - pixelsPos2.x + pixelsSize2.x) / pixelsSize1.x)),0.0f, pixelsSize2.x);
                j = j + 1;
                j2 = j2 + 1;
            }
        }
    }
    else if (pixelsPos1.x + pixelsSize1.x >= pixelsPos2.x && pixelsPos1.y<= pixelsPos2.y + pixelsSize2.y && pixelsPos1.x + pixelsSize1.x <= pixelsPos2.x + pixelsSize2.x && pixelsPos1.y >= pixelsPos2.y) {
        float ifin = clamp(pixelsSize1.x*((pixelsPos2.x - pixelsPos1.x + pixelsSize1.x) / pixelsSize1.x), 0.0f, pixelsSize1.x);
        float j = clamp(pixelsSize2.y - (pixelsSize1.y*((pixelsPos1.y - pixelsPos2.y + pixelsSize2.y) / pixelsSize1.y)),0.0f, pixelsSize2.y);
        float jfin = fmin(pixelsSize1.y - pixelsSize2.y, pixelsSize1.y);
        float i = 0;

        float i2 = clamp(pixelsSize1.x - pixelsSize1.x*((pixelsPos2.x - pixelsPos1.x + pixelsSize1.x) / pixelsSize1.x), 0.0f, pixelsSize1.x);
        float j2 = 0;
        while (j<jfin-1) {
            int k = floor((pixelsSize2.x*j) + i) * 4 - 1;
            int k2 = floor((pixelsSize1.x*j2) + i2) * 4 - 1;
            if (pixels1[k2 + 3] != 0 && pixels2[k + 3] != 0) {
                res = true;
            }
            if (i < ifin) {
                i = i + 1;
                i2 = i2 + 1;
            }
            else {
                i2 = clamp(pixelsSize1.x - pixelsSize1.x*((pixelsPos2.x - pixelsPos1.x + pixelsSize1.x) / pixelsSize1.x), 0.0f, pixelsSize1.x);
                i = 0;
                j = j + 1;
                j2 = j2 + 1;
            }
        }
    }
    else if (pixelsPos1.x + pixelsSize1.x >= pixelsPos2.x && pixelsPos1.y + pixelsSize1.y >= pixelsPos2.y && pixelsPos1.x + pixelsSize1.x <= pixelsPos2.x + pixelsSize2.x && pixelsPos1.y + pixelsSize1.y <= pixelsPos2.y + pixelsSize2.y) {
        float jfin = clamp(pixelsSize1.y*((pixelsPos2.y - pixelsPos1.y + pixelsSize1.y) / pixelsSize1.y), 0.0f, pixelsSize1.y);
        float j = 0;
        float ifin = clamp(pixelsSize1.x*((pixelsPos2.x - pixelsPos1.x + pixelsSize1.x) / pixelsSize1.x), 0.0f, pixelsSize1.x);
        float i = 0;
        float i2 = clamp(pixelsSize1.x - pixelsSize1.x*((pixelsPos2.x - pixelsPos1.x + pixelsSize1.x) / pixelsSize1.x), 0.0f, pixelsSize1.x);
        float j2 = clamp(pixelsSize1.y - pixelsSize1.y*((pixelsPos2.y - pixelsPos1.y + pixelsSize1.y) / pixelsSize1.y), 0.0f, pixelsSize1.y);
        while (j<jfin-1) {
            int k = floor((pixelsSize2.x*j) + i) * 4 - 1;
            int k2 = floor((pixelsSize1.x*j2) + i2) * 4 - 1;
            if (pixels1[k2 + 3] != 0 && pixels2[k + 3] != 0) {
                res = true;
            }
            if (i < ifin) {
                i = i + 1;
                i2 = i2 + 1;
            }
            else {
                i2 = clamp(pixelsSize1.x - pixelsSize1.x*((pixelsPos2.x - pixelsPos1.x + pixelsSize1.x) / pixelsSize1.x), 0.0f, pixelsSize1.x);
                i = 0;
                j = j + 1;
                j2 = j2 + 1;
            }
        }
    }
return res;
}

标签: c++multidimensional-array2dcollision-detectioncollision

解决方案


首先检查两个精灵的边界矩形是否重叠。如果他们不这样做,那就太好了;没有碰撞是可能的。如果它们确实重叠,则计算每个精灵的重叠矩形并逐个像素进行比较 - 如果像素 a 或像素 b 是透明的,则该像素不会引起碰撞,如果两个像素都不透明,则会发生碰撞并且您是完毕。如果您完成检查重叠区域中的所有像素并且没有碰撞,您也完成了。


推荐阅读