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

10.07.2012, 18:32

sinnvolle Lösung für Menüerweiterung?

Hallo zusammen,

ich habe eine Menüerweiterung für das SDL-Game geschrieben, aber bei der Funktion zum Beenden des Spiels vom Menu aus
meine ich etwas rabiaten Code geschrieben zu haben:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void CMenu::ProcessEvents ()
{
    SDL_Event Event;
    
    // Gab es ein Event?
    if (SDL_PollEvent (&Event))
    {
        // Ja, also schauen welches
        switch (Event.type)
        {
            // Beenden?
        case (SDL_QUIT):
            {       
                // Framework herunterfahren
                g_pFramework->Quit ();

                // Gesamtes Spiel beenden
                exit (1);

            } break;


Ich bin noch nicht so erfahren und habe deshalb auf die Methode zurückgegriffen, welche schon in der Load-Funktion
im Buch genutzt wurde:

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
void CSprite::Load (const string sFilename)
{
    // Bitmap laden
    m_pImage = SDL_LoadBMP (sFilename.c_str ());

    // Prüfen, ob alles glatt ging
    if (m_pImage == NULL)
    {
        cout << "Fehler beim Laden von: " << sFilename.c_str ();
        cout << endl;
        cout << "Fehlermeldung: " << SDL_GetError () << endl;

        // Framework herunterfahren
        g_pFramework->Quit ();

        // Gesamtes Spiel beenden
        exit (1);
    }

    // Rect initialisieren
    m_Rect.x = 0;
    m_Rect.y = 0;
    m_Rect.w = m_pImage->w;
    m_Rect.h = m_pImage->h;

} // Load



Vielen Dank im Voraus für Eure Hilfe!

2

10.07.2012, 18:38

Wärst du so nett, deine Menüklasse und alles was dazu gehört mal zu posten? Bin selber gerade dabei ein Menü einzubauen. Bei mir sieht es derzeit so aus:
main.ccp erweitert:

C-/C++-Quelltext

1
2
3
4
5
6
...
    // Spielmenü anzeigen
    Game.ShowMenu ();
...

}


Game.ccp erweitert:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
// CGame::ShowMenu
//
// Aufgabe: Spielmenü anzeigen
//
void CGame::ShowMenu ()
{
    m_pMenu = new CMenu();
    m_pMenu->Show();
}


Menu.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
#ifndef MENU_HPP
#define MENU_HPP

#include "Sprite.hpp"


class CMenu
{
    public:
        CMenu ();
        void Quit ();
        void Show ();
        void ProcessEvents();

    private:
        SDL_Surface *m_pScreen;     // Zeiger auf den Screen des Frameworks
        CSprite *m_pImage;          // Hintergrundbild-Menü
        bool m_bMenuRun;            // Läuft das Menu noch?
};

#endif


Menu.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
92
93
94
95
#include "Menu.hpp"

// Konstruktor
//
// Aufgabe: Zeiger auf Screen holen
//
CMenu::CMenu ()
{
    // Zeiger auf Screen holen
    m_pScreen = g_pFramework->GetScreen ();
    m_bMenuRun = true;

} // Konstruktor


// CMenu::Quit
//
// Aufgabe: Surface des Hintergrundbildes freigeben
//
void CMenu::Quit ()
{
    if ( m_pImage != NULL)
    {
           delete ( m_pImage);
           m_pImage = NULL;
    }

} // Destruktor


// CMenu:Show
//
// Aufgabe: Menü laden
//
void CMenu::Show ()
{
        m_pImage = new CSprite;
        m_pImage->Load ("Data/level4.jpg");

    while (m_bMenuRun == true) {
        // User-Interaktion überprüfen
        ProcessEvents ();

        // Framework updaten und Buffer löschen
        g_pFramework->Update ();
        g_pFramework->Clear ();

        // Hintergrundbild rendern
        m_pImage->Render();

        // Buffer flippen
        g_pFramework->Flip ();
    }

    cout << "Spiel aus dem Menü raus beendet.";
    Quit ();
    // Framework beenden
    g_pFramework->Quit ();
    g_pFramework->Del ();
        
} // Destruktor

// ProcessEvents
//
// Aufgabe: Events bearbeiten
//
void CMenu::ProcessEvents ()
{
    SDL_Event Event;

    // Gab es ein Event?
    if (SDL_PollEvent (&Event))
    {
        // Ja, also schauen welches
        switch (Event.type)
        {
            // Beenden?
        case (SDL_QUIT):
            {
                m_bMenuRun = false;
            } break;


            // Wurde eine Taste gedrückt?
        case (SDL_KEYDOWN):
            {
                switch (Event.key.keysym.sym)
                {
                    // TO-DO: Add Menu
                }
            } break;
        }
    }

} // ProcessEvents


Das Bild wird soweit geladen, jedoch gibt es noch einen Fehler beim Beenden des Spiels (Unbehandelte Ausnahme bei 0x776f15de in SDL_Game.exe: 0xC0000005: Zugriffsverletzung beim Lesen an Position 0xcdcdcdd1.).

Gruß

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

3

10.07.2012, 18:39

Vermutlich wären Exceptions hier eine Lösung.

4

10.07.2012, 18:55

Hier mein CMenu:

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

#include "Game.hpp"

class CMenu
{
    public:
        CMenu ();

        void Init   ();
        void Run    ();
        void Quit   ();

    private:
        void ProcessEvents ();

        CSprite     *m_pSpriteMenuScreen;       // Menübildschirm
        Mix_Music   *m_pMenuMusic;              // Menümusik
        bool         m_bMenuRun;                // Läuft das Menü noch?

};

#endif


Hier der Rest:

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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include "Menu.hpp"

// Konstruktor
//
// Aufgabe: Allgemeine Initialisierung
//
CMenu::CMenu ()
{
    m_pSpriteMenuScreen = NULL;
    m_pMenuMusic        = NULL;
} // Konstruktor

// Init
//
// Aufgabe: Bild und Musik initialisieren
//
void CMenu::Init ()
{
    // Menübild (Sprite) laden
    m_pSpriteMenuScreen = new CSprite;
    m_pSpriteMenuScreen->Load ("Data/MenuScreen.bmp");

    // Menümusikladen
    m_pMenuMusic = Mix_LoadMUS("Data/MenuMusic.wav");
}

// Run
//
// Aufgabe: Hauptschleife des Menüs
void CMenu::Run ()
{
    // Hauptschleife des Menüs
    //
    while (m_bMenuRun == true)
    {

    }
}

// Quit
//
// Aufgabe: Instanzen freigeben
//
void CMenu::Quit ()
{
    // Menusprite freigeben
    if (m_pSpriteMenuScreen != NULL)
    {
        delete (m_pSpriteMenuScreen);
        m_pSpriteMenuScreen = NULL;
    }

    // Menumusik freigeben
    if (m_pMenuMusic != NULL)
    {
        Mix_FreeMusic (m_pMenuMusic);
        m_pMenuMusic = NULL;
    }

}

// ProcessEvents
//
// Aufgabe: Events bearbeiten
//
void CMenu::ProcessEvents ()
{
    SDL_Event Event;
    
    // Gab es ein Event?
    if (SDL_PollEvent (&Event))
    {
        // Ja, also schauen welches
        switch (Event.type)
        {
            // Beenden?
        case (SDL_QUIT):
            {       
                // Framework herunterfahren
                g_pFramework->Quit ();

                // Gesamtes Spiel beenden
                exit (1);

            } break;


            // Wurde eine Taste gedrückt?
        case (SDL_KEYDOWN):
            {
                switch (Event.key.keysym.sym)
                {
                case (SDLK_ESCAPE):
                    {
                        // Framework herunterfahren
                        g_pFramework->Quit ();

                        // Gesamtes Spiel beenden
                        exit (1);

                    } break;
                }
            } break;
        }
    }
}


Ist noch nicht komplett, wie man an CMenu::Run () und ProcessEvents () sieht. Beim Aufbau habe ich mich an CGame
orientiert. Falls jemand eine bessere Idee hat soll er sich bitte melden ;) Ich bin noch relativ unsicher wie ich den Code
am besten gestalten sollte.

Was genau ist denn mit Exceptions gemeint?

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Beorn« (10.07.2012, 19:31)


5

10.07.2012, 19:44

Ein try-catch Block, siehe Seite 261.

Gruß

6

10.07.2012, 19:59

Das verwirrt mich jetzt ich dachte try und catch wären zum Abfangen von Fehlern gedacht? Ich hatte eigentlich
an eine bool Variable gedacht, ungefähr so:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int main()
{
   // Menuablauf, je nach dem wie ich das regele hier (vorheriger Post)


   // hier die Abfrage der Variable aus Menu::ProcessEvents () (auch vorheriger Post)
   if (Variable == true)
   {
    
    Game.Init ();
    Game.Run ();
    Game.Quit ();
    }

    // Framework beenden
    g_pFramework->Quit ();
    g_pFramework->Del ();

    return (0);

}

7

10.07.2012, 20:08

Ja, und im try-Teil werden die Exceptions geworfen, deswegen gehört das schon zusammen ;)
Nur was genau dot nun meint, weiß ich auch nicht.

