我正在使用 SDL2 用 C++ 制作 2D 游戏,其中世界地图由 120x67 block 组成。在任何给定时间,只会有大约 20 个左右的 Sprite (每个 Sprite 恰好占据一个图 block )在 map 上移动,并且只有一小部分图 block (主要是水图 block )会进行动画处理。因此,在绝大多数时间里,大部分图 block 将保持静态。目前,我有一个简单的绘制循环,可以迭代所有图 block 并重新绘制它们:
/* 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);
}
但是,由于大多数图 block 在大多数时间都保持静态,因此无需继续绘制它们。仅重绘屏幕上正在变化的小部分会更有效。所以我的新想法是,在更新游戏状态时,将所有更新的图 block 添加到列表中,然后只需在每个帧上仅重绘更新的图 block ,如下所示:
/* 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 文档中发现 here ,它说:
You are strongly encouraged to call SDL_RenderClear() to initialize the backbuffer before starting each new frame's drawing.
有了这个,我的两个问题是:
- 如果我只想更新修改后的图 block ,我真的需要在每个帧上调用
SDL_RenderClear()
吗? - 如果我必须坚持重绘每一帧上的每个图 block ,现代显卡/SDL 库是否足够“智能”,在调用
SDL_RenderPresent()
时,仅重绘更改的屏幕,而无需我执行此操作?
最佳答案
文档的相关部分紧接在您提到的部分之前(强调我的)
The backbuffer should be considered invalidated after each present; do not assume that previous contents will exist between frames.
这意味着对 SDL_RenderClear
的调用是强制的,而不是建议的。
您可以做的就是仅在目标纹理上绘制背景图像(无论它意味着什么,例如周围没有任何 PC 或 NPC 的图 block 集)进入场景之前一次(有关更多详细信息,请参阅 SDL_SetRenderTarget
和其他函数)。然后,在循环中,您可以清除默认渲染器,立即将该图像复制为背景图像,最后仅在其上绘制更新的图 block ,从而更新它们的(让我说)默认或基本表示。
事实上,如果您更新了 N 个图 block ,则最终会在每次迭代时通过对 SDL_RenderCopy
或其他内容的 N+1 次调用来绘制所有内容。
说实话,只有当您观察到由于每次迭代绘制太多而导致帧数显着下降时,我才会这样做。我的两分钱。
无论如何,这是一个肮脏但有效的解决方案,至少可以满足您的要求。
关于c++ - 使用 SDL2 在每一帧上渲染屏幕的一部分,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46311411/