【问题标题】:Detect a 2d collision in C++在 C++ 中检测二维碰撞
【发布时间】:2018-11-30 19:39:12
【问题描述】:

我需要创建一个函数,如果两个精灵之间没有碰撞,则返回一个布尔值,如果有,则返回一个布尔值,我想了很长时间,我找不到确切的解决方案,目标是检测每个像素是否存在碰撞,即 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 给出。 标题的其他三个参数对应于精灵 2。因此,目标是检查何时发生碰撞(在侧面或角落)并从那里建立两个矩形之间的碰撞矩形(重合区域),并设置两个索引,这些索引穿过像素 1 和像素 2(因为每个索引都必须从其对应向量中的不同位置开始)。 问题是我找不到最佳和/或简单的方法来做到这一点并且它有效。如果有人知道任何方法,我将非常感激。

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

#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;
}

【问题讨论】:

  • 像素是图片的离散元素(像素图片元素)。因此,使用浮点数考虑它们是不寻常的。也许您正在处理图像坐标,这些坐标不一定是离散的像素坐标。
  • 是的,float值是为了让运动更流畅,转换就是简单地建立一个static_cast (floor (floatval)) 从而得到对应的像素
  • 看起来大约是所需代码量的四倍。弄清楚你有多少行重叠。找出每个精灵中重叠的第一行和最后一行。然后对列执行相同的操作。然后你就有了一系列可以比较的值,不管谁在谁的左边
  • @TimRandall 问题是,我怎样才能轻松检测到碰撞并检测到碰撞的极限?因为根据它的产生位置,它会有一个值或另一个值,然后有必要查看我为每个向量设置的索引以通过它们。

标签: c++ multidimensional-array 2d collision-detection collision


【解决方案1】:

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

【讨论】:

  • 这很容易,问题是把它放在代码中,因为我需要检查每个角落,而且还有一些方面我需要再次检查,并且我需要为每个方面创建一个不同的索引对于每个向量,我尝试过的所有时间都找不到能够产生碰撞的具体值,因为在一个角落它检测到忽略 alpha 的碰撞,而在另一个角落它没有检测到任何碰撞
  • @YamikaIzumi 我建议你不要花时间写散文,而是用不起作用的代码更新你的问题。
  • @YamikaIzumi - 这不是一个“为我写代码”的网站。我已经告诉过你如何了。将其翻译成代码是你的工作。如果您对此有疑问,请发布 minimal reproducible example 显示导致问题的代码,然后询问有关该代码的特定问题。
  • @JesperJuhl 我将我的代码放入编辑中,我该怎么办?
猜你喜欢
  • 2012-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-02
  • 1970-01-01
  • 2011-06-26
  • 1970-01-01
相关资源
最近更新 更多