0
votes

I need to create a function that returns a bool that is false if there is no collision between two sprites and true if there is, I was thinking for a long time and I can not find an exact solution, the objective is to detect if there is a collision per pixel, that is if two pixels with the alpha value (from rgba) different than 0 (it is visible) coincide in the same place in the space, the function has the following signature :

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 is a struct with the next form:

struct Vector2
{
  float x;
  float y;
};

pixelPos1 is the position of the upper left corner of the rectangle that contains sprite 1, pixelSize1 is the size (x = width; y = height) of the rectangle that contains sprite 1, pixel1 is a vector that has the rgba values ​​of each pixel of the sprite, they are stored from 4 to 4 so that i contains the amount of r of the pixel i; i + 1 the amount of g of the pixel i; i + 2 the amount of b of the pixel i; i + 3 the amount of alpha of the pixel i, so that if i + 3 is different from 0 is a visible pixel, the size of pixel1 is given by pixelSize1.x * pixelSize1.y * 4. The other three parameters of the header are those corresponding to sprite 2. The objective would therefore be to check when there is a collision (either on the side or corner that is) and from there establish a collision rectangle between both rectangles (the coincident area), and set two indexes that travel pixel1 and pixel2 (since each one will have to start from a different position in its corresponding vector). The problem is that I can not find an optimal and / or easy way to do it and that it works. If anyone knows any way to do it, I would appreciate it very much.

EDIT Here is my code (it doesn't work)

#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;
}
1
Pixels are discreet elements of a picture (pixel <-> picture element). As such, it's unusual to consider them using floating point numbers. Perhaps you are dealing with image coordinates, which aren't necessarily in discreet pixel coordinates.François Andrieux
Yes, the float value is for the movement to be more fluid, the conversion would be simply to establish a static_cast <int> (floor (floatval)) and thus get the corresponding pixelYamika Izumi
It looks like roughly four times as much code as there needs to be. Figure out how many rows of overlap you have. Figure out the first and last row of the overlap in each sprite. Then do the same for columns. Then you've got a range of values you can compare, regardless of who's to the left of whomTim Randall
@TimRandall The problem is, how can I easily detect a collision and detect the limits of the collision? because depending on where it is produced, it will have a value or another and then it would be necessary to see what index I put to each vector to go through them.Yamika Izumi

1 Answers

0
votes

Start by checking if the bounding rectangles of the two sprites overlap. If they don't, great; no collision is possible. If they do overlap, calculate the overlapping rectangle for each sprite and compare pixel by pixel - if pixel a or pixel b is transparent then there is no collision caused by that pixel, if both pixels are non-transparent there is a collision and you are done. If you finish checking all pixels in the overlapping area and there are no collisions you are also done.