用SDL2在每个帧上渲染屏幕的部分

Rendering parts of the screen on each frame with SDL2

本文关键字:屏幕 SDL2      更新时间:2023-10-16

我使用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。

这样,我的两个问题是:

  1. 如果我只需更新修改的瓷砖,我真的需要在每个帧上调用SDL_RenderClear()
  2. 如果我必须坚持在每个框架上重新绘制每个瓷砖,则是现代图形卡/SDL库"智能",以至于在呼叫SDL_RenderPresent()时,只能重新绘制更改的屏幕部分,而没有我实施此操作?

文档的相关部分是在您提到的(强调我的)

之前

backbuffer 应在每次存在后视为无效;不要假设以前的内容将存在于框架之间。

这意味着对SDL_RenderClear的调用是强制性的,而不是建议的

您可以做的是绘制背景图像(无论是什么意思,作为一个示例,在没有PC或NPC周围没有PC或NPC的一个示例)上仅在目标纹理上一次进入场景之前(有关更多详细信息,请参见SDL_SetRenderTarget和其他功能)。然后,在循环中,您可以清除默认渲染器,立即将该图像复制为a background Image ,最后仅绘制更新的图块,从而更新其(让我说)默认或基本表示
实际上,如果您已更新了n个瓷砖,则最终会用n 1个调用SDL_RenderCopy或每次迭代中的任何内容绘制所有内容。

说实话,我只有在您观察大量帧的情况下,我才这样做,因为您在每次迭代中都绘制了太多。我的两分钱。
无论如何,这是一个肮脏且工作的解决方案,至少可以执行您想要的。