Разобрать карту тайлов в эффективные горизонтальные и вертикальные ограничивающие рамки - PullRequest
1 голос
/ 18 сентября 2011

Я работаю над простой платформерной игрой на C ++, все работает отлично, за исключением того, что я хочу сгруппировать плитки в ограничивающие рамки, чтобы иметь меньше проходов физической функции (я нацеливаюсь как на ПК, так и на встроенные устройства, так чтовсе о скорости).

Следующая функция загружает простой формат карты: "[char * header] [char bytesize] [bytesize w] [bytesize h] [char tw] [char th] [char * map] "Затем он читает массив как 2d карту и группирует вертикальные линии, когда это возможно.

Вопрос в том ... может ли кто-то показать мне, как сгруппировать эти плитки в эффективныеограничивающие рамки на вертикальной и горизонтальной оси?

Вот изображение, которое поможет объяснить, я знаю, что моя грамматика и орфография ужасны: http://thetooth.name/dev/blocks_bic.png

    void Environment::load_map(char* mapPath){
        cl("Loading Map: %s ", mapPath);

        FILE* mapFile = fopen(mapPath, "rb");
        FILE* mapInfoFile = fopen(strcat(substr(mapPath, 0, strlen(mapPath)-3), "bmd"), "rb");

        if (mapFile == NULL || mapInfoFile == NULL)
        {
            cl("[ERROR]\n");
            throw KLGLException("Error loading map file!");
            return;
        }

        size_t wordSize;
        char tBuffer[8] = {};
        int w = 0;
        int h = 0;
        int tileWidth = 0;
        int tileHeight = 0;

        fread(tBuffer, 1, 7, mapFile);
        if (strcmp(tBuffer, "STME1.0"))
        {
            cl("[BADHEADER]");
        }

        fill_n(tBuffer, 8, NULL);
        fread(tBuffer, 1, 1, mapFile);
        if (!strcmp(tBuffer, "B"))
        {
            wordSize = sizeof(char);
        }else{
            wordSize = sizeof(int);
        }

        fseek(mapFile, 8, SEEK_SET);
        fread(&w, wordSize, 1, mapFile);
        fread(&h, wordSize, 1, mapFile);
        fread(&tileWidth, 1, 1, mapFile);
        fread(&tileHeight, 1, 1, mapFile);

#define lvLookup y*w+x
        fill_n(mapData, (w*h)+1, '\0');
        fill_n(mapMask, (w*h)+1, '\0');

        // Read files into memory... back to front and inside out...
        for(int y = 0; y < h; y++){
            for(int x = 0; x < w; x++){
                fread(&mapData[lvLookup], 1, 1, mapFile);
                fread(&mapMask[lvLookup], 1, 1, mapInfoFile);
            }
        }

        fclose(mapFile);
        fclose(mapInfoFile);

        // Parse map data into are geometry vectors
        for(int x = 0; x < w; x++){
            for(int y = 0; y < h; y++){
                if(mapData[lvLookup] > 0){
                    int xl = x;
                    int yl = y;
                    while(mapData[yl*w+x] != 0/* && mapMask[yl*w+x] == 0*/){
                        yl++;
                    }
                    platforms->push_back(Platform(x*tileWidth, y*tileHeight, 1*tileWidth, (yl-y)*tileHeight, lvLookup, mapData, mapMask));
                    y = yl-1;
                }
            }
        }
        cl("[OK]\n");
    }

Спасибо заранее!

1 Ответ

0 голосов
/ 18 сентября 2011

Это немного некрасиво, но я думаю, что это должно работать как отправная точка.Он работает путем сканирования слева направо, сверху вниз, чтобы найти одинаковые столбцы.Сложной частью является отслеживание последовательных завершенных вертикальных блоков и вывод «правильных» ходов.

void find_bounds()
{
    int startx = 0;
    char last = mapData[0];
    for (int x = 0; x < w; x++) {
        int starty = 0;
        for (int y = 0; y < h; y++) {
            char c = mapData[x+y*w];
            if (c != last) {
                if (starty == 0) {
                    // finish last run of complete vertical blocks
                    if(startx != x) { 
                        // it ran more than one column, output those first
                        span(last, startx, 0, x-1, h-1);
                        startx = x;
                    }
                    // and a run from the start of this column
                    span(last, x, 0, x, y);
                } else {
                    // a run within a column
                    span(last, x, starty, x, y);
                }
                last = c;
                starty = y;
            }
        }
        // had a run withing this column or processing last column, finish it up
        if (starty || x == w-1) {
            span(last, x, starty, x, h-1);
            startx= x + 1;
        }
    }
}

Набор тестов (первые два должны соответствовать второму и третьему случаям на вашей иллюстрации):

#include <iostream>
#include <vector>
using namespace std;

const int w = 8, h = 8;
char mapData[w*h+1] = 
#if 1
"xxxxxxxx"
"xxxxxxxx"
"xxxxxxxx"
" xxxxxxx"
"xxxxxxxx"
"xxxxxxxx"
"xxxxxxxx"
"xxxxxxxx"
#elif 0
"xxxxxxxx"
"xxxxxxxx"
"xxx xxxx"
"xxxxxxxx"
"xxxxxxxx"
"xxxxxxxx"
"xxxxxxxx"
"xxxxxxxx"
#else
"xxxxxxxx"
"xx xxxxx"
"xxxxxxxx"
"xx xxxxx"
"xxxx xxx"
"xxxxxxxx"
"xxxxxxxx"
"xxxxxxxx"
#endif
;

void span(char type, int x0, int y0, int x1, int y1)
{
    if (!(x0 == x1 && y0 == y1))
        cout << type << " " << x0 << ", " << y0 << " ->  " << x1 << ", " << y1 << "\n";
}

int main()
{
    find_bounds();
}
...