С++ SDL2, как регулярно обновлять визуализированный текст? (ттф)

Итак, я практиковался/делал быструю игру последние 6 часов, потом что-то поставило меня в тупик. В игре было целое число Score, которое добавлялось к единице каждый раз, когда боеприпасы попадали в инопланетянина.

int Score;
stringstream sstr;
sstr << Score;
string str1 = sstr.str();

TTF_Font* Sans = NULL;
Sans = TTF_OpenFont("Sans.ttf", 24);
SDL_Color White = {255, 255, 255};  
SDL_Surface* surfaceMessage = NULL;
surfaceMessage = TTF_RenderText_Solid(Sans, str1.c_str(), White);
SDL_Texture* Message = NULL;
Message = SDL_CreateTextureFromSurface(renderer, surfaceMessage);

SDL_Rect Message_rect;
Message_rect.x = 0;
Message_rect.y = 0;
Message_rect.w = 100;
Message_rect.h = 100;

//UPDATE/GAMELOOP AREA, I DIDN'T REALLY PASTE THE WHOLE PART
SDL_RenderCopy(renderer, Message, NULL, &Message_rect);

Сейчас пробовал разными обходными путями, как обновить текстуру, Сообщение. Я сделал проверку cout, чтобы проверить, не попал ли я в инопланетянина, и каков мой текущий счет, он выглядит совершенно нормально, но визуализированная текстура, сообщение, не сдвинется с 0.

Я создал текстуру из поверхности (сообщения), потому что я в основном предпочитаю текстуры, и у меня нет поверхности, поскольку, насколько мне известно, вам, по крайней мере, нужна заполненная поверхность, где вы могли бы блицировать это

И еще вопрос, я планирую сделать диалоговую игру тяжелой, есть ли другой способ сделать тексты? У меня есть стойкое ощущение, что я делаю это неправильно.


person kdyz    schedule 04.04.2014    source источник
comment
Если вы не перерисовываете текстуру, то она, конечно, не меняется... Что касается больших объемов текста - может быть лучше создать атлас, содержащий все нужные вам глифы (графическое представление символов), и просто собрать линию по символам -условное обозначение.   -  person keltar    schedule 04.04.2014
comment
Я перерисовываю его в своем игровом цикле, затем я пытался повторно обновлять текстуру и сообщение о поверхности каждый раз, когда мой счет получает еще один +1, но визуализированный текст все еще не изменится... В любом случае, мне любопытно, что это за Атлас. , позвольте мне поискать об этом, спасибо за информацию об атласе: D   -  person kdyz    schedule 04.04.2014
comment
Вот как я это сделал: посмотрите на ответ Руцкого stackoverflow.com /questions/29003216/sdl2-rendering-text-issues   -  person doomglhfcn    schedule 12.03.2015


Ответы (2)


Минимальный запускаемый пример

введите здесь описание изображения

Счетчик обновляется каждую секунду.

Ubuntu 16.10, SDL 2.0.4:

sudo apt-get install libsdl2-dev libsdl2-ttf-dev
./main /path/to/my.ttf

Этот метод легко интегрировать, но он не очень эффективен, так как он постоянно повторно растрирует и воссоздает текстуры. Если вам также нужна эффективность, см.: Эффективный рендеринг шрифтов и текста с помощью SDL2 У меня 4k FPS, так что для простых приложений может подойти.

Восходящий поток GitHub с файлом ttf для тестирования: https://github.com/cirosantilli/cpp-cheat/blob/d36527fe4977bb9ef4b885b1ec92bd0cd3444a98/sdl/ttf.c:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>

#define COMMON_COLOR_MAX 255
#define COMMON_WINDOW_WIDTH 500
#define COMMON_WINDOW_HEIGHT (COMMON_WINDOW_WIDTH)

double common_get_secs(void) {
    struct timespec ts;
    timespec_get(&ts, TIME_UTC);
    return ts.tv_sec + (1e-9 * ts.tv_nsec);
}
const double COMMON_FPS_GRANULARITY_S = 0.5;
double common_fps_last_time_s;
unsigned int common_fps_nframes;
void common_fps_init() {
    common_fps_nframes = 0;
    common_fps_last_time_s = common_get_secs();
}
void common_fps_update_and_print() {
    double dt, current_time_s;
    current_time_s = common_get_secs();
    common_fps_nframes++;
    dt = current_time_s - common_fps_last_time_s;
    if (dt > COMMON_FPS_GRANULARITY_S) {
        printf("FPS = %f\n", common_fps_nframes / dt);
        common_fps_last_time_s = current_time_s;
        common_fps_nframes = 0;
    }
}

