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

1

24.03.2012, 17:27

SDL_ttf: Kein Text sichtbar

Hallo liebe community,

ich habe nun das Buch "C++ für Spieleprogrammierer" durch und bin jetzt dabei das SDL-Game aus dem letzten Kapitel zu erweitern.
Ich habe dazu schon ein Hauptmenü gestaltet über das man unter anderem zum Highscore kommt.
Die aktuelle Punktzahl im Spiel sowie den Highscore habe ich auch schon integriert, die Ausgabe der Werte folgt aber noch (zu Testzwecken) über die Win32-Konsole.



Jetzt möchte ich die Ausgabe natürlich im Fenster machen und bin dann auf SDL_ttf gestoßen, dass ich mittlerweile auch eingebettet habe und nun versuche eine Textausgabe beim Highscore hinzubekommen. Dazu folgende Quellcode-Ausschnitte, die zeigen, wie ich mir das gedacht habe:



Die Klasse CTff:

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include "SDL.h"
#include "SDL_ttf.h"
#include <string>
#include <iostream>

using namespace std;

class CTff
{

public:
    //Instanzen
    SDL_Surface *message;
    TTF_Font *font;

    bool init()
    {
        //Initialisierung
     if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 )
     {
         //Fehlermeldung 
         cout << "Fehler bei SDL_Init" << endl;
         cin.get();
         return false;    
     }
    
     //SDL_ttf initialisieren
        if( TTF_Init() == -1 )
     {
         //Fehlermeldung
         cout << "Fehler bei Tff_Init" << endl;
         cin.get();
         return false;    
     }
    
    //Alles gut gegangen
    return true;
    }

    bool load_files()
    {    
        //Font öffnen
        font = TTF_OpenFont( "Data/FreeSans.ttf", 30);
    
        if( font == NULL )
         {
             //Fehlermeldung
             cout << "Fehler bei Font" << endl;
             cin.get();
             return false;
         }
    
         //Alles gut gegangen
        return true;    
    }

    void clean_up()
    {
    //Freigeben
    SDL_FreeSurface(message);

    //Font schließen
    TTF_CloseFont(font);

    //Quit SDL_ttf
    TTF_Quit();
    }   

};


Highscore.cpp-Auschnitt (Hier soll die Textausgabe erfolgen):

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
56
57
58
59
60
61
62
63
64
65
//Run
//Aufgabe: Hauptschleife des Highscores
int CHighscore::Run()
{
    //Hauptschleife des Spiels durchlaufen
    while (m_bHighscoreRun == true)
    {

        //Text laden und ausgeben
        SDL_Color textColor = {0, 0, 0 };
        Tff.message = NULL;
        Tff.font = NULL;

        //Initialisieren
        if (Tff.init() == false )
        {
            std::cerr << "Konnte SDL_ttf nicht initialisieren! Fehler: " << TTF_GetError() << std::endl;
            return 1;
        }

        //Dateien laden
        if(Tff.load_files() == false )
        {
            std::cerr << "Konnte Dateien nicht laden! Fehler: " << TTF_GetError() << std::endl;
            return 1;
        }

        //Text renden
        Tff.message = TTF_RenderText_Solid( Tff.font, "Wo ist mein Text?", textColor);

        //Text Position
        SDL_Rect textPosition;
        textPosition.x = 300;
        textPosition.y = 300;
        SDL_BlitSurface(Tff.message, 0, Framework.m_pScreen, &textPosition);



        if( Tff.message == NULL )
        {
            //Fehlermeldung
            cout << "Fehler bei Render" << endl;
            cin.get();
            return 1;
        }   

        //Events bearbeiten
        ProcessEvents();
         
        //Freigeben
        Tff.clean_up();
        
        //Framework updaten und Buffer löschen
        g_pFramework->Update();
        g_pFramework->Clear();

        //Bilder rendern
        m_pSpriteBackground->Render();

        //Buffer flippen
        g_pFramework->Flip();

    }

}


Jetzt habe ich folgende Probleme:

1. Starte ich im "Release"-Modus funktioniert das Menü, das Spiel und ich komm zum Bildschirm wo die Textausgabe stehen sollte. Jedoch sieht man dort nur den Hintergrund aber kein Text! Dazu bekomme ich nur gelegentlich und auch nur ca. 5-10sec nachdem ich im Highscoremenü bin, die Rückmeldung "Fehler bei Font" (Fehlermeldung habe ich ja selber eingebaut)

