4 Stimmen

C++ SDL2, Wie aktualisiere ich regelmäßig einen gerenderten Text? (ttf)

Also habe ich in den letzten 6 Stunden geübt/ein schnelles Spiel erstellt, dann hat mich etwas verblüfft. Das Spiel hatte einen Ganzzahl-Wert, Score, der jedes Mal um eins erhöht werden sollte, wenn eine Munition ein Alien trifft.

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;

//BEREICH AKTUALISIERUNG/SPIELSCHLEIFE, ICH HABE NICHT DEN GANZEN TEIL EINGEFÜGT
SDL_RenderCopy(renderer, Message, NULL, &Message_rect);

Jetzt habe ich verschiedene Umwege versucht, wie ich die Textur, Message, aktualisieren kann. Ich habe eine cout-Überprüfung erstellt, um zu überprüfen, ob ich ein Alien getroffen habe und was mein aktueller Score ist, es scheint alles in Ordnung zu sein, aber die gerenderte Textur, Message, bewegt sich nicht von 0.

Ich habe eine Textur aus der Oberfläche (der Nachricht) erstellt, weil ich hauptsächlich Texturen bevorzuge und ich keine Oberfläche habe, da ich in meinem aktuellen Kenntnisstand mindestens eine gefüllte Oberfläche benötigen würde, über die ich dies schneller tun könnte

Und noch eine Frage, ich plane, ein dialoglastiges Spiel zu erstellen, gibt es einen anderen Weg, die Texte zu erstellen? Ich habe das starke Gefühl, dass ich es falsch mache.

3voto

Minimaler ausführbarer Beispiel

Bildbeschreibung hier eingeben

Der Zähler wird alle Sekunde aktualisiert.

Ubuntu 16.10, SDL 2.0.4:

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

Diese Methode ist einfach zu integrieren, aber nicht sehr effizient, da sie ständig neu erstellt Texturen und Raster-Bilder. Wenn Sie auch Effizienz wünschen, siehe: Schriftarten und Texte mit SDL2 effizient rendern Ich bekomme 4k FPS, also könnte es für einfache Anwendungen in Ordnung sein.

GitHub upstream mit einer ttf-Datei zum Testen: https://github.com/cirosantilli/cpp-cheat/blob/d36527fe4977bb9ef4b885b1ec92bd0cd3444a98/sdl/ttf.c:

#include 
#include 
#include 

#include 
#include 

#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: obere linke Ecke des Strings
- Rechteck-Ausgabebreite und -höhe enthalten die gerenderten Abmessungen.
*/
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;
    /* Dies ist für Texturen, die gleich bleiben, verschwenderisch.
     * Macht die Dinge jedoch weniger zustandsbehaftet und einfacher zu verwenden.
     * Werden wir hier eine Atlaslösung kodieren...? */
    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];

    /* Befehlszeilenargumente. */
    if (argc == 1) {
        font_path = "FreeSans.ttf";
    } else if (argc == 2) {
        font_path = argv[1];
    } else {
        fprintf(stderr, "Fehler: Zu viele Argumente\n");
        exit(EXIT_FAILURE);
    }

    /* Variablen initialisieren. */
    color.r = COMMON_COLOR_MAX;
    color.g = COMMON_COLOR_MAX;
    color.b = COMMON_COLOR_MAX;
    color.a = COMMON_COLOR_MAX;

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

    /* TTF initialisieren. */
    TTF_Init();
    TTF_Font *font = TTF_OpenFont(font_path, 24);
    if (font == NULL) {
        fprintf(stderr, "Fehler: Schriftart nicht gefunden\n");
        exit(EXIT_FAILURE);
    }

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

        /* TTF verwenden. */
        SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
        SDL_RenderClear(renderer);
        render_text(renderer, 0, 0,               "Hallo", font, &rect, &color);
        render_text(renderer, 0, rect.y + rect.h, "Welt", 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();
    }

    /* Aufräumen. */
    TTF_Quit();
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();
    return EXIT_SUCCESS;
}

2voto

Petr Abdulin Punkte 32034

Nun, offensichtlich müssen Sie jedes Mal, wenn sich Ihr Score ändert, die Textur von der Oberfläche mit neuem Text neu erstellen. Das ist nicht sehr effizient für Texte, die sich häufig ändern (da Sie viele Oberflächen/Texturen erstellen/zerstören), kann jedoch für kleine Spiele in Ordnung sein (da moderne Computer sehr leistungsstark sind).

Im Allgemeinen werden, wie in den Kommentaren erwähnt, in diesem Fall Schriftschnitte in Kombination mit benutzerdefinierten Textrenderern verwendet. Der Trick besteht darin, alle Zeichen in einer Textur zu speichern und ihre Bereiche mehrmals zu rendern, um den erforderlichen Text zu erzeugen. Das AngelCode BMFont ist ein beliebtes Tool zur Erstellung von Schriftschnitten.

Für maximale Leistung werden beide Ansätze in Kombination verwendet: vorab erstellte Texturen für statischen Text und Schriftschnitte für dynamischen Text.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X