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

Din

Frischling

  • »Din« ist der Autor dieses Themas
  • Private Nachricht senden

1

12.12.2016, 08:55

Kapitel 12: CGame mit States?

Hallo Leute,

Angenommen man würde der CGame Klasse folgende States geben: 1)Menu(hier wird das Menü angezeigt) 2) Level(das eigentliche Spiel läuft) 3) Transition(für den Uebergang zwischen den Level) 4) Highscore(hier wird der Highscore angezeigt) 5) End(hier wird die Variable umgestellt die die Schleife des Spiels beendet). Während des Spiels wird dann zwischen diesen States gewechselt um jeweils die richtige Bildschirmausgabe und so zu erreichen. Wäre das ok oder verstösst es gegen die Objektorientierung (da CGame sich um mehrere Sachen (Menü, Level, Highscore etc.) kümmern muss) oder andere Regeln?

Vielen Dank.

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

2

12.12.2016, 09:36

Ehrlich gesagt ist für mich die erste Frage: Was ist bitte CGame und wofür ist das Ding verantwortlich? Der Name allein sagt nämlich überhaupt nichts aus. Erst wenn wir das geklärt haben, können wir darüber reden, was da rein darf und was da nicht rein sollte.
(Ich habe das Buch nicht, daher ist hier etwas Erleuchtung notwendig)
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Din

Frischling

  • »Din« ist der Autor dieses Themas
  • Private Nachricht senden

3

13.12.2016, 08:05

Ehrlich gesagt ist für mich die erste Frage: Was ist bitte CGame und wofür ist das Ding verantwortlich? Der Name allein sagt nämlich überhaupt nichts aus. Erst wenn wir das geklärt haben, können wir darüber reden, was da rein darf und was da nicht rein sollte.
(Ich habe das Buch nicht, daher ist hier etwas Erleuchtung notwendig)


Tut mir leid, mein Fehler, hab nicht daran gedacht (ich dachte das wäre nicht nötig da ich das im Forum für das Buch schreibe).
CGame kümmert sich darum das eigentliche Spiel zum laufen zu bringen (erzeugt und aktualisiert den Spieler und die Asteroiden, überprüft die Kollisionen, bearbeitet die Events, rendert das ganze und enthält die Schleife des Spiels).

Hier sind die Header und cpp Dateien, falls die dir mehr helfen:

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

#include "Player.hpp"
#include "Asteroid.hpp"

class CGame
{
    public:
        CGame ();

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

    private:
        void ProcessEvents   ();
        void SpawnAsteroids  ();
        void RenderAsteroids ();
        void CheckCollisions ();

        CPlayer *m_pPlayer;             // Spieler-Instanz
        CSprite *m_pSpriteBackground;   // Sprite fόr den Hintergrund
        CSprite *m_pSpriteAsteroid;     // Sprite fόr die Asteroiden
        float    m_fAsteroidTimer;      // Zeitgeber fόr nδchsten Asteroiden
        bool     m_bGameRun;            // Lδuft das Spiel noch?
        list<CAsteroid> m_AsteroidList; // Liste der Asteroiden

};

#endif
.

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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
#include "Game.hpp"

// Konstruktor
//
// Aufgabe: Allgemeine Initialisierungen
//
CGame::CGame ()
{
    m_pPlayer = NULL;
    m_pSpriteBackground = NULL;
    m_pSpriteAsteroid = NULL;

} // Konstruktor


// Init
//
// Aufgabe: Spieler, Hintergrund und Asteroid initialisieren
//
void CGame::Init ()
{
    // Neuen Spieler initialisieren
    m_pPlayer = new CPlayer;
    m_pPlayer->Init ();
    m_pPlayer->Reset ();

    // Hintergrundbild (Sprite) laden
    m_pSpriteBackground = new CSprite;
    m_pSpriteBackground->Load ("Data/Background.bmp");

    // Sprite fόr Asteroiden laden
    m_pSpriteAsteroid = new CSprite;
    m_pSpriteAsteroid->Load ("Data/Asteroid.bmp", 20, 64, 64);
    
    // Timer fόr Asteroiden zurόcksetzen
    m_fAsteroidTimer = 0.0f;

    // Spiel lδuft
    m_bGameRun = true;
} // Init


