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 может работать.

Другие вопросы по тегам