使用 SDL2 在每一帧上渲染部分屏幕
Rendering parts of the screen on each frame with SDL2
我正在使用 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 文档中找到 here,它说:
You are strongly encouraged to call SDL_RenderClear() to initialize the backbuffer before starting each new frame's drawing.
有了这个,我的两个问题是:
- 如果我只想更新修改后的图块,我真的需要在每一帧上调用
SDL_RenderClear()
吗?
- 如果我必须坚持在每一帧上重绘每个图块,现代显卡/SDL 库 "smart" 是否足以在调用
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 的一组图块)在进入场景之前只在目标纹理上执行一次(有关更多详细信息,请参阅 SDL_SetRenderTarget
和周围的其他功能)。然后,在循环中,您可以清除默认渲染器,立即将该图像复制为 背景图像 ,最后只在其上绘制更新的图块,从而更新它们(让我说) 默认或基本表示法。
事实上,如果您更新了 N 个图块,您最终会在每次迭代时通过 N+1 次调用 SDL_RenderCopy
或其他任何方式来绘制所有内容。
老实说,只有当您观察到由于每次迭代绘制过多而导致帧明显下降时,我才会这样做。我的两分钱。
无论如何,这是一个肮脏的工作解决方案,至少可以满足您的需求。
我正在使用 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 文档中找到 here,它说:
You are strongly encouraged to call SDL_RenderClear() to initialize the backbuffer before starting each new frame's drawing.
有了这个,我的两个问题是:
- 如果我只想更新修改后的图块,我真的需要在每一帧上调用
SDL_RenderClear()
吗? - 如果我必须坚持在每一帧上重绘每个图块,现代显卡/SDL 库 "smart" 是否足以在调用
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 的一组图块)在进入场景之前只在目标纹理上执行一次(有关更多详细信息,请参阅 SDL_SetRenderTarget
和周围的其他功能)。然后,在循环中,您可以清除默认渲染器,立即将该图像复制为 背景图像 ,最后只在其上绘制更新的图块,从而更新它们(让我说) 默认或基本表示法。
事实上,如果您更新了 N 个图块,您最终会在每次迭代时通过 N+1 次调用 SDL_RenderCopy
或其他任何方式来绘制所有内容。
老实说,只有当您观察到由于每次迭代绘制过多而导致帧明显下降时,我才会这样做。我的两分钱。
无论如何,这是一个肮脏的工作解决方案,至少可以满足您的需求。