如何用SDL2_TTF库在SDL窗口中显示动态流逝时间?
问题解答
1. 仅用SDL2_TTF成员函数能否显示动态文本?
可以,但你遇到的报错是参数类型不匹配导致的:TTF_RenderText_Solid要求文本参数为const char*,而std::to_string(float)返回的是std::string,直接传递会触发类型不兼容错误。
解决这个问题只需调用std::string的c_str()方法,将其转换为C风格字符串即可:
float elapsedTime = 45.67f; std::string timeStr = std::to_string(elapsedTime); // 转成const char*传入 SDL_Surface* textSurface = TTF_RenderText_Solid(yourFont, timeStr.c_str(), yourTextColor);
需要注意:每次动态内容(比如分数、生命值)变化时,都需要重新调用TTF渲染函数生成新的Surface,再转换为Texture交给SDL渲染器更新显示。
2. 封装基于SDL渲染的动态文本类
如果需要频繁更新文本(如帧率、实时分数),封装一个复用的动态文本类能大幅提升代码可维护性,还能减少不必要的重复渲染开销。以下是一个实用的实现示例:
核心设计思路
- 保存SDL渲染器、字体、文本颜色的引用,避免重复传递参数
- 内部维护当前文本内容和对应的Texture,仅在文本/颜色变化时重新渲染,节省性能
- 提供统一的文本更新、颜色设置、渲染方法,支持直接传入数字类型(int/float)
示例代码
#include <SDL2/SDL.h> #include <SDL2/SDL_ttf.h> #include <string> #include <cstdio> class DynamicText { private: SDL_Renderer* m_renderer; TTF_Font* m_font; SDL_Color m_textColor; std::string m_currentText; SDL_Texture* m_textTexture = nullptr; int m_textWidth = 0; int m_textHeight = 0; // 内部方法:重新渲染文本并更新Texture void refreshTexture() { // 销毁旧Texture避免内存泄漏 if (m_textTexture != nullptr) { SDL_DestroyTexture(m_textTexture); m_textTexture = nullptr; } // 生成Surface并转成Texture SDL_Surface* textSurface = TTF_RenderText_Solid(m_font, m_currentText.c_str(), m_textColor); if (!textSurface) return; m_textTexture = SDL_CreateTextureFromSurface(m_renderer, textSurface); m_textWidth = textSurface->w; m_textHeight = textSurface->h; SDL_FreeSurface(textSurface); } public: // 构造函数:初始化依赖资源 DynamicText(SDL_Renderer* renderer, TTF_Font* font, SDL_Color color) : m_renderer(renderer), m_font(font), m_textColor(color) {} // 析构函数:清理资源 ~DynamicText() { if (m_textTexture) SDL_DestroyTexture(m_textTexture); } // 更新文本内容(仅当内容变化时重新渲染) void setText(const std::string& newText) { if (newText != m_currentText) { m_currentText = newText; refreshTexture(); } } // 重载:支持直接传入int类型 void setText(int number) { setText(std::to_string(number)); } // 重载:支持float类型,可自定义小数位数 void setText(float number) { char buffer[32]; snprintf(buffer, sizeof(buffer), "%.2f", number); // 保留两位小数 setText(std::string(buffer)); } // 修改文本颜色 void setColor(SDL_Color newColor) { if (newColor.r != m_textColor.r || newColor.g != m_textColor.g || newColor.b != m_textColor.b || newColor.a != m_textColor.a) { m_textColor = newColor; refreshTexture(); } } // 将文本渲染到指定坐标 void render(int x, int y) { if (!m_textTexture) return; SDL_Rect destRect = {x, y, m_textWidth, m_textHeight}; SDL_RenderCopy(m_renderer, m_textTexture, nullptr, &destRect); } // 获取当前文本的尺寸 void getSize(int& outWidth, int& outHeight) { outWidth = m_textWidth; outHeight = m_textHeight; } };
使用示例
// 假设已完成SDL、TTF初始化,且创建了renderer和font对象 SDL_Color white = {255, 255, 255, 255}; DynamicText scoreText(renderer, gameFont, white); DynamicText timeText(renderer, gameFont, white); float gameElapsedTime = 0.0f; int playerScore = 0; // 游戏主循环 while (isRunning) { // 处理事件、更新游戏逻辑... gameElapsedTime += deltaTime; playerScore += 10; // 更新动态文本 scoreText.setText(playerScore); timeText.setText(gameElapsedTime); // 渲染流程 SDL_RenderClear(renderer); // 渲染游戏场景... scoreText.render(30, 30); // 渲染分数到(30,30) timeText.render(30, 60); // 渲染时长到(30,60) SDL_RenderPresent(renderer); }
额外提示
- 如果需要更美观的文本效果(如抗锯齿、阴影),只需将
TTF_RenderText_Solid替换为TTF_RenderText_Blended或TTF_RenderText_Shaded即可 - 确保字体对象
TTF_Font*的生命周期长于DynamicText实例,避免出现悬空指针问题
内容的提问来源于stack exchange,提问作者Ömer Can Öztürk
相关产品推荐
相关产品推荐

