我之前有一个关于堆栈溢出错误的问题,并切换到我的对象数组的向量。如果需要,可以在此处引用该问题:How to get rid of stack overflow error
然而,我当前的问题是,如何加快向量的初始化。我目前的方法目前需要约15秒。使用数组而不是向量,它花了一秒钟,数组大小足够小,不会引发堆栈溢出错误。
以下是我如何初始化它:
在main.cpp中我初始化我的dungeon对象:
dungeon = Dungeon(0, &textureHandler, MIN_X, MAX_Y);
在我的dungeon(...)构造函数中,我初始化我的5x5房间向量并调用loadDungeon:
Dungeon::Dungeon(int dungeonID, TextureHandler* textureHandler, int topLeftX, int topLeftY)
{
currentRoomRow = 0;
currentRoomCol = 0;
for (int r = 0; r < MAX_RM_ROWS; ++r)
{
rooms.push_back(vector<Room>());
for (int c = 0; c < MAX_RM_COLS; ++c)
{
rooms[r].push_back(Room());
}
}
loadDungeon(dungeonID, textureHandler, topLeftX, topLeftY);
}
我的Room构造函数填充了我的30x50单元格向量(所以我可以在loadDungeon函数中设置它们):
Room::Room()
{
for (int r = 0; r < MAX_ROWS; ++r)
{
cells.push_back(vector<Cell>());
for (int c = 0; c < MAX_COLS; ++c)
{
cells[r].push_back(Cell());
}
}
}
我的默认单元格构造函数很简单,并没有做太多,但无论如何我都会发布它:
Cell::Cell()
{
x = 0;
y = 0;
width = 16;
height = 16;
solid = false;
texCoords.push_back(0);
texCoords.push_back(0);
texCoords.push_back(1);
texCoords.push_back(0);
texCoords.push_back(1);
texCoords.push_back(1);
texCoords.push_back(0);
texCoords.push_back(1);
}
最后我的loadDungeon()函数将设置单元格。最终,这将从文件读取并加载单元格,但是现在我想尽可能优化它。
void Dungeon::loadDungeon(int dungeonID, TextureHandler* textureHandler, int topLeftX, int topLeftY)
{
int startX = topLeftX + (textureHandler->getSpriteWidth()/2);
int startY = topLeftY - (textureHandler->getSpriteHeight()/2);
int xOffset = 0;
int yOffset = 0;
for (int r = 0; r < MAX_RM_ROWS; ++r)
{
for (int c = 0; c < MAX_RM_COLS; ++c)
{
for (int cellRow = 0; cellRow < rooms[r][c].getMaxRows(); ++cellRow)
{
xOffset = 0;
for (int cellCol = 0; cellCol < rooms[r][c].getMaxCols(); ++cellCol)
{
rooms[r][c].setupCell(cellRow, cellCol, startX + xOffset, startY - yOffset, textureHandler->getSpriteWidth(), textureHandler->getSpriteHeight(), false, textureHandler->getSpriteTexCoords("grass"));
xOffset += textureHandler->getSpriteWidth();
}
yOffset += textureHandler->getSpriteHeight();
}
}
}
currentDungeon = dungeonID;
currentRoomRow = 0;
currentRoomCol = 0;
}
那么我怎样才能加快速度,所以每次加载都不需要15秒。我觉得加载简单的2D游戏不需要15秒。
解 好吧,我的解决方案是使用std :: vector :: reserve调用(rooms.reserve在我的代码中,它最终运行良好。我将我的函数Dungeon :: loadDungeon更改为Dungeon :: loadDefaultDungeon,因为它现在加载了一个保存文件。
无论如何这里是代码(我在调试模式下从约15 +秒开始大约需要4-5秒):
Dungeon::Dungeon()
{
rooms.reserve(MAX_RM_ROWS * MAX_RM_COLS);
currentDungeon = 0;
currentRoomRow = 0;
currentRoomCol = 0;
}
void Dungeon::loadDefaultDungeon(TextureHandler* textureHandler, int topLeftX, int topLeftY)
{
int startX = topLeftX + (textureHandler->getSpriteWidth()/2);
int startY = topLeftY - (textureHandler->getSpriteHeight()/2);
int xOffset = 0;
int yOffset = 0;
cerr << "Loading default dungeon..." << endl;
for (int roomRow = 0; roomRow < MAX_RM_ROWS; ++roomRow)
{
for (int roomCol = 0; roomCol < MAX_RM_COLS; ++roomCol)
{
rooms.push_back(Room());
int curRoom = roomRow * MAX_RM_COLS + roomCol;
for (int cellRow = 0; cellRow < rooms[curRoom].getMaxRows(); ++cellRow)
{
for (int cellCol = 0; cellCol < rooms[curRoom].getMaxCols(); ++cellCol)
{
rooms[curRoom].setupCell(cellRow, cellCol, startX + xOffset, startY - yOffset, textureHandler->getSpriteWidth(), textureHandler->getSpriteHeight(), false, textureHandler->getSpriteTexCoords("default"), "default");
xOffset += textureHandler->getSpriteWidth();
}
yOffset += textureHandler->getSpriteHeight();
xOffset = 0;
}
cerr << " room " << curRoom << " complete" << endl;
}
}
cerr << "default dungeon loaded" << endl;
}
Room::Room()
{
cells.reserve(MAX_ROWS * MAX_COLS);
for (int r = 0; r < MAX_ROWS; ++r)
{
for (int c = 0; c < MAX_COLS; ++c)
{
cells.push_back(Cell());
}
}
}
void Room::setupCell(int row, int col, float x, float y, float width, float height, bool solid, /*std::array<float, 8>*/ vector<float> texCoords, string texName)
{
cells[row * MAX_COLS + col].setup(x, y, width, height, solid, texCoords, texName);
}
void Cell::setup(float x, float y, float width, float height, bool solid, /*std::array<float,8>*/ vector<float> t, string texName)
{
this->x = x;
this->y = y;
this->width = width;
this->height = height;
this->solid = solid;
for (int i = 0; i < t.size(); ++i)
this->texCoords.push_back(t[i]);
this->texName = texName;
}
答案 0 :(得分:3)
由于您的向量似乎在编译时定义了它们的大小,如果您可以使用C ++ 11,则可以考虑使用std::array
而不是std::vector
。 std::array
无法调整大小并且缺少std::vector
中的许多操作,但更轻量级,似乎非常适合您正在做的事情。
例如,您可以将cells
声明为:
#include <array>
/* ... */
std::array<std::array<Cell, MAX_COLS>, MAX_ROWS> cells;
UPDATE:,因为本地定义的std::array
在堆栈上分配其内部数组,由于数组的大小相当大,OP将遇到堆栈溢出。尽管如此,通过在堆上分配数组,可以使用std::array
(与使用std::vector
相比,它的好处)。这可以通过以下方式完成:
typedef std::array<std::array<Cell, MAX_COLS>, MAX_ROWS> Map;
Map* cells;
/* ... */
cells = new Map();
更好的是,可以使用智能指针:
#include <memory>
/* ... */
std::unique_ptr<Map> cells;
cells = std::unique_ptr(new Map());
答案 1 :(得分:3)
拥有如此多的动态分配似乎很浪费。你可以通过展平你的向量并大步访问它来获得一个单一的分配:
std::vector<Room> rooms;
rooms.resize(MAX_RM_ROWS * MAX_RM_COLS);
for (unsigned int i = 0; i != MAX_RM_ROWS; ++i)
{
for (unsigned int j = 0; j != MAX_RM_COLS; ++j)
{
Room & r = rooms[i * MAX_RM_COLS + j];
// use `r` ^^^^^^^^^^^^^^^^^^^-----<< strides!
}
}
注意resize
如何执行一次,只产生一次单独分配,以及默认构造每个元素。如果您更愿意专门构造每个元素,请改用rooms.reserve(MAX_RM_ROWS * MAX_RM_COLS);
并填充循环中的向量。
您可能还希望对交换的行和列进行分析,看看哪个更快。