Gruß

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

8

10.07.2012, 20:26

Naja, wenn z.B. in CSprite::Load() (das wohl eigentlich ein Konstruktor sein sollte und keine Methode) was schiefläuft, dann wirf eine Exception und bau dir in deine main() eine allgemeine Ausnahmebehandlung, die das Programm entsprechend beendet:

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
// Sprite.cpp

#include <stdexcept>

Sprite::Sprite(const char* filename)
{
  if (was schiefgegangen)
    throw std::runtime_error("unable to load image");
}


// main.cpp

#include <stdexcept>
#include <iostream>

int main()
{
  try
  {
    Sprite dein_sprite("bla.png");

    // ...

  }
  catch (const std::exception& e)
  {
    std::cout << "error :" << e.what() << std::endl;
    return -1;
  }
  return 0;
}


Was das Beenden übers Menü angeht, verpass CMenu:: ProcessEvents() einfach einen Rückgabewert, der false oder -1 oder sonstwas wird, wenn das Programm beendet werden soll.


Btw: Du solltest dir solche Methoden wie Init() oder Load() unbedingt abgewöhnen; genau für sowas gibt es Konstruktoren. Und diese Namenskonvention, allen Klassen ein C voranzustellen, würd ich auch ablegen. Aber gut, das ist zumindest Geschmackssache...