2. Starte ich im "Debug"-Modus, startet das Spiel erst gar nicht und ich bekomm folgende Debug-Fehlermeldung:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
1>d:\projekte\sdl_game2\sdl_game2\start.cpp(128): warning C4715: "CStart::Run": Nicht alle Steuerelementpfade geben einen Wert zurück.
1>CGame.obj : error LNK2019: Verweis auf nicht aufgelöstes externes Symbol "__imp___CrtDbgReportW" in Funktion ""public: class std::_List_const_iterator<class std::_List_val<class CAsteroid,class std::allocator<class CAsteroid> > > & __thiscall std::_List_const_iterator<class std::_List_val<class CAsteroid,class std::allocator<class CAsteroid> > >::operator++(void)" (??E?$_List_const_iterator@V?$_List_val@VCAsteroid@@V?$allocator@VCAsteroid@@@std@@@std@@@std@@QAEAAV01@XZ)".
1>CHighscore.obj : error LNK2001: Nicht aufgelöstes externes Symbol "__imp___CrtDbgReportW".
1>CPlayer.obj : error LNK2001: Nicht aufgelöstes externes Symbol "__imp___CrtDbgReportW".
1>CHighscore.obj : error LNK2019: Verweis auf nicht aufgelöstes externes Symbol "_TTF_RenderText_Solid" in Funktion ""public: int __thiscall CHighscore::Run(void)" (?Run@CHighscore@@QAEHXZ)".
1>CHighscore.obj : error LNK2019: Verweis auf nicht aufgelöstes externes Symbol "_TTF_Init" in Funktion ""public: bool __thiscall CTff::init(void)" (?init@CTff@@QAE_NXZ)".
1>CHighscore.obj : error LNK2019: Verweis auf nicht aufgelöstes externes Symbol "_TTF_OpenFont" in Funktion ""public: bool __thiscall CTff::load_files(void)" (?load_files@CTff@@QAE_NXZ)".
1>CHighscore.obj : error LNK2019: Verweis auf nicht aufgelöstes externes Symbol "_TTF_Quit" in Funktion ""public: void __thiscall CTff::clean_up(void)" (?clean_up@CTff@@QAEXXZ)".
1>CHighscore.obj : error LNK2019: Verweis auf nicht aufgelöstes externes Symbol "_TTF_CloseFont" in Funktion ""public: void __thiscall CTff::clean_up(void)" (?clean_up@CTff@@QAEXXZ)".
1>D:\Projekte\SDL_Game2\Debug\SDL_Game2.exe : fatal error LNK1120: 6 nicht aufgelöste externe Verweise.


Die Debug-meldung deutet ja darauf hin, dass irgendwas mit dem Linker nicht funktioniert, doch warum geht es dann im Release-Modus?
Und warum bekomm ich keine Textausgabe im Release-Modus?
Könnt ihr mir weiterhelfen?


Gruß theBeGinner

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

2

24.03.2012, 17:56

1. Du hast die Libraries (.lib) wohl nur bei Release eingetragen und bei Debug vergessen.

2. Du rufst in jedem Durchlauf deiner while-Schleife die init- und load_files-Methoden auf. Total unnötig. Warum sollen die Daten in jedem Frame neu geladen und dann wieder weggeworfen werden?

3. Außerdem glaube ich, dass du das Konzept von Klassen nicht verstanden hast. Deine Klasse "CTff" (sollte es nicht "CTtf" heißen?) ist einfach totaler Murks. Eine Klasse soll eine Art von Objekt repräsentieren. Das sehe ich hier nicht.

-> zurück zu den Grundlagen, dann mit Spielen weitermachen.

3

24.03.2012, 19:23

1. Du hast die Libraries (.lib) wohl nur bei Release eingetragen und bei Debug vergessen.

Ok, wie kann ich sie zusätzlich bei Debug eintragen?
Wird das nicht automatisch für beides gemacht?

2. Du rufst in jedem Durchlauf deiner while-Schleife die init- und load_files-Methoden auf. Total unnötig. Warum sollen die Daten in jedem Frame neu geladen und dann wieder weggeworfen werden?

Ok werde ich verbessern!

