1
votes

We are creating a game where there are maps. On those maps, players can walk, but to know if they can walk somewhere, we have another image, where the path is paint.

The player can move by clicking on the map, if the click match with the collider image, the character should go to the clicked point with a pathfinder. If not, the character don't move.

For example, here is a map and its collision path image :

enter image description here enter image description here

How can I know if I've clicked on the collider (this is a png with one color and transparency) in Qt ? I'm using QML and Felgo for rendering so if there is already a way to do it with QML, it's even better, but I can implement it in C++ too.

My second question is how can I do a pathfinder ? I know the algorithms for that but should I move by using pixels ?

I've seen the QPainterPath class which could be what i'm looking for, how can I read all pixels with a certain color of my image and know their coordonates ?

Thanks

1
You could use a line from current position to target position and check all the pixels on that line in your mask (2nd image). To compute pixel (coordinates) on a line, Bresenham's line algorithm comes into my mind. (And, I was always thinking such knowledge is obsolete nowadays...) ;-)Scheff's Cat
Sorry, I forget to tell you how the player should move (i've edited my post). The problem of your algorithm is that my player can only move in a line, and it doesn't allow to move with a path. Finally, my question is just how can I read pixels of an image and convert them to coordonate with Qt. I don't want a path algorithm, I know some of them (but I take tips with pleasure)Ephesiel
what about QImage::pixel()?folibis
@folibis After reading the documentation, it appears that used QImage::pixel() isn't recommended for a massive manipulation. But I would like to create a map of pixels for my pathfinder. So I need to check all pixels ! If I do it only at start, is it considered as "a massive manipulation" ? The documentation recommend to use QImage::constBits() but it returns a uchar of the first pixel and I don't know how to check all pixel color value with that...Ephesiel

1 Answers

0
votes
  • QML interface doesn't provide efficient way to resolve your task. It should be done at C++ side.
  • To get image data you can use:
    • QImage to load image
    • Call N times QImage::constScanLine, each time read K pixels. N equals to image height in pixels, K equals to width.

How to deal with returned uchar* of QImage::constScanLine?

You should call QImage::format() to determine pixel format hidden by uchar*. Or you can call QImage::convertToFormat(QImage::Format_RGB32) and always cast pixel data from uchar* to your custom struct like PixelData:

#pragma pack(push, 1)
struct PixelData {
   uint8_t padding;
   uint8_t r;
   uint8_t g;
   uint8_t b;
};
#pragma pack(pop)

according to this documentation: https://doc.qt.io/qt-5/qimage.html#Format-enum

Here is compilable solution for loading image into RAM for further effective working with it's data:

#include <QImage>


#pragma pack(push, 1)
struct PixelData {
   uint8_t padding;
   uint8_t r;
   uint8_t g;
   uint8_t b;
};
#pragma pack(pop)


void loadImage(const char* path, int& w, int& h, PixelData** data) {
    Q_ASSERT(data);

    QImage initialImage;
    initialImage.load(path);
    auto image = initialImage.convertToFormat(QImage::Format_RGB32);

    w = image.width();
    h = image.height();
    *data = new PixelData[w * h];

    PixelData* outData = *data;

    for (int y = 0; y < h; y++) {
        auto scanLine = image.constScanLine(y);
        memcpy(outData, scanLine, sizeof(PixelData) * w);
        outData += w;
    }
}


void pathfinder(const PixelData* data, int w, int h) {
    // Your algorithm here
}


void cleanupData(PixelData* data) {
    delete[] data;
}


int main(int argc, char *argv[])
{
    int width, height;
    PixelData* data;

    loadImage("D:\\image.png", width, height, &data);
    pathfinder(data, width, height);
    cleanupData(data);

    return 0;
}

You can access each pixel by calling this function

inline const PixelData& getPixel(int x, int y, const PixelData* data, int w) {
    return *(data + (w * y) + x);
}

... or use this formula somewhere in your pathfinding algorithm, where it could be more efficient.