Dieser Beitrag wurde bereits 7 mal editiert, zuletzt von »dot« (10.07.2012, 20:40)


NachoMan

Community-Fossil

Beiträge: 3 885

Wohnort: Berlin

Beruf: (Nachhilfe)Lehrer (Mathematik, C++, Java, C#)

  • Private Nachricht senden

9

10.07.2012, 20:35

Diese Methode:

C-/C++-Quelltext

1
2
3
4
5
void CGame::ShowMenu ()
{
    m_pMenu = new CMenu();
    m_pMenu->Show();
}

riecht schwer nach einem Memoryleak.

Tut euch bitte den Gefallen und versucht nicht das Spiel weiter zu entwickeln. In dem Spiel von Heiko gibt es viel, was ihr nur nach dem Durcharbeiten des Buchs noch nicht wirklich verstehen könnt. Bzw. gibt es einige Dinge, auf die ihr erstmal selbst kommen müsst. Ausserdem hat er einen ziemlich schlechten Stil.

Als erstes solltet ihr euch entscheiden, ob ihr bei C++ bleibt oder lieber zu einer einfacheren Sprache wie C# wechseln wollt. Wollt ihr bei C++ bleiben könnt ihr euch ein Handbuch wie "The C++ Programminglanguage" oder "Der C++ Programmierer" bestellen und durcharbeiten. Solltet ihr wechseln, dann wäre natürlich ein solches Handbuch zu C# angebracht.

Und schreibt bitte erst noch ein paar kleine Konsolenprogramme und fangt dann selbst von null an ein 2d Spiel zu entwickeln(dafür würde ich auch die SFML an Stelle der SDL empfehlen, weil sie euch etwas mehr Arbeit abnimmt). Fremden Code weiter zu entwickeln ist besonders für Anfänger wesentlich schwieriger als eigenen Code zu schreiben.
"Der erste Trunk aus dem Becher der Erkenntnis macht einem zum Atheist, doch auf dem Grund des Bechers wartet Gott." - Werner Heisenberg
Biete Privatunterricht in Berlin und Online.
Kommt jemand mit Nach oMan?

10

10.07.2012, 20:39

Ok Vielen Dank schonmal soweit werde mal versuchen Eure Tipps umzusetzen :thumbsup:

Werbeanzeige