Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

Architekt

Community-Fossil

Beiträge: 2 481

Wohnort: Hamburg

Beruf: Student

  • Private Nachricht senden

11

14.03.2014, 14:25

Du musst sie ständig updaten bzw. die Texture neu erstellen, sofern der Punktestand mit dem vorherigen nicht übereinstimmt, ja.

Aber dann wäre es doch einfacher, das Updaten genau dann durchzuführen, wenn die Punktezahl aktualisiert wurde.

Richtig.

Zitat


Du musst sie ständig updaten bzw. die Texture neu erstellen, sofern der Punktestand mit dem vorherigen nicht übereinstimmt, ja.
Der einfachste Weg eine Kopie zu entfernen ist sie zu löschen.
- Stephan Schmidt -

Architekt

Community-Fossil

Beiträge: 2 481

Wohnort: Hamburg

Beruf: Student

  • Private Nachricht senden

12

14.03.2014, 14:30

Alles klar. Braucht dies nicht massiv viel Speicher? Ich müsste doch die alten Texturen dann irgendwie wieder löschen?

Ja, das ist halt ein Nachteil an SDL_TTF. Aber ich habe ja erklärt wieso das irgendwie Sinn macht und wann es vermieden werden könnte.
Und ja, SDL_DestroyTexture muss natürlich dann aufgerufen werden. :)
Der einfachste Weg eine Kopie zu entfernen ist sie zu löschen.
- Stephan Schmidt -

Sacaldur

Community-Fossil

Beiträge: 2 301

Wohnort: Berlin

Beruf: FIAE

  • Private Nachricht senden

13

14.03.2014, 14:42

Du musst sie ständig updaten bzw. die Texture neu erstellen, sofern der Punktestand mit dem vorherigen nicht übereinstimmt, ja.

Aber dann wäre es doch einfacher, das Updaten genau dann durchzuführen, wenn die Punktezahl aktualisiert wurde.

Richtig.

Zitat


Du musst sie ständig updaten bzw. die Texture neu erstellen, sofern der Punktestand mit dem vorherigen nicht übereinstimmt, ja.

Das sind 2 verschiedene Dinge: Entweder wird in jedem Frame überprüft, ob es eine Änderung gab und ggf. die Textur neu erstellt oder es wird noch während der Änderung des Werts die Textur erstellt. In letzterem Fall ist keine Prüfung, die jeden Frame erneut durchgeführt wird, und keine Zwischenspeicherung des Werts, um die Prüfung durchführen zu können, notwendig.
Solltest du es aber genauso meinen wie ich, dann liegt es evtl. an der weiter oben stehenden Formulierung, dass ich das so verstehe:
Deswegen muss [...] jedesmal eine erneute SDL_Texture aus der durch SDL_TTF generierten SDL_Surface erzeugt werden. Aber um zumindest ein wenig neu Erzeugung zu sparen, sollte man schon prüfen, ob sich der Punktestand verändert hat.
Spieleentwickler in Berlin? (Thema in diesem Forum)
---
Es ist ja keine Schande etwas falsch zu machen, als Programmierer tu ich das täglich, [...].

Architekt

Community-Fossil

Beiträge: 2 481

Wohnort: Hamburg

Beruf: Student

  • Private Nachricht senden

14

14.03.2014, 14:51

Ich meine es so wie du. ;)
Der einfachste Weg eine Kopie zu entfernen ist sie zu löschen.
- Stephan Schmidt -

15

16.03.2014, 23:28

Vielen Dank für eure Antworten.
Ich habe mittlerweile die erste spielbare Version fertiggestellt. Bis dato ist nur Spieler vs. Spieler möglich. Mit "0" kann das Spielfeld gelöscht werden.

