SDL_TTF медленный эффект печати
Итак, я работаю над игрой из командной строки, и сейчас я начинаю с малого. Я изучил основы медленной системы печати текста, но столкнулся с проблемой, которую не знаю, как ее исправить.
В принципе; текст растягивается до предопределенного поля: и под предопределенным блоком я подразумеваю SDL_Rect, который я определил как srcrect и dstrect.
Теперь решением было бы просто расширить SDL_Rect, чтобы он соответствовал моему тексту, и, поскольку я использую моноширинный шрифт, это будет довольно легко. Но я просто ушел думать; "Должен быть лучший способ!".
Наконец, вот мой код, если вам это нужно:
#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;
}
1 ответ
Я сделал это, используя немного разные методы. Прежде всего, я предлагаю вам прочитать этот учебник: http://lazyfoo.net/tutorials/SDL/index.php. Во-вторых: попробуйте использовать проверки инициализации в критических точках, как в этом примере:
//...
if (!myInitFunction())
{
//error message and quit without crash
}
else
{
//continue game
}
//...
Давайте вернемся к вашей проблеме:
Да возможно, что хочешь, получая dstrect.w
от surface->w
, Но не все так просто. Потому что при первом запуске цикла while мы попадаем в аварию, если dstrect.w = surcface->h
тогда ваша игра вылетает. Зачем? Потому что строка равна нулю: ""
,
Чтобы избежать этого, вы должны просто начать с пробела или поставить 'H'
символ в строке перед началом. (На самом деле я сделал это по-другому, не используя SDL_TimerID
но я не хочу усложнять это.)
Также вы должны следовать "правилу заказа": 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 может работать.