3. Außerdem glaube ich, dass du das Konzept von Klassen nicht verstanden hast. Deine Klasse "CTff" (sollte es nicht "CTtf" heißen?) ist einfach totaler Murks. Eine Klasse soll eine Art von Objekt repräsentieren. Das sehe ich hier nicht.
-> zurück zu den Grundlagen, dann mit Spielen weitermachen.

Du meinst wohl, weil ich die Funktionen direkt in der Klasse aufrufe, sowie meine Variablen nicht "privatisiere" oder?
Mir ist das Konzept der Klassen durchaus klar, ich möchte jedoch dazu sagen, dass dies nur ein erster Testversuch war einen Text auf den Bildschirm zu bekommen und ich der Einfachheit halber auf oben genanntes verzichtet habe.
Das werde ich schon noch objektorientiert gestalten, es war wie gesagt ein erster Test!

Trotz allem hätte aber beim Release-Modus ein Text erscheinen müssen oder nicht? Warum funktioniert das nicht?

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

4

24.03.2012, 19:49

Für einen "ersten Test" würdest du aber kaum extra eine neue Klasse machen, oder?

Ich habe keine Ahnung, was dein Code tut.
Aber es sieht so aus, als ob du zuerst den Text anzeigst und dann später etwas namens "SpriteBackground" darüber anzeigst, so dass der Text verdeckt wird.

5

27.03.2012, 00:43

Also ich hab das jetzt alles nochmal überarbeitet, die Variablen der Klasse CTtf hab ich der Einfachheit halber nicht privatisiert.
Folgend sind die Quelltexte der Klasse CTtf (.hpp und .cpp), CHighscore (wo die Textausgabe erfolgen soll) und das Framework (also das Grundgerüst für das Fenster der SDL):

TTFFont.hpp:

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
#ifndef TTFFont_HPP
#define TTFFont_HPP

#include "SDL.h"
#include "SDL_ttf.h"
#include <iostream>

using namespace std;

class CTtf
{
public:

    //Instanzen
    SDL_Surface *m_pMessage;
    TTF_Font *m_pFont;

    //Memberfunktionen
    CTtf();             //Konstruktor
    bool Init();
    bool LoadFiles();
    void Quit();
};

#endif



TTFFont.cpp:

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
#include "TFF_Font.hpp"

//Konstruktor
//Aufgabe: Allgemeine Initialisierung
CTtf::CTtf()
{
    m_pMessage = NULL;
    m_pFont = NULL;
}

//Init
//Aufgabe: Initialisierung des Bildschirms
bool CTtf::Init()
{
    //TTF initialisieren
    if(TTF_Init() == -1)
    {
        return false;
    }

    //Alles geklappt
    return true;
}

//LoadFiles
//Aufgabe: Dateien laden
bool CTtf::LoadFiles()
{
    //Font öffnen
    m_pFont = TTF_OpenFont("Data/FreeSerif.ttf", 28);

    //Fehlerabfrage
    if(m_pFont == NULL)
    {
        cout << "Fehler bei Font" << endl;
    }

    //Alles geklappt
    return true;
}

//Quit
//Aufgabe: Freigeben
void CTtf::Quit()
{
    //Surface freigeben
    SDL_FreeSurface(m_pMessage);

    //Font schließen
    TTF_CloseFont(m_pFont);

    //Quit SDL_ttf
    TTF_Quit();
}



CHighscore.cpp (Ausschnitt Run()):

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
void CHighscore::Run()
{
    SDL_Color TextColor = {255,255,200};
    
    //Initialisieren
    if(Ttf.Init() == false)
    {
        cout << "Fehler bei Init!" << endl;
        cin.get();
    }

    //Dateien laden
    if(Ttf.LoadFiles() == false )
    {
        cout << "Fehler bei LoadFiles!" << endl;
        cin.get();
    }
    
    //Hauptschleife des Spiels durchlaufen
    while (m_bHighscoreRun == true)
    {
        
        //Events bearbeiten
        ProcessEvents();
        
        //Framework updaten und Buffer löschen
        g_pFramework->Update();
        g_pFramework->Clear();

        //Hintergrundbild rendern
        m_pSpriteBackground->Render();
        
        //Text rendern
        Ttf.m_pMessage = TTF_RenderText_Solid(Ttf.m_pFont, "Hallo", TextColor );

         //Fehlermeldung
        if(Ttf.m_pMessage == NULL)
        {
             cout << "Fehler bei Rendern!" << endl;
             cin.get();
         }
        
        //Buffer flippen
        g_pFramework->Flip();

        //Freigeben
        Ttf.Quit();
    }
}