// Quit
//
// Aufgabe: Instanzen freigeben
//
void CGame::Quit ()
{
    // Spieler freigeben
    if (m_pPlayer != NULL)
    {
        m_pPlayer->Quit ();
        delete (m_pPlayer);
        m_pPlayer = NULL ;
    }

    // Hintergrundsprite freigeben
    if (m_pSpriteBackground != NULL)
    {
        delete (m_pSpriteBackground);
        m_pSpriteBackground = NULL;
    }

    // Asteroidensprite freigeben
    if (m_pSpriteAsteroid != NULL)
    {
        delete (m_pSpriteBackground);
        m_pSpriteBackground = NULL;
    }

} // Quit


// Run
//
// Aufgabe: Hauptschleife des Spiels
//
void CGame::Run ()
{
    // Hauptschleife des Spiels durchlaufen
    //
    while (m_bGameRun == true)
    {
        // Events bearbeiten
        ProcessEvents ();

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

        // Hintergrundbild rendern
        m_pSpriteBackground->Render ();

        // Spieler updaten und rendern
        m_pPlayer->Update ();
        m_pPlayer->Render ();

        // Neue Asteroiden hinzufόgen
        SpawnAsteroids ();

        // Kollisionen prόfen
        CheckCollisions ();

        // Asteroiden rendern
        RenderAsteroids ();

        // Spiel darstellen
        g_pFramework->Render ();

    }

} // Run


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

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

            } break;


            // Wurde eine Taste gedrόckt?
            case (SDL_KEYDOWN):
            {
                switch (Event.key.keysym.sym)
                {
                    case (SDLK_ESCAPE):
                    {
                        // Ja, also Spiel beenden
                        m_bGameRun = false;

                    } break;
                        
                    default:
                        break;
                }
            } break;
        }
    }

} // ProcessEvents


// SpawnAsteroids
//
// Aufgabe: Nach Ablauf einer bestimmten Zeit neuen Asteroiden erzeugen
//
void CGame::SpawnAsteroids ()
{
    // Timer fόr nδchsten Asteroiden erhφhen
    m_fAsteroidTimer += g_pTimer->GetElapsed ();

    // Wenn eine halbe Sekunde vergangen ist,
    // einen neuen Asteroiden erzeugen
    if (m_fAsteroidTimer >= 0.5f)
    {
        // Neuer Asteroid
        CAsteroid Asteroid;

        // Zufδllige X-Position
        int XPos = rand()%736;

        // Asteroid initialisieren
        Asteroid.Init (m_pSpriteAsteroid, static_cast<float>(XPos), -60.0f);

        // Asteroid in Liste einfόgen
        m_AsteroidList.push_back (Asteroid);

        // Zeitgeber wieder zurόcksetzen
        m_fAsteroidTimer = 0.0f;

    }

} // SpawnAsteroids


