简体   繁体   English

如何使用 SDL2 显示 2D 视频游戏的计数器?

[英]How to display a counter for a 2D video game using SDL2?

I'm making a 2D RPG-type video game in C++ ver.17 using the SDL2 libraries for my own pleasure (I don't intend to sell the game yet, at most to make it public for free).我正在使用 SDL2 库在 C++ ver.17 中制作一个 2D RPG 类型的视频游戏(我不打算出售游戏,最多免费公开)。 I've reached a point where I want to display in the GUI window of the game a counter of keys collected by my 2D character (it's a sprite sheet with animations in 4 directions).我已经到了我想在游戏的 GUI window 中显示我的 2D 角色收集的按键计数器的地步(这是一个带有 4 个方向动画的精灵表)。 Also I would also add a second message always to be displayed in the GUI during the game.此外,我还会添加第二条消息,在游戏过程中始终显示在 GUI 中。 I structured the project by creating a class named GamePanel which represents the manager of the entire game.我通过创建一个名为 class 的 GamePanel 来构建项目,它代表整个游戏的经理。 This class has a method named run() which contains the game loop of the game.这个 class 有一个名为 run() 的方法,其中包含游戏的游戏循环。 In it the usual methods are called cyclically (with an FPS of 60):在其中循环调用通常的方法(FPS 为 60):

Events( ): for user events Events( ):用于用户事件
Update( ): for updating game scene frame Update():用于更新游戏场景帧
Render( ): to draw and render the game scene frame. Render():绘制和渲染游戏场景帧。

Among other things, in the Update() method I update a counter of keys collected by the character and consequently update the message to be displayed on the scene.除此之外,在 Update() 方法中,我更新了角色收集的键的计数器,并因此更新了要在场景中显示的消息。 Then the Render() method renders it all to me, thus showing me the message.然后 Render() 方法将它全部呈现给我,从而向我显示消息。 Now the problem that arises is the use of the text through the SDL2_ttf library and the consequent use of SDL_Surface, containing the message using the font of SDL2_ttf and then the transition to the SDL_Texture to then display it using SDL_RenderCopy( ) and SDL_RenderPresent( ) in the scene.现在出现的问题是通过 SDL2_ttf 库使用文本以及随后使用 SDL_Surface,包含使用 SDL2_ttf 字体的消息,然后过渡到 SDL_Texture,然后使用 SDL_RenderCopy( ) 和 SDL_RenderPresent( ) 显示它现场。 These passages cannot be done in the game loop, because this would lead to a "fatigue" of the PC doing it at the speed of 60 frames per second.这些段落不能在游戏循环中完成,因为这会导致 PC 以每秒 60 帧的速度进行“疲劳”。

Is there therefore a way to make the display of the message, which updates continuously (at the speed of 60 FPS)?因此,有没有办法显示不断更新的消息(以 60 FPS 的速度)?

Can you give me some advice on how to proceed or better if you have found some tutorials that explain it to me?如果你找到一些向我解释的教程,你能给我一些关于如何继续或更好的建议吗?

I created a class named TextureManager to handle most of the graphics with SDL2.我创建了一个名为 TextureManager 的 class 来处理大部分带有 SDL2 的图形。 I made this class singleton in order to have only one instance and to be able to use it anywhere in the code.我做了这个 class singleton 是为了只有一个实例并且能够在代码中的任何地方使用它。 In this class I created some methods:在这个 class 中我创建了一些方法:

  • TextureManager::LoadText(std::string* tex): for loading the SDL_Surface which are then transformed into SDL_Texture. TextureManager::LoadText(std::string* tex):用于加载 SDL_Surface,然后将其转换为 SDL_Texture。 Of course, the created SDL_Surface must be deleted via SDL_FreeSurface.当然,创建的SDL_Surface必须通过SDL_FreeSurface删除。 This for each texture you want to create.这适用于您要创建的每个纹理。

  • TextureManager::DrawText(std::string* text, int x, int y, SDL_Texture* image): for drawing the texture (which contains for example the text, or the character). TextureManager::DrawText(std::string* text, int x, int y, SDL_Texture* image):用于绘制纹理(包含例如文本或字符)。

In the GamePanel class I render everything by calling the TextureManagers, then using SDL_RenderPresent(m_Renderer);在 GamePanel class 中,我通过调用 TextureManagers 渲染所有内容,然后使用 SDL_RenderPresent(m_Renderer);

I created a UI class that contains the update() and draw() methods related to the message to be displayed (the count of collected keys), and other messages to be displayed in the game.我创建了一个 UI class,其中包含与要显示的消息(收集的键数)以及游戏中要显示的其他消息相关的 update() 和 draw() 方法。

This class is created outside the game loop in GamePanel and more precisely in the GamePanel::Init( ) method, where I initialize all the SDL2 libraries, including SDL2_ttf (the character font to be displayed in the GUI environment).这个 class 是在 GamePanel 的游戏循环之外创建的,更准确地说是在 GamePanel::Init( ) 方法中创建的,我在这里初始化所有 SDL2 库,包括 SDL2_ttf(要在 GUI 环境中显示的字符字体)。

