使用sfml绘制图块地图

问题描述 投票:1回答:2

因此,我一直试图创建一个'Map'类来处理窗口上我的地图的绘制,但是在将所有地图绘制到屏幕上时遇到了问题。

[这是我的问题:比方说,我有一张5层的10 * 10瓷砖地图,总计10 * 10 * 5 = 500瓷砖(当然,实时情况下,可能会有10倍以上的瓷砖更糟糕的是)...,它存储在3d数组[layer] [row] [col]或chars中,每个char代表我的Sprite瓷砖图上的索引所以我创建了一个'SpriteSheet'类来处理我的Sprite工作表,并通过索引spriteSheet->GetSubSprite(idx)从工作表中获取每个Sprite。所以最后我要为每个子画面调用Draw(spriteSheet->GetSubSprite((int)mapArray[i][j][k]))之类的东西,每一个游戏圈,所以可以说我的游戏以60 fps的速度运行,并且我要绘制500个图块:游戏的目标是绘制500 * 60 = 30,000( !)每秒平铺...

所以您可以看到我这里有点问题...?有人知道如何在速度上充分改善这一点吗? (当然,对我当前的结构进行任何形式的改进都是很幸运的)。

所以,以防万一,这是我的SpriteSheet.cpp和我的Map.cpp文件,我知道我有很多设计错误,但请专注于我的问题,设计还远远没有完成。


#include "Map.h"

sz::Map::Map(std::string path, std::string name, std::string image) : Tmx::Map() {
    ParseFile(path);

    if (HasError()) {
        printf("error code: %d\n", GetErrorCode());
        printf("error text: %s\n", GetErrorText().c_str());

        system("PAUSE");
    } 
    else {
        mapArray = new unsigned char**[GetNumLayers()];
        for(int i = 0; i < GetNumLayers(); i++) {
            mapArray[i] = new unsigned char*[GetLayer(i)->GetHeight()];
            for(int j=0; j<GetLayer(i)->GetHeight(); j++) {
                mapArray[i][j] = new unsigned char[GetLayer(i)->GetWidth()];
                // [layer][row][col]
            }
        }
        //load the array
        for (int i = 0; i < GetNumLayers(); ++i) {

            // Get a layer.
            const Tmx::Layer *layer = GetLayer(i);

            for (int y = 0; y < layer->GetHeight(); ++y) {
                for (int x = 0; x < layer->GetWidth(); ++x) {
                    // Get a tile global id.
                    mapArray[i][x][y] = (char)layer->GetTileGid(x, y);
                    //printf("%3d", mapArray[i][x][y]);
                    /* need to fix later on
                    /****************************
                    // Find a tileset for that id.
                    const Tmx::Tileset *tileset = FindTileset(layer->GetTileGid(x, y));
                    if (layer->IsTileFlippedHorizontally(x, y)){
                        printf("h");
                    }else{
                        printf(" ");
                    }
                    if (layer->IsTileFlippedVertically(x, y)){
                        printf("v");
                    }else{
                        printf(" ");
                    }
                    if (layer->IsTileFlippedDiagonally(x, y)){
                        printf("d ");
                    } else {
                        printf("  ");
                    }
                    ****************************/
                }
                //printf("\n");
            }
            //printf("\n\n");
        }
    }
    tiles = new sz::SpriteSheet(name, image, 33, 33);
}

void sz::Map::Draw(sf::RenderWindow *rw) {
    // dont know what to do T_T
}

#include "SpriteSheet.h"

sz::SpriteSheet::SpriteSheet(std::string name, std::string path, int tileW, int tileH) : sz::GameObject(name, path) {
    this->tileH = tileH;
    this->tileW = tileW;
    numOfTiles = ((this->GetImage()->GetHeight()) / tileH) * ((this->GetImage()->GetWidth()) / tileW);
}

int sz::SpriteSheet::GetTileWidth() { return tileW; }
int sz::SpriteSheet::GetTileHeight() { return tileH; }
int sz::SpriteSheet::GetNumOfTiles() { return numOfTiles; }

sf::Sprite sz::SpriteSheet::GetSubSprite(int idx) {
    if(idx < 1 || idx > numOfTiles) {
        std::cout << "Incorrect index!" << std::endl;
        // need return value
    }

    int row=0, col=0, tilesEachRow = (GetImage()->GetWidth() / tileW);

    while(idx > tilesEachRow) {
        idx -= tilesEachRow;
        col++;
    }
    row = idx-1;

    sz::GameObject *sub = new sz::GameObject(name, path);
    /*std::cout << "tileW: " << tileW << std::endl;
    std::cout << "tileH: " << tileH << std::endl;
    std::cout << "row: " << row << std::endl;
    std::cout << "col: " << col << std::endl;
    std::cout << "tiles per row: " << tilesEachRow << std::endl;
    std::cout << "(" << row*tileW << ", " << col*tileH << ", " << (row+1)*tileW << ", " << (col+1)*tileH << ")" << std::endl;*/
    sub->SetSubRect(sf::IntRect(row*tileW, col*tileH, (row+1)*tileW, (col+1)*tileH));
    return *sub;
}
c++ sfml
2个回答
4
投票

您是否真的遇到速度问题?虽然每秒30000个瓦片听起来可能很多,但就使用更现代的PC进行计算而言,这可能不是什么大问题。

话虽如此,但我绝对可以想到一种方法来优化您的输出,如果输出单个图块具有一定的相关开销(例如,输出2个图块所花的时间比1个图块(这两个图块的总和要长)要长) )。我不太了解SFML,但是我假设已经有某种曲面/画布系统。您可以做的是编写一种将静态图块绘制到表面一次的方法。然后在游戏的每一帧输出该表面一次。这意味着不需要以瓦片的方式重复输出每一帧的瓦片。您只需输出所有静态图块的单个图像即可。

我认为您甚至可以动态使用此系统。如果需要更改图块,只需使用更新的图块数据覆盖此表面的相关部分。换句话说,您将所有静态的东西都留了下来,只针对需要更新的目标区域。


1
投票

我同意亚历克斯·Z的观点,在现代/主流硬件中,渲染5个屏幕的磁贴不应太慢。但是,唯一可以确定的方法就是对其进行测试。

此外,即使您的地图上有1000x1000的图块,由于其余图块都在屏幕之外,所以每帧仅渲染10x10的图块。

如果要使当前结构更优化,则应将每个精灵存储在数组中,作为单独的精灵存储在数组中。这样,您无需在每次需要访问单个图块时都调用SetSubRect。

© www.soinside.com 2019 - 2024. All rights reserved.