SDL_TTF打印效果慢
SDL_TTF slow printing effect
所以,我正在开发一个命令提示符游戏,现在我从小处着手。我已经掌握了打印速度较慢的文本系统的基础知识,但我遇到了一个我不确定如何解决的问题。
基本上;文本会拉伸以适合预定义的框:
对于预定义框,我的意思是 SDL_Rect 我定义为 srcrect 和 dstrect。
现在,一个解决方案是简单地扩展 SDL_Rect 以适合我的文本,并且由于我使用的是等宽字体,这将相当容易。但是我只是在想; "There must be a better way!".
最后,如果您需要的话,这是我的代码:
#include<iostream>
#include<SDL.h>
#include<string>
#include<SDL_ttf.h>
std::string text = "";
std::string textToAdd = "Hello there, how are you doing?";
int pos = 0;
void handleEvents(SDL_Event e, bool* quit){
while(SDL_PollEvent(&e) > 0){
if(e.type == SDL_QUIT){
*quit = true;
}
}
}
void render(SDL_Renderer* renderer, SDL_Texture* textToRender, SDL_Rect srcrect, SDL_Rect dstrect){
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, textToRender, &srcrect, &dstrect);
SDL_RenderPresent(renderer);
}
Uint32 calcText(Uint32 interval, void *param){
if(pos < textToAdd.length()){
text = text + textToAdd[pos];
pos++;
}
return interval;
}
int main( int argc, char *argv[] ) {
SDL_Init(SDL_INIT_EVERYTHING);
TTF_Init();
SDL_Window* window = SDL_CreateWindow("Game", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 600, 600, SDL_RENDERER_ACCELERATED);
SDL_Renderer* renderer = SDL_CreateRenderer(window, 0, 0);
bool quit = false;
SDL_Event e;
SDL_TimerID repeatText = SDL_AddTimer(70, calcText, NULL);
TTF_Font* font = TTF_OpenFont("Hack-Regular.ttf", 28);
SDL_Color color = {255, 255, 255};
SDL_Surface* textSurface;
SDL_Texture* textTexture;
SDL_Rect srcrect;
SDL_Rect dstrect;
srcrect.x = 0;
srcrect.y = 0;
srcrect.w = 580;
srcrect.h = 32;
dstrect.x = 10;
dstrect.y = 10;
dstrect.w = 580;
dstrect.h = 32;
while(!quit){
handleEvents(e, &quit);
render(renderer, textTexture, srcrect, dstrect);
textSurface = TTF_RenderText_Solid(font, text.c_str(), color);
textTexture = SDL_CreateTextureFromSurface(renderer, textSurface);
}
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
window = NULL;
renderer = NULL;
TTF_Quit();
SDL_Quit();
return 0;
}
我用了一些不同的方法。首先,我建议您阅读本教程:http://lazyfoo.net/tutorials/SDL/index.php。其次:尝试在关键点使用初始化检查,如本例所示:
//...
if (!myInitFunction())
{
//error message and quit without crash
}
else
{
//continue game
}
//...
让我们回到您的问题:
是的,有可能,如您所愿,从 surface->w
得到 dstrect.w
。但不是那么简单。因为一开始 运行 的 while 循环我们会崩溃,如果我们这样做 dstrect.w = surcface->h
那么你的游戏就会崩溃。为什么?因为字符串等于什么都没有:""
.
为避免这种情况,您应该简单地以一个带空格的字符串开始,或者在开始之前将 'H'
字符放在字符串中。 (实际上我没有使用 SDL_TimerID
而是用另一种方式制作的,但我不想让它复杂化。)
此外,您应该遵循 "order rule":INPUT >>> HANDLING >>> RENDER
。
因此您的代码应如下所示:
//...
std::string text = "H";
std::string textToAdd = "ello there, how are you doing?";
//...
while(!quit)
{
handleEvents(e, &quit);
textSurface = TTF_RenderText_Solid(font, text.c_str(), color);
dstrect.w = textSurface->w; //change the width of rectangle
textTexture = SDL_CreateTextureFromSurface(renderer, textSurface);
render(renderer, textTexture, srcrect, dstrect);
}
//...
另一个建议是尝试泛化这个渲染方法,如果你没有做过的话,尝试在控制台应用程序中做。
重要编辑:
我让它重复文本,然后速度变慢了。我意识到有内存泄漏!因此,在使用之后或重新创建表面之前,您必须使用 SDL_FreeSurface
删除它并使用 SDL_DestroyTexture
.
删除纹理
编辑 2:
因此,回应您的评论,这是您的 while 循环:
{
handleEvents(e, &quit);
if (textSurface != NULL)
{
SDL_FreeSurface(textSurface);
//textSurface = NULL; //optional
}
textSurface = TTF_RenderText_Solid(font, text.c_str(), color);
dstrect.w = textSurface->w; //change the width of rectangle
if (textTexture != NULL)
{
SDL_DestroyTexture(textTexture);
//textTexture = NULL;
}
textTexture = SDL_CreateTextureFromSurface(renderer, textSurface);
render(renderer, textTexture, srcrect, dstrect);
}
注意:您必须将 Surface
和 Texture
指针声明为 NULL,这样 if 部分才能工作。
所以,我正在开发一个命令提示符游戏,现在我从小处着手。我已经掌握了打印速度较慢的文本系统的基础知识,但我遇到了一个我不确定如何解决的问题。
基本上;文本会拉伸以适合预定义的框:
现在,一个解决方案是简单地扩展 SDL_Rect 以适合我的文本,并且由于我使用的是等宽字体,这将相当容易。但是我只是在想; "There must be a better way!".
最后,如果您需要的话,这是我的代码:
#include<iostream>
#include<SDL.h>
#include<string>
#include<SDL_ttf.h>
std::string text = "";
std::string textToAdd = "Hello there, how are you doing?";
int pos = 0;
void handleEvents(SDL_Event e, bool* quit){
while(SDL_PollEvent(&e) > 0){
if(e.type == SDL_QUIT){
*quit = true;
}
}
}
void render(SDL_Renderer* renderer, SDL_Texture* textToRender, SDL_Rect srcrect, SDL_Rect dstrect){
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, textToRender, &srcrect, &dstrect);
SDL_RenderPresent(renderer);
}
Uint32 calcText(Uint32 interval, void *param){
if(pos < textToAdd.length()){
text = text + textToAdd[pos];
pos++;
}
return interval;
}
int main( int argc, char *argv[] ) {
SDL_Init(SDL_INIT_EVERYTHING);
TTF_Init();
SDL_Window* window = SDL_CreateWindow("Game", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 600, 600, SDL_RENDERER_ACCELERATED);
SDL_Renderer* renderer = SDL_CreateRenderer(window, 0, 0);
bool quit = false;
SDL_Event e;
SDL_TimerID repeatText = SDL_AddTimer(70, calcText, NULL);
TTF_Font* font = TTF_OpenFont("Hack-Regular.ttf", 28);
SDL_Color color = {255, 255, 255};
SDL_Surface* textSurface;
SDL_Texture* textTexture;
SDL_Rect srcrect;
SDL_Rect dstrect;
srcrect.x = 0;
srcrect.y = 0;
srcrect.w = 580;
srcrect.h = 32;
dstrect.x = 10;
dstrect.y = 10;
dstrect.w = 580;
dstrect.h = 32;
while(!quit){
handleEvents(e, &quit);
render(renderer, textTexture, srcrect, dstrect);
textSurface = TTF_RenderText_Solid(font, text.c_str(), color);
textTexture = SDL_CreateTextureFromSurface(renderer, textSurface);
}
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
window = NULL;
renderer = NULL;
TTF_Quit();
SDL_Quit();
return 0;
}
我用了一些不同的方法。首先,我建议您阅读本教程:http://lazyfoo.net/tutorials/SDL/index.php。其次:尝试在关键点使用初始化检查,如本例所示:
//...
if (!myInitFunction())
{
//error message and quit without crash
}
else
{
//continue game
}
//...
让我们回到您的问题:
是的,有可能,如您所愿,从 surface->w
得到 dstrect.w
。但不是那么简单。因为一开始 运行 的 while 循环我们会崩溃,如果我们这样做 dstrect.w = surcface->h
那么你的游戏就会崩溃。为什么?因为字符串等于什么都没有:""
.
为避免这种情况,您应该简单地以一个带空格的字符串开始,或者在开始之前将 'H'
字符放在字符串中。 (实际上我没有使用 SDL_TimerID
而是用另一种方式制作的,但我不想让它复杂化。)
此外,您应该遵循 "order rule":INPUT >>> HANDLING >>> RENDER
。
因此您的代码应如下所示:
//...
std::string text = "H";
std::string textToAdd = "ello there, how are you doing?";
//...
while(!quit)
{
handleEvents(e, &quit);
textSurface = TTF_RenderText_Solid(font, text.c_str(), color);
dstrect.w = textSurface->w; //change the width of rectangle
textTexture = SDL_CreateTextureFromSurface(renderer, textSurface);
render(renderer, textTexture, srcrect, dstrect);
}
//...
另一个建议是尝试泛化这个渲染方法,如果你没有做过的话,尝试在控制台应用程序中做。
重要编辑:
我让它重复文本,然后速度变慢了。我意识到有内存泄漏!因此,在使用之后或重新创建表面之前,您必须使用 SDL_FreeSurface
删除它并使用 SDL_DestroyTexture
.
编辑 2: 因此,回应您的评论,这是您的 while 循环:
{
handleEvents(e, &quit);
if (textSurface != NULL)
{
SDL_FreeSurface(textSurface);
//textSurface = NULL; //optional
}
textSurface = TTF_RenderText_Solid(font, text.c_str(), color);
dstrect.w = textSurface->w; //change the width of rectangle
if (textTexture != NULL)
{
SDL_DestroyTexture(textTexture);
//textTexture = NULL;
}
textTexture = SDL_CreateTextureFromSurface(renderer, textSurface);
render(renderer, textTexture, srcrect, dstrect);
}
注意:您必须将 Surface
和 Texture
指针声明为 NULL,这样 if 部分才能工作。