So I have the following methods:所以我有以下方法:

void GamePanel::update() {

    float dt = Timer::GetInstance()->GetDeltaTime();

    //player->Update(dt);
    player->update();

    // aggiorna l'interfaccia utente
    ui->update();
}

void GamePanel::Render() {

    SDL_SetRenderDrawColor(m_Renderer, 124, 218, 254, 255);
    SDL_RenderClear(m_Renderer);
    
    // Tiles
    tileM->draw();

    // Objects
    for (int i = 0; i < obj.size(); i++)
    {
        if (!obj.at(i).name.empty()) 
        {
            obj.at(i).draw();
        }
    }
    
    // Player
    player->draw(m_Renderer);

    // disegna interfaccia utente: testo indicante numero chiavi disponibili
    ui->draw();

    SDL_RenderPresent(m_Renderer);

}

The text rendering API of SDL_ttf isn't the best. SDL_ttf 的文本呈现 API 不是最好的。 It works, but it has some disadvantages, especially concerning the performance.它有效,但有一些缺点,尤其是在性能方面。

The speed of the text rendering really depends on the quality setting you use (ie the function you use).文本呈现的速度实际上取决于您使用的质量设置(即您使用的 function)。 The old documentation of SDL_ttf states: SDL_ttf 的旧文档指出:

  • Solid (ie TTF_RenderUTF8_Solid ): " Quick and Dirty: [...] render the given text at fast quality [...]. This is the fastest rendering speed of all the rendering modes. This results in no box around the text, but the text is not as smooth. [...] Use this mode for FPS and other fast changing updating text displays." Solid (即TTF_RenderUTF8_Solid ): " Quick and Dirty: [...]但文本不那么流畅。[...] 将此模式用于 FPS 和其他快速变化的更新文本显示。”
  • Shaded (ie TTF_RenderUTF8_Shaded ): " Slow and Nice, but with a Solid Box: [...] The text is antialiased. This will render slower than Solid, but in about the same time as Blended mode."阴影(即TTF_RenderUTF8_Shaded ):“慢而好,但带有实心框: [...] 文本是抗锯齿的。这将比实心渲染慢,但与混合模式大致相同。”
  • Blended (ie TTF_RenderUTF8_Blended ): " Slow Slow Slow, but Ultra Nice over another image: [...] Use this when you want high quality, and the text isn't changing too fast."混合(即TTF_RenderUTF8_Blended ):“慢慢慢,但在另一幅图像上非常好: [...] 当你想要高质量时使用它,并且文本变化不会太快。”

Furthermore you need to copy the image into the VRAM (this is, what you described as the transition to a SDL_Texture ).此外,您需要将图像复制到 VRAM 中(这就是您描述的向SDL_Texture的过渡)。 This operation is really slow.这个操作真的很慢。 You should really minimize the use of this function during the game loop (maybe just for a FPS counter, but an external debug terminal would be definitely faster).你真的应该在游戏循环中尽量减少这个 function 的使用(也许只是为了 FPS 计数器,但外部调试终端肯定会更快)。

For every static text (like conversations with NPCs) or any text, that won't change, you should render and copy them to VRAM during the loading phase of your game or scene.对于每个 static 文本(如与 NPC 的对话)或任何不会更改的文本,您应该在游戏或场景的加载阶段渲染并将它们复制到 VRAM。 You probably want a good quality for such strings.您可能希望此类琴弦具有良好的质量。 Therefore you need to create all the SDL_Texture s during startup and cache them.因此,您需要在启动期间创建所有SDL_Texture并缓存它们。 Then you just need to call SDL_RenderCopy in your GamePanel::render() method.然后你只需要在你的GamePanel::render()方法中调用SDL_RenderCopy

Now I don't know, how fast your item counter changes.现在我不知道,你的物品计数器变化多快。 But probably it will be even on higher text quality levels sufficient, if you just render the text once when the counter updates (including the creation of the texture).但是,如果您在计数器更新(包括创建纹理)时只渲染一次文本,那么它甚至可能在更高的文本质量水平上就足够了。 And then you store the texture like the static strings until the counter changes.然后将纹理存储为 static 字符串,直到计数器发生变化。 This shouldn't introduce a huge lag.这不应该引入巨大的滞后。

But if it does, you can cache the individual digits.但如果是这样,您可以缓存各个数字。 Render all digits from 0-9 once in separate textures and store them.在单独的纹理中渲染 0-9 的所有数字一次并存储它们。 Now you just need to pick the right textures and render them to the number you want to display.现在你只需要选择正确的纹理并将它们渲染到你想要显示的数字。 But be aware, that you shouldn't do this with texts, as you then would need to apply proper kerning.但请注意,您不应该对文本执行此操作,因为您需要应用适当的字距调整。 For numbers this is negligible, but for texts not.对于数字,这是可以忽略不计的,但对于文本则不然。 Texts would not look nice if you do that with the individual glyphs.如果您对单个字形这样做,文本看起来不会很好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM