我使用SDL2在C 中制作了2D游戏,其中世界地图由120x67瓷砖组成。在任何给定的时间,在地图上只有大约20个左右的精灵(每个砖块)四处移动,并且只有一小部分瓷砖(主要只是水砖)将被动画。因此,在绝大多数时间里,大多数瓷砖将保持静态。目前,我有一个简单的拉动循环,可以在所有瓷砖上迭代并重新绘制它们:
/* Drawing loop, excluding frame rate limiting logic and updating gamestate */
while(true) {
/* game state is updated (omitted) */
/* clear the entire screen */
SDL_RenderClear(renderer);
/* loop through all the tiles and redraw them */
for (int i = 0; i < rows; i++) {
for(int j = 0; j < cols; j++) {
/* call the tile's draw method, which calls SDL_renderCopy()
* to draw the tile background and sprite (if there is one) */
tiles[i][j].drawTile(renderer);
}
}
/* output everything to the screen */
SDL_RenderPresent(renderer);
}
但是,由于大多数瓷砖大部分时间都将保持静态,因此无需继续绘制它们。仅重新绘制正在更改的屏幕的一小部分将要有效得多。因此,我的新想法是,在更新游戏状态时,将所有更新的图块添加到列表中,然后仅重新绘制每个帧上更新的瓷砖,例如:
/* Drawing loop that only redraws updated tiles */
while(true) {
/* game state is updated, updated tiles added to a list (omitted) */
/* loop through only the updated tiles and redraw them */
for (std::list<Tile>::iterator it=updatedTiles.begin(); it != updatedTiles.end(); ++it) {
/* call the tile's draw method, which calls SDL_renderCopy()
* to draw the tile background and sprite (if there is one) */
it->drawTile(renderer);
}
/* output everything to the screen */
SDL_RenderPresent(renderer);
}
由于我不想在每帧之前清除屏幕,因此在第二种情况下删除了SDL_RenderClear()
的调用。但是,从此处找到的SDL_RenderPresent
的SDL2文档中说:
强烈建议您在启动每个新帧的绘图之前调用SDL_RenderClear()初始化backbuffer。
这样,我的两个问题是:
- 如果我只需更新修改的瓷砖,我真的需要在每个帧上调用
SDL_RenderClear()
? - 如果我必须坚持在每个框架上重新绘制每个瓷砖,则是现代图形卡/SDL库"智能",以至于在呼叫
SDL_RenderPresent()
时,只能重新绘制更改的屏幕部分,而没有我实施此操作?
文档的相关部分是在您提到的(强调我的)
之前backbuffer 应在每次存在后视为无效;不要假设以前的内容将存在于框架之间。
这意味着对SDL_RenderClear
的调用是强制性的,而不是建议的。
您可以做的是绘制背景图像(无论是什么意思,作为一个示例,在没有PC或NPC周围没有PC或NPC的一个示例)上仅在目标纹理上一次进入场景之前(有关更多详细信息,请参见SDL_SetRenderTarget
和其他功能)。然后,在循环中,您可以清除默认渲染器,立即将该图像复制为a background Image ,最后仅绘制更新的图块,从而更新其(让我说)默认或基本表示。
实际上,如果您已更新了n个瓷砖,则最终会用n 1个调用SDL_RenderCopy
或每次迭代中的任何内容绘制所有内容。
说实话,我只有在您观察大量帧的情况下,我才这样做,因为您在每次迭代中都绘制了太多。我的两分钱。
无论如何,这是一个肮脏且工作的解决方案,至少可以执行您想要的。