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

Snowy

Frischling

  • »Snowy« ist der Autor dieses Themas

Beiträge: 54

Wohnort: Stuttgart

  • Private Nachricht senden

1

22.08.2014, 19:16

[C++] Frage: Wie weit verschachteln? Weitere Möglichkeiten?

Hallo liebe Community,

heute bräuchte ich mal einen kleinen bzw. großen Rat von Euch. Ich bin an einem Punkt angelangt, an dem ich mich Frage, ob ich einen richtigen Weg folge oder nicht. Ob es ein schlechter Stil ist oder ob es für mein Vorhaben eine Möglichkeit gibt, den schlechten Stil zum umgehen, welche ich nur noch nicht kenne.

Bei meiner Frage geht es um folgendes: Wie weit sollte man verschachteln?

Ich habe ein Hauptmenü gebastelt, dass in etwa so aussieht:

Neues Spiel
Laden
Optionen
Credits
Beenden

Das ganze natürlich im Switch - Case Verfahren. Bei den unteren vier Punkten ist das kein Problem, da irgendwann bzw. in "absehbarer Zeit" mit dem Verschachteln Ende ist. Bei neuem Spiel hingegen könnte das ganze eine längere Geschichte geben (je nach Größe des Spieles). Das ganze würde ja dann irgendwann so aussehen:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
cout << " Viel Text " << endl;
cin >> IrgendeineMoeglichkeit;
switch(IrgendeineMoeglichkeit)
{
   case('X'):   
       {     
               cout << " Wieder viel Text " << endl;
              cin >> IrgendeineMoeglichkeit;
              
               switch(IrgendeineMoeglichkeit)
               {
                     case('X'):
                     {
                           usw usw usw
                     }break;
                }
           
    }break;
}


Ich denke anhand des Beispieles ist klar, worauf ich hinaus möchte. Irgendwann komme ich auf den anderen Seite des Bildschirmes an und dann wird das irgendwann ganz schön hässlich. Viele habe ich schon in andere Daten verknüpft und ebenfalls auch mit Klassen, aber ich weis nicht genau wie ich dann den Spielablauf noch geordnet unterbringe.

Daher die Frage: Ist das nur so Möglich bzw. Standard oder gibt es da andere Möglichkeiten, welche ich bisher aber nicht kenne? Falls ja, welche wären das?


Danke im voraus.

Grüßle,

Snowy

EDIT: Ich weis nicht warum mein Code so dermaßen umformatiert wird, eventl. kann das ein mod richten? ?(
return 0;

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »Snowy« (22.08.2014, 21:29)


dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

2

22.08.2014, 19:20

Kennst du dich schon mit Funktionen aus? Wenn nicht wärs nun wohl ein guter Zeitpunkt... ;)

Snowy

Frischling

  • »Snowy« ist der Autor dieses Themas

Beiträge: 54

Wohnort: Stuttgart

  • Private Nachricht senden

3

22.08.2014, 19:26

Hallo dot,

falls du nun meinst:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
cout << " TEXT " << endl;

cin >> Moeglichkeit

switch(Moeglichkeit)
{
     case('X'):
     {
         Objekt.EineFunktion();

     }break;
}


C-/C++-Quelltext

1
2
3
4
5
6
// Andere CPP Datei

void CClass::EineFunktion()
{
         //Weiteres Switch-Case Verfahren?
}


Dann ja. Sprich das wird dann von der einen zur nächsten cpp Datei weiter getragen? Ebenfalls wenn Klassen im Spiel sind?


Gruß,

Snowy
return 0;

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

4

22.08.2014, 19:28

Genau, du könntest z.B. einfach für jedes Untermenü eine Funktion machen, die dann das jeweilige Untermenü implementiert...

Snowy

Frischling

  • »Snowy« ist der Autor dieses Themas

Beiträge: 54

Wohnort: Stuttgart

  • Private Nachricht senden

5

22.08.2014, 19:36

Okay, dieser Gedanke kam mir auch schon heute Mittag. Allerdings gab es dann noch einen Knackpunkt dabei, der mir da im Wege stand:

Wenn ich eine Instanz von einer Klasse bilde, z.B. CPlayer Player. Diese beinhaltet die Attribute des Spielers (Leben, Items, etc., ...), habe ich keine Möglichkeit gefunden diese Instanz in der Parameterliste zu übergeben, damit ich in der anderen XYZ.cpp Datei damit arbeiten kann. (benuzte keine globalen Variablen)

Oder habe ich da eine Möglichkeit übersehen bzw. ist mir dessen existens (was durauch sein kann) nicht bewusst?

Danke dir für deine Hilfe.


Gruß
return 0;

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

6

22.08.2014, 19:40

Einfach eine Referenz, also z.B. CPlayer& bzw. const CPlayer&, übergeben. Ein weiteres Stichwort, das für dich nun wohl interessant wird, ist "Forward Declaration"... ;)