// CheckCollisions
//
// Aufgabe: Kollisionen zwischen Asteroiden und Schόssen prόfen
//
void CGame::CheckCollisions ()
{
    // Schussliste des Spielers holen
    list<CShot> *ShotList = m_pPlayer->GetShotList ();

    // Iteratoren fόr Asteroiden- und Schussliste
    list<CAsteroid>::iterator ItAsteroid = m_AsteroidList.begin ();
    list<CShot>::iterator ItShot;

    // Rects fόr Asteroiden und Schόsse
    SDL_Rect RectAsteroid;
    SDL_Rect RectShot;

    // Alle Asteroiden durchlaufen
    while (ItAsteroid != m_AsteroidList.end () )
    {
        // Rect des Asteroiden holen
        RectAsteroid = ItAsteroid->GetRect ();

        // Alle Schόsse durchlaufen
        for (ItShot = ShotList->begin ();
            ItShot != ShotList->end ();
            ++ItShot)
        {
            // Rect des Schusses holen
            RectShot = ItShot->GetRect ();

            // άberschneiden sich die Rects?
            if (RectShot.y < RectAsteroid.y + RectAsteroid.h &&
                RectShot.y + RectShot.h > RectAsteroid.y &&
                RectShot.x < RectAsteroid.x + RectAsteroid.w &&
                RectShot.x + RectShot.w > RectAsteroid.x)
            {
                // Ja, also gab es eine Kollision. Somit Schuss und
                // Asteroid deaktivieren
                ItAsteroid->SetAlive (false);
                ItShot->SetAlive (false);
            }
        }

        // Asteroid lφschen, falls deaktiviert
        if (ItAsteroid->IsAlive () )
            ItAsteroid++;
        else
            ItAsteroid = m_AsteroidList.erase (ItAsteroid);

    }

} // CheckCollision


// RenderAsteroids
//
// Aufgabe: Alle Asteroiden rendern und updaten
//
void CGame::RenderAsteroids ()
{
    // Iterator fόr die Asteroiden-Liste
    list<CAsteroid>::iterator It;

    // Asteroiden-Liste durchlaufen
    for (It = m_AsteroidList.begin (); It != m_AsteroidList.end (); ++It)
    {
        // Asteroid rendern
        It->Render ();

        // Asteroid updaten
        It->Update ();

    }

} // RenderAsteroids

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

4

13.12.2016, 17:33

Tut mir leid, mein Fehler, hab nicht daran gedacht (ich dachte das wäre nicht nötig da ich das im Forum für das Buch schreibe).
Das stimmt zwar, aber die Alternative ist wohl, dass du dann gar keine Antwort bekommst oder erst eine ganze Weile hin.

Hier sind die Header und cpp Dateien, falls die dir mehr helfen:
OK, also CGame kümmert sich offenbar um das Spielgeschehen, die Regeln und Aktionen. Dazu passen jetzt Menüs irgendwie so gar nicht. Du hast es also schon richtig vermutet, dort solltest du deine Menüs nicht rein quetschen.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

ByteJunkie

Alter Hase

Beiträge: 891

Wohnort: Deutschland

Beruf: Softwareentwickler

  • Private Nachricht senden

5

13.12.2016, 17:59

Er will doch verschiedene Stati in CGame unterbringen. Aus meiner Sicht wäre das ok.
Für das Menü sollte allerdings eine eigene Klasse erstellt werden. ;)

Ergänzung: Obwohl, wenn ich recht überlege sollten die States eine Ebene höher untergebracht werden.
Mach was Du nicht lassen kannst und lass was Du nicht machen kannst. ;)

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »ByteJunkie« (13.12.2016, 18:06)


BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

6

13.12.2016, 19:03

wenn ich recht überlege sollten die States eine Ebene höher untergebracht werden.
Mindestens eine ;)
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Din

Frischling

  • »Din« ist der Autor dieses Themas
  • Private Nachricht senden

7

14.12.2016, 08:57

Ergänzung: Obwohl, wenn ich recht überlege sollten die States eine Ebene höher untergebracht werden.


Mindestens eine

Danke erstmal fuer die Antworten. Allerdings, glaube ich nicht dass ich das oben zitierte verstanden habe. Was ist mit "Ebene" gemeint und wie koennte man "eine Ebene hoeher" umsetzen? Ob das vielleicht etwas erklaert werden koennte? Danke sehr.

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

8

14.12.2016, 09:42

Nun, irgendeine Klasse oder Funktion wird ja die Instanz von CGame besitzen. Das ist die Ebene "höher". Es geht hier also um Besitz-Hierarchien.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Colin117