#define MAX_STRING_LEN 4

/*
- x, y: upper left corner of string
- rect output Width and height contain rendered dimensions.
*/
void render_text(
    SDL_Renderer *renderer,
    int x,
    int y,
    const char *text,
    TTF_Font *font,
    SDL_Rect *rect,
    SDL_Color *color
) {
    SDL_Surface *surface;
    SDL_Texture *texture;

    surface = TTF_RenderText_Solid(font, text, *color);
    texture = SDL_CreateTextureFromSurface(renderer, surface);
    rect->x = x;
    rect->y = y;
    rect->w = surface->w;
    rect->h = surface->h;
    /* This is wasteful for textures that stay the same.
     * But makes things less stateful and easier to use.
     * Not going to code an atlas solution here... are we? */
    SDL_FreeSurface(surface);
    SDL_RenderCopy(renderer, texture, NULL, rect);
    SDL_DestroyTexture(texture);
}

int main(int argc, char **argv) {
    SDL_Color color;
    SDL_Event event;
    SDL_Rect rect;
    SDL_Renderer *renderer;
    SDL_Window *window;
    char *font_path, text[MAX_STRING_LEN];

    /* CLI arguments. */
    if (argc == 1) {
        font_path = "FreeSans.ttf";
    } else if (argc == 2) {
        font_path = argv[1];
    } else {
        fprintf(stderr, "error: too many arguments\n");
        exit(EXIT_FAILURE);
    }

    /* initialize variables. */
    color.r = COMMON_COLOR_MAX;
    color.g = COMMON_COLOR_MAX;
    color.b = COMMON_COLOR_MAX;
    color.a = COMMON_COLOR_MAX;

    /* Init window. */
    SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO);
    SDL_CreateWindowAndRenderer(
        COMMON_WINDOW_WIDTH,
        COMMON_WINDOW_WIDTH,
        0,
        &window,
        &renderer
    );

    /* Init TTF. */
    TTF_Init();
    TTF_Font *font = TTF_OpenFont(font_path, 24);
    if (font == NULL) {
        fprintf(stderr, "error: font not found\n");
        exit(EXIT_FAILURE);
    }

    /* Main loop. */
    common_fps_init();
    while (1) {
        if (SDL_PollEvent(&event) && event.type == SDL_QUIT) {
            break;
        }

        /* Use TTF. */
        SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
        SDL_RenderClear(renderer);
        render_text(renderer, 0, 0,               "hello", font, &rect, &color);
        render_text(renderer, 0, rect.y + rect.h, "world", font, &rect, &color);
        snprintf(text, MAX_STRING_LEN, "%u", (unsigned int)(time(NULL) % 1000));
        render_text(renderer, 0, rect.y + rect.h, text, font, &rect, &color);
        SDL_RenderPresent(renderer);

        common_fps_update_and_print();
    }

    /* Cleanup. */
    TTF_Quit();
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();
    return EXIT_SUCCESS;
}
person Ciro Santilli 新疆再教育营六四事件ۍ    schedule 27.12.2016

Ну, очевидно, вам нужно воссоздавать текстуру с поверхности с новым текстом каждый раз, когда ваш счет меняется. Это не очень эффективно для текстов, которые часто меняются (поскольку вы создаете/уничтожаете много поверхностей/текстур), но может подойти для небольших игр (поскольку современные компьютеры очень мощные).

Но обычно, как упоминалось в комментариях, для этого случая используются атласы шрифтов с комбинацией пользовательских текстовых рендереров. Хитрость заключается в том, чтобы хранить все символы в одной текстуре и рендерить ее области несколько раз для получения необходимого текста. AngelCode BMFont — популярный инструмент для создания атласов шрифтов.

Для достижения максимальной производительности оба подхода используются в комбинации: предварительно созданные текстуры для статического текста и атласы шрифтов для динамического текста.

person Petr Abdulin    schedule 27.07.2015