C++ SDL2, Cum se actualizează în mod regulat un text redat? (ttf) (Programare, C++, Sdl, Fonturi True Type, Sdl 2, Redarea Textului)

kdyz a intrebat.

Deci, am practicat / făcut un joc rapid în ultimele 6 ore, apoi ceva m-a blocat. jocul avea un număr întreg, Score, care ar fi fost adăugat cu unu de fiecare dată când o muniție lovește un extraterestru.

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);

Acum am încercat diferite rotițe cum să actualizez textura, Message. am făcut o verificare cout pentru a verifica dacă am lovit un extraterestru și care este scorul meu actual, pare perfect în regulă, dar textura redată, Message nu se va muta de la 0.

Am creat o textură de la suprafață (Mesaj) pentru că prefer mai ales texturile și nu am nicio suprafață, deoarece în cunoștințele mele actuale, ar fi nevoie cel puțin de o suprafață umplută unde să poți blitz-ui asta

Și încă o întrebare, intenționez să fac un joc cu dialoguri grele, există o altă modalitate de a face textele? Am o senzație puternică că o fac greșit.

Comentarii

  • Dacă nu redesenezi textura, normal că nu se schimbă… În ceea ce privește cantitățile mari de text – s-ar putea să fie mai bine să creezi un atlas care să conțină toate glifele (reprezentarea grafică a simbolurilor) de care ai nevoie și să asamblezi doar linia simbol cu simbol. –  > Por keltar.
  • Îl redesenez, în gameloop-ul meu, apoi am încercat să reactualizez textura și mesajul de suprafață de fiecare dată când scorul meu primește încă +1, dar textul redat tot nu se schimbă… Oricum, sunt curios în legătură cu chestia asta cu Atlasul, lasă-mă să caut despre asta, mulțumesc pentru informația despre atlas 😀 – -.  > Por kdyz.
  • Iată cum am făcut-o: uitați-vă la răspunsul lui rutsky ‘s stackoverflow.com/questions/29003216/sdl2-rendering-text-issues –  > Por doomglhfcn.
2 răspunsuri
Ciro Santilli新疆棉花TRUMP BAN BAD

Exemplu minim executabil

Contorul este actualizat la fiecare secundă.

Ubuntu 16.10, SDL 2.0.4:

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

Această metodă este ușor de integrat, dar nu este foarte eficientă, deoarece reface și recreează texturi tot timpul. Dacă doriți, de asemenea, eficiență, vedeți: „Eficiență”: Renderizarea eficientă a fonturilor și a textului cu SDL2 Obțin 4k FPS, deci ar putea fi bună pentru aplicații simple.

GitHub upstream cu un fișier ttf cu care să testați: 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
", 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
");
        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
");
        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;
}

Petr Abdulin

Ei bine, în mod evident, trebuie să recreezi textura din suprafață cu text nou de fiecare dată când se schimbă scorul. Acest lucru nu este foarte eficient pentru texte care se schimbă frecvent (din moment ce creați/distrugeți o mulțime de suprafețe/texturi), dar poate fi bine pentru jocuri mici (din moment ce calculatoarele moderne sunt foarte puternice).

Dar, în general, așa cum s-a menționat în comentarii, pentru acest caz se folosesc atlase de fonturi în combinație cu redactori de text personalizați. Trucul este de a stoca toate caracterele într-o singură textură și de a reda regiunile sale de mai multe ori pentru a produce textul necesar. Site-ul AngelCode BMFont este un instrument popular pentru crearea de atlase de fonturi.

Pentru o performanță maximă, ambele abordări sunt utilizate în combinație: texturi precreate pentru text static și atlase de fonturi pentru text dinamic.