Snowy

Frischling

  • »Snowy« ist der Autor dieses Themas

Beiträge: 54

Wohnort: Stuttgart

  • Private Nachricht senden

7

22.08.2014, 21:14

Hallo dot,

mit den Referenzen hatte ich es heute Mittag auch versucht, bin allerdings gescheitert. Lag allerdings an mir, da ich es falsch geschrieben hatte. Durch deinen Post ist mir dieser Fehler klar geworden bzw. aufgefallen. Ebenfalls war das Stichwort des Tages "Forward Declaration" perfekt. Habe es eben ausprobiert und auch getestet. Funktioniert auch 1A.

Nachteil ist, ich muss nun einen Großteil des Codes in meinem derzeitigen Spiel ändern. :S Shit happens...


Ich danke dir für deine Hilfe! :thumbsup:


Für diejenigen, die sich ebenfalls mal diese Frage stellen wie ich, habe ich hier auch noch ein paar Links zu Dot's Stichworten. Damit sollte das ganze dann eigentlich klappen.

Klasse per Referenz an Funktion übergeben:
https://bbs.archlinux.de/viewtopic.php?id=14728

Wann und wie "Forward Declaration" einsetzen:
http://stackoverflow.com/questions/55368…ard-declaration

Wiki Forward Declaration:
http://en.wikipedia.org/wiki/Forward_declaration


Liebe Grüße,


Snowy
return 0;

8

22.08.2014, 21:21

Wenn dein spielablauf durch verschachtelte switch case Geschichten verwirklicht werden soll, ist das keine gute Idee. In Funktionen lagerst du den Code nur aus und wenn ich dich richtig verstehe, wirst du dann die Funktion noch sich selbst aufrufen lassen.

Sinnvoller ist hier imho wohl eine schleife und entsprechende gamestates mithilfe denen du in jedem schleifendurchlauf je nach gamestate eine entsprechende Funktion aufrufst. ;)
EnvisionGame(); EnableGame(); AchieveGame(); - Visionen kann man viele haben. Sie umzusetzen und auf das Ergebnis stolz zu sein ist die eigentliche Kunst.

Snowy

Frischling

  • »Snowy« ist der Autor dieses Themas

Beiträge: 54

Wohnort: Stuttgart

  • Private Nachricht senden

9

22.08.2014, 21:29

Hallo iSmokiieZz,

ja du hast recht, eigentlich lager ich den ganzen Code nur aus. Geplant hatte ich allerdings nicht, dass sich die Funktionen selbst aufrufen.
Könntest du das mit den Gamestates genauer Erläutern, ist mir noch nicht so ganz klar wie du das meinst?


Gruß,

Snowy
return 0;

10

22.08.2014, 21:41

In etwa folgendermaßen. Für größere Projekte mag das eventuell ungünstig sein, aber für den Anfang reicht es allemal:

Hier ein Beispiel für bspw. ein Mensch-Ärger-Dich-Nicht:

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
// Werte, um den aktuellen Spielstatus zu beschreiben
enum EGameState
{
    eGS_MAINMENU, // im hauptmenu (Lobby)
    eGS_FIRST_PLAYER, // Spieler eins ist an der Reihe
    eGS_SECOND_PLAYER, // Spieler 2 ...
    ...
};

// forward declarations, muessen natuerlich noch irgendwo definiert werden
void DoMainMenuStuff(); 
void DoPlayerTurn(const CPlayer& player);

void main()
{
    EGameState state = eGS_MAINMENU;
    CPlayer players[4];


    bool bGameRunning = true; // sobald das spiel beendet werden soll, auf false setzen.

    // main loop
    while (bGameRunning)
    {
        switch (state)
        {
            case eGS_MAINMENU:
            {            
                DoMainMenuStuff(); // sollte vermutlich auch state aendern
                break;
            }
            case eGS_FIRST_PLAYER:
            {            
                DoPlayerTurn(players[0]);
                state = eGS_SECOND_PLAYER; // der naechste in dran.
                break;
            }
            ...
        }               
    }
}

// Wird aufgerufen, wenn ein Spieler an der Reihe ist.
void DoPlayerTurn(const CPlayer& player)
{
    cin >> auswahl;
    switch (auswahl)
    {
        case 'X': // spieler moechte aussetzen...
            break;
        case 'Y': // spieler moechte nicht mehr mitspielen...
            player.KickFromGame();
            break;
        ...
    }
}


Das ist noch lange nicht gut, aber ich habe es zur Einfachkeit einfach mal einfach gehalten ;)
EnvisionGame(); EnableGame(); AchieveGame(); - Visionen kann man viele haben. Sie umzusetzen und auf das Ergebnis stolz zu sein ist die eigentliche Kunst.

Werbeanzeige