Framework.cpp:

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#include "CFramework.hpp"

//Init
//Aufgabe: Framework initialisieren
bool CFramework::Init(int ScreenWidth, int ScreenHeight, int ColorDepth, bool bFullscreen)
{
    //Alle Systeme der SDL initialisieren
    if (SDL_Init (SDL_INIT_VIDEO | SDL_INIT_TIMER) == -1)
    {
        cout << "SDL konnte nicht initialisiert werden!" << endl;
        cout << "Fehlermeldung: " << SDL_GetError() << endl;
        cin.get();

        Quit();
        
        return (false);
    }

    //Vollbild oder Fenstermodus
    if (bFullscreen == true)
    {
        m_pScreen = SDL_SetVideoMode (ScreenWidth, ScreenHeight, ColorDepth, SDL_HWSURFACE | SDL_DOUBLEBUF);

    }

    else
    {
        m_pScreen = SDL_SetVideoMode (ScreenWidth, ScreenHeight, ColorDepth, SDL_HWSURFACE | SDL_DOUBLEBUF);
    }

    //Prüfen ob alles funktioniert hat
    if (m_pScreen == NULL)
    {
        cout << "Videomodus konnte nicht gesetzt werden!" << endl;
        cout << "Fehlermeldung: " << SDL_GetError() << endl;
        cin.get();

        Quit();

        return (false); //hat nicht funktioniert also "false" zurückliefern
    }
    
    //Zeiger auf internes Array für Tastaturstatus ermitteln
    m_pKeystate = SDL_GetKeyState (NULL);

    //Alles ging glatt also "true" zurückliefern
    return (true);
}

//Quit
//Aufgabe: Framework (SDL) beenden
void CFramework::Quit()
{
    //SDL beenden, gibt auch automatisch den reservierten Speicher von "m_pScreen" wieder frei
    SDL_Quit();
}

//Update
//Aufgabe: Timer und Keyboardstatus updaten
void CFramework::Update()
{
    //timer updaten
    g_pTimer-> Update();

    //Tastaturstatus ermitteln
    SDL_PumpEvents();
}

//Keydown
//Aufgabe: Tastendruck abfragen
bool CFramework::KeyDown(int Key_ID)
{
    //Prüfen ob Taste gedrückt ist
    return (m_pKeystate[Key_ID] ? true : false);
}

//Clear
//Aufgabe: Buffer löschen
void CFramework::Clear()
{
    //Buffer(Surface) mit Hintergrundfarbe füllen und damit das zuvor gerenderte Surface löschen
    SDL_FillRect(m_pScreen, NULL, SDL_MapRGB (m_pScreen->format, 0, 0, 0)); //RGB-Farbe - (0,0,0) ist schwarz
}

//Flip
//Aufgabe: Surface umschalten (flippen)
void CFramework::Flip()
{
    //Surface umschalten
    SDL_Flip(m_pScreen);
}



Ich bekomme jetzt zwar keine Debugging-Fehler mehr, jedoch die Meldung "Fehler bei Render" (Hab ich selbst eingebaut).
Hat irgendjemand eine Idee was ich falsch gemacht haben könnte, ich bin schon seit 2 Tagen dran und finde einfach keine Lösung!

Architekt

Community-Fossil

Beiträge: 2 481

Wohnort: Hamburg

Beruf: Student

  • Private Nachricht senden

6

27.03.2012, 02:13

Du könntest dir den Fehler ja mal holen, indem du TTF_GetError benutzt.
Zudem fällt mir auf, dass du irgendwie noch nicht den Sinn von Kon- und Destruktoren verstanden hast, diesen Eindruck vermitteln jedenfalls deine Init und Quit Methoden.
Der einfachste Weg eine Kopie zu entfernen ist sie zu löschen.
- Stephan Schmidt -

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

7

27.03.2012, 07:52

Jo, dein Programm ruft mehrfach SDL_Init und SDL_Quit auf.

Werbeanzeige