Ich konnte das Problem lösen, indem ich das Laden und Rendern der Textures in die Hauptschleife genommen habe.

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
while(bGameRun == true)
    {
        SDL_RenderClear(r_pRenderer);
        sBackground->Render("Hintergrund", 0, 0, 800, 600, r_pRenderer);

        Field->Choose();
        Field->Render();
        Field->Update();
        Field->CheckWin1(Player1);
        Field->CheckWin2(Player2);
    
        stringstream s;
        s << "Player 1: " << Player1;
        Spieler1->LoadText (s.str().c_str(), { 0, 0, 0 },".../AvenirNext.ttc", 20, "Player 1");
        Spieler1->RenderText(40, 90, 120, 24, "Player 1");
        
        stringstream b;
        b << "Player 2: " << Player2;
        Spieler2->LoadText (b.str().c_str(), { 0, 0, 0 },".../AvenirNext.ttc", 20, "Player 2");
        Spieler2->RenderText(40, 120, 120, 24, "Player 2");
        SDL_RenderPresent(r_pRenderer);
        
        if (g_pFramework->isKeyDown (SDL_SCANCODE_ESCAPE))
        {
            bGameRun = false;
        }
        
    }


Wichtig waren dann vor allem diese zusätzlichen Zeilen beim Laden der Schrift über eine Surface in eine Texture, womit ich
ein Überladen verhindern konnte und automatisch ein Überschreiben der alten Texture erreichen konnte.

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
    if (textImage[id] != NULL)
    {
       SDL_DestroyTexture(textImage[id]);
    }
    else
    {
        
    }
    textImage[id] = textTexture;
    TTF_CloseFont(fFont);
    fFont = NULL;
    return true;


Lg, Eric

Architekt

Community-Fossil

Beiträge: 2 481

Wohnort: Hamburg

Beruf: Student

  • Private Nachricht senden

16

17.03.2014, 11:38

Du öffnest und schließt aber nicht bei jedem loadText/renderText Vorgang eine TTF_Font oder? Die solltest du dir wenn möglich speichern und wiederverwenden. Außerdem, soweit ich das sehe, hast du nun in jedem Frame einen Reload (Zerstören und Neu anlegen) der Texture . Doch gerade das wurde ja diskutiert möglichst nicht in jedem Frame durchzuführen.
Der einfachste Weg eine Kopie zu entfernen ist sie zu löschen.
- Stephan Schmidt -

17

18.03.2014, 10:41

Doch, irgendwie funktioniert es sonst nicht. Wenn ich das Font nicht schliesse folgen diese Fehlermeldungen:

"Font konnte nicht geladen werden: Couldn't open .../AvenirNext.ttc"
"Font konnte nicht geladen werden: Couldn't open .../AvenirNext.ttc"
"Font konnte nicht geladen werden: Couldn't open .../AvenirNext.ttc"
"Font konnte nicht geladen werden: Couldn't open .../AvenirNext.ttc"
"Font konnte nicht geladen werden: Couldn't open .../AvenirNext.ttc"
"Font konnte nicht geladen werden: Couldn't open .../AvenirNext.ttc"
...

und das geht endlos so weiter. Im Programm selber funktioniert das Rendern der Punkte dann irgendwann auch nicht mehr.

Hier nochmals der ganze Code:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
bool CText::LoadText(string textureText, SDL_Color textColor, string fontFile, int fontSize, string id)
{
    
    // Font wird geladen
    fFont = TTF_OpenFont(fontFile.c_str(), fontSize );
    if( fFont == NULL )
    {
        cout << "Font konnte nicht geladen werden: " << TTF_GetError () << endl;
        return false;
    }
    else
    {
    
    // Der Text wird auf eine Surface gerendert
    SDL_Surface* textSurface = TTF_RenderText_Blended(fFont, textureText.c_str(), textColor );
    if( textSurface == NULL )
    {
        cout << "Text Surface konnte nicht gerendert werden: " << SDL_GetError () << endl;
        return 0;
    }
    else
    {
        // Von Surface zu einer Texture
        textTexture = SDL_CreateTextureFromSurface(r_pRenderer, textSurface);
        if( textTexture == NULL )
        {
            cout << "Text Template konnte nicht gerendert werden: " << SDL_GetError () << endl;
            return 0;
        }
        else
        {
            // Bild Dimension eintragen
            fWidth = textSurface->w;
            fHeight = textSurface->h;
        }
        
        // Alte Surface löschen
        SDL_FreeSurface( textSurface );
    }
    }
    // Erfolg!

    if (textImage[id] != NULL)
    {
       SDL_DestroyTexture(textImage[id]);
    }
    else
    {
        
    }
    textImage[id] = textTexture;
    TTF_CloseFont(fFont);
    fFont = NULL;
    return true;
}