Frischling

Beiträge: 16

Beruf: Azubi Fachinformatiker - Anwendungsentwickler

  • Private Nachricht senden

9

15.12.2016, 15:16

Da die "Hauptschleife" allerdings in CGame ist, würde ich sagen du lagerst die Spieldaten, also CPlayer, CSprite, usw in eine andere Klasse. Dann kannst du vielleicht in CGame nur die Klasse updaten/zeichnen, die aktiv ist.

z.B.

CGame
->Intro
->Menu
->Ingame

Hier würde ich die oben besagten Daten zur Ingame Klasse hinzufügen. Dort kannst du dann den Spieler zeichnen usw, du musst halt in CGame wissen welcher "State" aktiv ist.

Din

Frischling

  • »Din« ist der Autor dieses Themas
  • Private Nachricht senden

10

15.12.2016, 15:32


Da die "Hauptschleife" allerdings in CGame ist, würde ich sagen du lagerst die Spieldaten, also CPlayer, CSprite, usw in eine andere Klasse. Dann kannst du vielleicht in CGame nur die Klasse updaten/zeichnen, die aktiv ist.

z.B.

CGame
->Intro
->Menu
->Ingame

Hier würde ich die oben besagten Daten zur Ingame Klasse hinzufügen. Dort kannst du dann den Spieler zeichnen usw, du musst halt in CGame wissen welcher "State" aktiv ist.

Danke fuer die Antwort.
War gerade dabei allgemein nachzufragen ob folgender Code ok waere, als ich beim schreiben deine Antwort gelesen habe (hab mir sowas schon gedacht, anhand der anderen Antworten).

Wäre es ok wenn man eine CMenu, CHighscore und CLevel Klasse(wie schon vorgeschlagen) schreiben wuerde und CGame so umschreiben würde, dass sie sich um die States kuemmert?
Dann wuerde CGame so aussehen:

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
CGame::Run ()
{
    while (m_bRun)
    {
        Update ();
        Render ();
    }
}

CGame::Update ()
{
    PumpEvents ();

    int Result = 0; // Temporaere Variable um die State zu kontrollieren
            

    switch (state)
    {
        case (Menu):
        {
            Result = m_pMenu->Update ();

            if (Result == 1) state = Level;
            if (Result == 2) state = Highscore;
            if (Result == -1) state = End;
        } break;

        case (Level):
        {
            Result = m_pLevel->Update ();

            if (Result == 1) state = Highscore;
            if (Result == -1) state = End;
        } break;

        case (Highscore):
        {
            Result = m_pHighscore->Update ();

            if (Result == -1) state = End;
        } break;

        case (End)
        {
            m_bRun = false;
        } break;

        case (default):
        {
            cout << "Fehler bei States" << endl;
        }
    }
}

CGame::Render ()
{
    g_pFramework->Clear ();
    g_pFramework->Update ();

    switch (State)
    {
        case (Menu):
        {
            m_pMenu->Render ();
        } break;

        case (Level)
        {
            m_pLevel->Render ();
        } break;

        case (Highscore):
        {
            m_pHighscore->Render ();
        } break;

        case (default):
        {
            cout << "Fehler bei States" << endl;
        }
    }

    g_pFramework->Render ();

}


Das andere Zeug aus CGame kommt in CLevel. CGame besitzt jeweils eine Instanz von CMenu, CLevel und CHighscore und ruft durch ein Switch-Konstrukt die Funktion der benoetigten Instanz auf. Ueber den Rueckgabewert der Update()-Funktionen wird dann die aktuelle State gesteuert. Dann braeuchte man auch nicht von jeder Instanz g_pFramework->Clear(), Update() und Render() und PumpEvents()(wobei jede Klasse diese Funktion haben muesste) aufzurufen (allerdings braeuchte man dann Funktionen um Menu, Level und zurueckzusetzen, oder?).

Werbeanzeige