Falls es irgendeine bessere Lösung gibt, bin ich immer froh um Feedback. Danke!

Architekt

Community-Fossil

Beiträge: 2 481

Wohnort: Hamburg

Beruf: Student

  • Private Nachricht senden

18

18.03.2014, 11:03

Du öffnest die TTF_Font auch nur einmal und speicherst dir dann den Zeiger darauf. Wenn dein internen TTF_Font Zeiger bspw. NULL ist (wobei nullptr vorzuziehen wäre), dann lädst du die TTF_Font und speicherst den Zeiger, damit du den Kram nicht noch einmal öffnen musst.
Der einfachste Weg eine Kopie zu entfernen ist sie zu löschen.
- Stephan Schmidt -

19

19.03.2014, 10:58

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
bool CText::LoadText(string textureText, SDL_Color textColor, string fontFile, int fontSize, string id)
{
    
    // Font wird geladen
    
    if( fFont == nullptr )
    {
        fFont = TTF_OpenFont(fontFile.c_str(), fontSize );
    }
    
    else
    {
    }
    
    // Der Text wird auf eine Surface gerendert
    SDL_Surface* textSurface = TTF_RenderText_Blended(fFont, textureText.c_str(), textColor );
    if( textSurface == nullptr )
    {
        cout << "Text Surface konnte nicht gerendert werden: " << SDL_GetError () << endl;
        return 0;
    }
    else
    {
        // Von Surface zu einer Texture
        textTexture = SDL_CreateTextureFromSurface(r_pRenderer, textSurface);
        if( textTexture == nullptr )
        {
            cout << "Text Template konnte nicht gerendert werden: " << SDL_GetError () << endl;
            return 0;
        }
        else
        {
            // Bild Dimension eintragen
            fWidth = textSurface->w;
            fHeight = textSurface->h;
        }
        
        // Alte Surface löschen
        SDL_FreeSurface( textSurface );
    }
    
    // Erfolg!
    if (textImage[id] != nullptr)
    {
        SDL_DestroyTexture(textImage[id]);
    }
    else
    {
        
    }
    textImage[id] = textTexture;
    return true;
}


So? Interessant ist, dass im Internet auf den meisten Seiten eine andere Vorgehensweise gewählt wird. Logischer erscheint aber
tatsächlich dieser Weg hier. So muss die Font nicht ständig auf nullptr gesetzt werden bzw. geschlossen werden.

Achja und dieser Code ist entscheidend, wenn ich denn nicht reinmache, dann steigt der Speicher langsam langsam langsam an bis der Mac abstürzt ;)

C-/C++-Quelltext

1
2
3
4
5
6
7
8
 if (textImage[id] != nullptr)
    {
        SDL_DestroyTexture(textImage[id]);
    }
    else
    {
        
    }

Architekt

Community-Fossil

Beiträge: 2 481

Wohnort: Hamburg

Beruf: Student

  • Private Nachricht senden

20

19.03.2014, 11:16

Natürlich, du musst den Speicher den die vorherige Texture beschlagnahmte ja auch wieder freigeben, sobald du ihn nicht mehr brauchst. :)
Der einfachste Weg eine Kopie zu entfernen ist sie zu löschen.
- Stephan Schmidt -

Werbeanzeige