Looking for Peer Reviews on Game Code

Pages: 12
So I'm working on a personal project with the goal of developing a sort of survival simulator. I've been taking the minuscule step of creating its first form as a text game. A big concern for me at the moment though is establishing good programming habits so I can carry them on in the rest of the project and throughout different "reincarnations" of the game. So far with my current game I've added early versions of some of the main interfaces, but I'd like some reviews from some experienced programmers before I continue under my current methods.

To help give an idea of my situation, My background in coding consists of merely an introductory class I took in high school. I still have a lot to learn (and re-learn), particularly when it comes to good coding habits. I plan to open my project for collaboration so having proper coding that reduces errors and miscommunication is a must for me. More specifically, I've been led to sticking to two major priorities so far:
1) Having clean and efficient code that doesn't bog down the system or make room for bugs
2) Making clear, unambiguous notes in the code that describe what isn't already explicit from the code itself

I'd also prefer to use code that encourages multi-platform support, so things like #include <windows.h> should probably be avoided unless absolutely necessary.

BTW, I did some cursory research and made a decision on what would be the best indent format for my project:
* Indent Style: Allman (mostly because it seems to be the most common, only slightly more than K&D)
* Indent Length: 4 (using spaces to minimize copy-paste formatting issues)

Before I continue I'd like to say that I am grateful for using this website since it has, to me, some of the most understandable free C++ tutorials there is online. It felt like this would be a natural place to post this.

Now on with the code. I omitted some characteristic features of the game without altering the overall structure of the code. It compiles and runs perfectly. A few things I'd like to point out is that so far I managed to learn the habit of excluding using namespace std; and I got rid of all my goto's and replaced them with for(;;) loops, but cin was having an issue so I replaced my std::cin >> input;'s with getline (std::cin, input)'s. I understand that it is known as bad practice to universally declare variables but I could find no better alternative for applying my input variable.

Please provide some feedback on the structure of my code. Should I change the indents? Should I use more functions? Do the notes explain enough? Should I rearrange anything? Are there code alternatives that run faster? Bear in mind that I want this to be as clear and logically-sound as possible. Also, if you're going to recommend a new method, if possible, please provide a fundamental reason why it would be better, e.g.: this article by Timo Geusch (http://www.lonecpluspluscoder.com/2012/09/22/i-dont-want-to-see-another-using-namespace-xxx-in-a-header-file-ever-again/) goes into detail about the problems with global namespaces and provides some alternatives, and there are many who explain the value of structured programming over using gotos and its notorious risk of creating spaghetti code.

I'm currently coding using Codelite on Ubuntu 16.04. I plan on ordering Windows 10 soon. I have the code posted below.
Last edited on
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
#include <cstdlib>
#include <iostream>
#include <string>

/*
Output Format Notes:
* There is a manually-added word-wrap that follows an output limit of 64 characters per line
* spaces are added after every line in case copy-paste formatting ignores line breaks
* line breaks are added before every output that immediately follows an input EXCEPT input error messages
* Line breaks are added before calling main or actionPrompt functions
*/

std::string input;

//Functions List
void ingame();
  void statusUpdate();
  void actionPrompt();
    void gameMenu();

//Note: "enter 1" is placeholder prompt until new code is found for recognizing spacebar input
void cont1()
{
    std::cout << "Enter 1 to continue: ";
    for(;;)
    {
        getline (std::cin, input);
        if (input == "1")
            return;
        else
        {
            std::cout << "\"" << input << "\" is not a valid input. Please enter 1 to continue: "; continue;
        }
    }
}

//Start Menu
int main()
{
    std::cout << "Welcome to [game title] [pre-release 1] \n";
    std::cout << "1) New Game \n";
    std::cout << "2) Launch Settings \n";
    std::cout << "0) Quit \n";
    std::cout << "Enter a number: ";
    for(;;)
    {
        getline (std::cin, input);
        if (input == "1")
            ingame();
        else if (input == "2")
        {
            std::cout << "\n";
            std::cout << "Launch settings are currently in development. \n";
            std::cout << "You will be returned to the start menu. \n";
            cont1();
            std::cout << "\n";
            main();
        }
        else if (input == "0")
            exit(0);
        else
        {
            std::cout << "\"" << input << "\" is not a valid input. Please enter either 1, 2 or 0: "; continue;
        }
    }
}

//In-Game
void ingame()
{
    std::cout << "\n";
    std::cout << "[insert intro here] \n";
    std::cout << "\n";
    cont1();
    statusUpdate();
}

    //In-Game >> Status Update
    void statusUpdate()
    {
        std::cout << "\n";
        std::cout << "You feel normal \n"; //health conditions list will later be displayed here
        std::cout << "The current time is 00:00 \n"; //time will later be displayed here
        std::cout << "You are wielding: nothing \n"; //equipped item will later be displayed here
        std::cout << "\n";
        actionPrompt();
    }

    //In-Game >> Action Prompt
    void actionPrompt()
    {
        std::cout << "Enter a command: "; getline (std::cin, input);
        if (input == "help" || input == "?")
        {
            std::cout << "\n";
            std::cout << "Command List: \n";
            std::cout << "\"help\"/\"?\" - Displays a list of commands \n";
            std::cout << "\"menu\"/\"gm\" - Opens the game menu \n";
            std::cout << "\n";
            actionPrompt();
        }
        else if (input == "menu" || input == "gm")
            gameMenu();

        //Alternative Inputs
        else if (input == "map")
        {
            std::cout << "\n";
            std::cout << "You don't have a map. \n";
            std::cout << "\n";
            actionPrompt();
        }
        else if (input == "rest" || input == "sleep")
        {
            std::cout << "\n";
            std::cout << "You can't rest here. \n";
            std::cout << "\n";
            actionPrompt();
        }

        else
        {
            std::cout << "\"" << input << "\" is not a valid input. You may enter \"help\" for a list of commands. \n";
            actionPrompt();
        }
        /*
        std::cout << "\n";
        std::cout << "The rest of the game is currently in development. \n";
        std::cout << "You will be returned to the start menu. \n";
        cont1();
        std::cout << "\n";
        main();
        */
    }

        //In-Game >> Action Prompt >> Game Menu
        void gameMenu()
        {
            std::cout << "\n";
            std::cout << "Game Menu: \n";
            std::cout << "1) Return to Game \n";
            std::cout << "2) In-Game Settings \n";
            std::cout << "0) Quit to Start Menu \n";
            std::cout << "Enter a number: ";
            for(;;)
            {
                getline (std::cin, input);
                if (input == "1")
                    statusUpdate();
                else if (input == "2")
                {
                    std::cout << "\n";
                    std::cout << "Sorry, the in-game settings are still in development. \n";
                    gameMenu();
                }
                else if (input == "0")
                {
                    std::cout << "\n";
                    std::cout << "Are you sure you want to end the current game and quit to the \n";
                    std::cout << "start menu? All progress will be lost. \n";
                    std::cout << "Enter q to quit or c to cancel back to the game menu: ";
                    for (;;)
                    {
                        getline (std::cin, input);
                        if (input == "q")
                        {
                            std::cout << "\n";
                            main();
                        }
                        else if (input == "c")
                            gameMenu();
                        else
                        {
                            std::cout << "\"" << input << "\" is not a valid input. Please enter either q to quit to the \n";
                            std::cout << "start menu or c to cancel back to the game menu: "; continue;
                        }
                    }
                }
                else
                {
                    std::cout << "\"" << input << "\" is not a valid input. Please enter either 1, 2 or 0: "; continue;
                }
            }
        }
Should I change the indents?

The biggest issue I see with the indents is that you're not being consistent. Here is your code reformatted.

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
#include <cstdlib> 
#include <iostream>
#include <string>

/*
Output Format Notes:
* There is a manually-added word-wrap that follows an output limit of 64 characters per line
* spaces are added after every line in case copy-paste formatting ignores line breaks
* line breaks are added before every output that immediately follows an input EXCEPT input error messages
* Line breaks are added before calling main or actionPrompt functions
*/

std::string input;

//Functions List
void ingame();
void statusUpdate();
void actionPrompt();
void gameMenu();

//Note: "enter 1" is placeholder prompt until new code is found for recognizing spacebar input
void cont1()
{
    std::cout << "Enter 1 to continue: ";
    for(;;)  // A do/while() loop would probably be a better option here.
    {
        getline(std::cin, input);
        if(input == "1")
            return;
        else
        {
            std::cout << "\"" << input << "\" is not a valid input. Please enter 1 to continue: "; continue;
        }
    }
}

//Start Menu
int main()
{
    std::cout << "Welcome to [game title] [pre-release 1] \n";
    std::cout << "1) New Game \n";
    std::cout << "2) Launch Settings \n";
    std::cout << "0) Quit \n";
    std::cout << "Enter a number: ";
    for(;;)
    {
        getline(std::cin, input);
        if(input == "1")
            ingame();
        else if(input == "2")
        {
            std::cout << "\n";
            std::cout << "Launch settings are currently in development. \n";
            std::cout << "You will be returned to the start menu. \n";
            cont1();
            std::cout << "\n";
            main();   // This is not allowed in a C++ program
        }
        else if(input == "0")
            exit(0);
        else
        {
            std::cout << "\"" << input << "\" is not a valid input. Please enter either 1, 2 or 0: "; continue;
        }
    }
}

//In-Game
void ingame()
{
    std::cout << "\n";
    std::cout << "[insert intro here] \n";
    std::cout << "\n";
    cont1();
    statusUpdate();
}

//In-Game >> Status Update
void statusUpdate()
{
    std::cout << "\n";
    std::cout << "You feel normal \n"; //health conditions list will later be displayed here
    std::cout << "The current time is 00:00 \n"; //time will later be displayed here
    std::cout << "You are wielding: nothing \n"; //equipped item will later be displayed here
    std::cout << "\n";
    actionPrompt();
}

//In-Game >> Action Prompt
void actionPrompt()
{
    std::cout << "Enter a command: "; getline(std::cin, input);
    if(input == "help" || input == "?")
    {
        std::cout << "\n";
        std::cout << "Command List: \n";
        std::cout << "\"help\"/\"?\" - Displays a list of commands \n";
        std::cout << "\"menu\"/\"gm\" - Opens the game menu \n";
        std::cout << "\n";
        actionPrompt();   // This is a recursive call and is probably not a good idea, use loops instead.
    }
    else if(input == "menu" || input == "gm")
        gameMenu();

    //Alternative Inputs
    else if(input == "map")
    {
        std::cout << "\n";
        std::cout << "You don't have a map. \n";
        std::cout << "\n";
        actionPrompt();
    }
    else if(input == "rest" || input == "sleep")
    {
        std::cout << "\n";
        std::cout << "You can't rest here. \n";
        std::cout << "\n";
        actionPrompt();
    }

    else
    {
        std::cout << "\"" << input << "\" is not a valid input. You may enter \"help\" for a list of commands. \n";
        actionPrompt();
    }
    /*
    std::cout << "\n";
    std::cout << "The rest of the game is currently in development. \n";
    std::cout << "You will be returned to the start menu. \n";
    cont1();
    std::cout << "\n";
    main();  // Again not allowed in a C++ program.
    */
}

//In-Game >> Action Prompt >> Game Menu
void gameMenu()
{
    std::cout << "\n";
    std::cout << "Game Menu: \n";
    std::cout << "1) Return to Game \n";
    std::cout << "2) In-Game Settings \n";
    std::cout << "0) Quit to Start Menu \n";
    std::cout << "Enter a number: ";
    for(;;)
    {
        getline(std::cin, input);
        if(input == "1")
            statusUpdate();
        else if(input == "2")
        {
            std::cout << "\n";
            std::cout << "Sorry, the in-game settings are still in development. \n";
            gameMenu();
        }
        else if(input == "0")
        {
            std::cout << "\n";
            std::cout << "Are you sure you want to end the current game and quit to the \n";
            std::cout << "start menu? All progress will be lost. \n";
            std::cout << "Enter q to quit or c to cancel back to the game menu: ";
            for(;;)
            {
                getline(std::cin, input);
                if(input == "q")
                {
                    std::cout << "\n";
                    main();   // Not allowed in a C++ program.
                }
                else if(input == "c")
                    gameMenu();  // Another recrusive call, use loops instead.
                else
                {
                    std::cout << "\"" << input << "\" is not a valid input. Please enter either q to quit to the \n";
                    std::cout << "start menu or c to cancel back to the game menu: "; continue;
                }
            }
        }
        else
        {
            std::cout << "\"" << input << "\" is not a valid input. Please enter either 1, 2 or 0: "; continue;
        }
    }
}


Next you are calling main() in several places, this is incorrect. The function main() is special and should never be called by another function including main(). Learn to use other looping structures like the while() loop, the do{}while() loop and the for(;;) loop instead.

Also in several places you are calling functions recursively instead of using the above loops. While recursive functions have there uses the use should probably be kept to a minimum.

Next avoid exit() in C++ programs. This C function doesn't understand C++ classes and can lead to data corruption.

Speaking of C++ classes you really should start thinking about using classes to encapsulate information in your game.

Also you should learn to use the different extraction operators so that you can use the many different types of variables.

Lastly, for now anyway, you should strive to have your functions do as little as possible. And you should start getting used to passing values into functions using the different passing mechanisms when required (pass by value, pass by reference, pass by pointer reference) and learning to return values with the return statement.


Thank you for your response, jlb.

avoid exit() in C++ programs.

Oh yeah, I forgot to mention that return 0; wasn't working for me. It compiled fine, but for some reason, whenever I exited the first for(;;) loop called another function and returned to main(), return 0 wouldn't execute. Oddly enough, cin would accept every input except for the one in the if statement that led to return 0. The only solution I could find was by using exit(0). It sounds like I should find another alternative though.

Next you are calling main() in several places, this is incorrect. The function main() is special and should never be called by another function including main().

Like I said, if possible, please provide a fundamental reason why this should be changed. I can look into it though.

Also, I'm still learning about classes. It sounds like it would be pretty useful in the overall structure of my program. Along with that I'll start looking into extraction operators and how I can use function parameter passing in my program. Again, thank you.
Last edited on
Like I said, if possible, please provide a fundamental reason why this should be changed. I can look into it though.

It should be changed because it is explicitly forbidden. In particular, some implementations may modify the main function to perform initialization of objects with static storage duration, and the linkage of ::main() is implementation-defined.

§6.8.3.1, paragraph 3 [basic.start.main]:
The function main shall not be used within a program. [...]
http://eel.is/c++draft/basic.start.main#3
Last edited on
Oh yeah, I forgot to mention that return 0; wasn't working for me. It compiled fine, but for some reason, whenever I exited the first for(;;) loop, return 0 wouldn't execute.

The return is working, it's just not doing what you expect. The problem is because your broken compiler is allowing you to recursively call main(). Remember that return returns to the calling function and in this case it means that it is returning to the previous main(), not the operating system as you expect.

This is one of the reasons I suggested you stop all the recursive calls and use proper loops, you don't seem to understand what is actually happening when you call a function recursively.



Also, if you're going to recommend a new method, if possible, please provide a fundamental reason why it would be better


You've already stated the principle reason for all of my suggestions in this part of your question:

Bear in mind that I want this to be as clear and logically-sound as possible.


Recursively calling functions tends to obscure your logic. Stick with iteration (loops) until you actually study recursion. IMO, unnecessary recursion is as bad or possibly even worse than using goto statements.

Like I said, if possible, please provide a fundamental reason why this should be changed. I can look into it though.

I suggest you start looking into the suggestions I suggested. One of the biggest lessons you need to learn to become a decent programmer is how to research your problems and how to find and understand the documentation for the language elements you desire to use.


Last edited on
To give a status update, I managed to find out many new things and make changes to my code, but lately I've hit some road-blocks of sorts with my research so I've decided to share my problems here and wait for some answers while I continue my research.

So I learned about the problems with calling main(), or any function recursively for that matter. I found multiple sources basically claiming that improper function recursion will keep adding to the call stack, risking a stack overflow. I assume this is what jlb meant by stating that I didn't seem to understand what was actually happening when I call functions recursively and that it is possibly even worse than using goto statements. I've also just about learned how to use classes, but haven't found a useful way to apply them to my code yet.

I made numerous changes my code. I think I'll wait on posting it until I learn how to make use of function parameter passing, how to use different extraction methods, and/or fix the rest of the problems, but here is a quick list of changes I made:
* Reorganized my functions
* Moved the start menu's contents from main() to a new function, startMenu()
* Removed the gameMenu() function and nested its contents inside its corresponding if statement in actionPrompt()

I had to resort to using one goto statement though after relocating the contents of the game menu since I created a nested loop after replacing a function recursion. Speaking of recursion, I managed to remove most of my recursive function calling. The main ones left though are the ones in actionPrompt(), which leads me to my current problems.

At the moment, I can't figure out how to replace some of the actionPrompt() function recursions except with long-winded while (input != ... || input != ...) loops, which would be a pain because the action prompt is going to have conditional responses to at least dozens of different inputs. Another big issue is that I've been trying to use return 0; instead of exit(0);, but I can't figure out how to return to main without calling it. My only guess is that both of these problems can be fixed with something along the lines of some well-applied passing mechanisms but I haven't found a short and elegant way to apply that sort of thing yet. And lastly, as far as I can tell, there is only one type of extraction operator, ">>", but I'll still be looking into how to use different kinds of variables, which I presume jlb might've suggested it primarily for applying passing mechanisms.

My project is demanding a lot of time and effort so any expert advice would be greatly appreciated. However, I strongly request that when presenting new rules or ideas to apply my code, please cite your source(s) or at least give a brief explanation on the nature/extent of the rule/idea.
Last edited on
OK, so after finally getting some time to work on this, I made a couple of significant changes to the code.

Foremost, I learned how to use classes and structures which enabled me to organize my interface menus and also remove the global variables and put them inside the class, which is a proud accomplishment for me. Aside from that, I will mention the other changes. I'll exclude the changes already mentioned in my previous post. It's been a long time since I've thoroughly reviewed my code so I might've overlooked a few things, but here is my list of major changes:
* Removed all function recursion
* Added skip intros" feature in launch settings, with new bool and string
* Added "travel" command feature, with new system called "zones", applied with new string
* Added "status update" command feature in action prompt
* Removed "cont1" function, since it is no longer planned on being used

The removal of function recursion has led me to using nested for loops, which the only way I've learned how to exit them is by using goto's, perhaps its only acceptable use. Still though, I worry that there is still a potential risk for "spaghetti code" and perhaps there is a more compact and elegant way of applying those loops.

The way things are going, I've only planned to learn new C++ concepts as they are needed for a specific use in the game, like learning vectors for when I need to create an inventory system. A difficult part for me though is being able to recognize the more abstract needs such as organizing code to allow more complex mechanics, minimizing CPU usage, and properly handling the hidden "moving parts" of the software, which are huge priorities for me.

One big potential insight I'd hope to find but failed to find online is to see some source code of a well-designed text-based game so I can better understand how to properly build interface loops and such.

Lastly, provided that I've been asking for help for free on here, I figured I can at least find a way to work in the contributors' names in the credits section of the project. Due to character limit, my new code will be in the next post.
Last edited on
EDIT: Even the code itself exceeded the max char limit so instead I'll post the actionPrompt() function separately from everything else. So first is everything else:

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
#include <cstdlib>
#include <iostream>
#include <string>

//CRITICAL DEBUG REQUEST: replace "exit(0)" with safer code

/*
Output Format Notes:
* There is a manually-added word-wrap that follows an output limit of 64 characters per line
* Spaces are added after every line in case copy-paste formatting ignores line breaks
* Line breaks are added before every output that immediately follows an input EXCEPT input error messages
* Line breaks are added before calling startMenu and actionPrompt functions
*/

class interface
{
    private:
        std::string input;
        bool skipIntros = 0;
        std::string zone;
    public:
        void startMenu();
        void newGameIntrosOn();
        void newGameIntrosOff();
        void statusUpdate();
        void actionPrompt();
};

int main()
{
    interface initiate;
    initiate.startMenu();
}

void interface::startMenu()
{
    interface initiate;
    startMenu:
    for(;;)
    {
        std::cout << "Welcome to [insert game title]! \n";
        std::cout << "1) New Game \n";
        std::cout << "2) Launch Settings \n";
        std::cout << "0) Quit \n";
        std::cout << "Enter a number: ";
        for(;;)
        {
            getline (std::cin, input);
            if (input == "1")
            {
                if (skipIntros == 0)
                    initiate.newGameIntrosOn();
                if (skipIntros == 1)
                    initiate.newGameIntrosOff();
            }
            else if (input == "2")
            {
                for(;;)
                {
                    std::string skipIntrosOnOff;
                    if (skipIntros == 0)
                        skipIntrosOnOff = "Off";
                    else if (skipIntros == 1)
                        skipIntrosOnOff = "On";
                    std::cout << "\n";
                    std::cout << "Launch Settings: \n";
                    std::cout << "1) Skip Intros: " << skipIntrosOnOff << "\n";
                    std::cout << "0) Cancel to Start Menu \n";
                    std::cout << "Enter a number: ";
                    for(;;)
                    {
                        getline (std::cin, input);
                        if (input == "1")
                        {
                            if (skipIntros == 0)
                            {
                                skipIntros = 1;
                                skipIntrosOnOff = "On";
                            }
                            else if (skipIntros == 1)
                            {
                                skipIntros = 0;
                                skipIntrosOnOff = "Off";
                            }
                            std::cout << "\n";
                            std::cout << "Skip intros has been set to: " << skipIntrosOnOff << "\n";
                            break;
                        }
                        else if (input == "0")
                        {
                            std::cout << "\n";
                            goto startMenu;
                        }
                        else
                        {
                            std::cout << "\"" << input << "\" is not a valid input. Please enter either 1 or 0: ";
                            continue;
                        }
                    }
                }
            }
            else if (input == "0")
            {
                std::cout << "\n";
                exit(0);
            }
            else
            {
                std::cout << "\"" << input << "\" is not a valid input. Please enter either 1, 2 or 0: "; continue;
            }
        }
    }
}

void interface::newGameIntrosOn()
{
    std::cout << "\n";
    std::cout << "[insert intro here] \n";
    std::cout << "\n";
    std::cout << "When you're ready to start your first morning, enter 1: ";
    for(;;)
    {
        getline (std::cin, input);
        if (input == "1")
        {
            zone = "zone1";
            statusUpdate();
        }
        else
        {
            std::cout << "\"" << input << "\" is not a valid input. Enter 1 to begin the first morning: \n"; continue;
        }
    }
}

void interface::newGameIntrosOff()
{
    std::cout << "\n";
    std::cout << "When you're ready to start your first morning, enter 1: ";
    for(;;)
    {
        getline (std::cin, input);
        if (input == "1")
        {
            zone = "zone1";
            statusUpdate();
        }
        else
        {
            std::cout << "\"" << input << "\" is not a valid input. Enter 1 to begin the first morning: \n"; continue;
        }
    }
}

void interface::statusUpdate()
{
    std::cout << "\n";
    std::cout << "You feel normal \n"; //health conditions list will later be displayed here
    std::cout << "The current time is 00:00 \n"; //time will later be displayed here
    std::cout << "You are wielding: nothing \n"; //equipped item will later be displayed here
    std::cout << "\n";
    actionPrompt();
}
Last edited on
Next is the actionPrompt() function, which goes immediately after the previous code:

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
void interface::actionPrompt()
{
    actionPrompt:
    for(;;)
    {
        std::cout << "Enter a command: "; getline (std::cin, input);
        
        //Main Inputs
        if (input == "help" || input == "?")
        {
            std::cout << "\n";
            std::cout << "Command List: \n";
            std::cout << "\"help\"/\"?\" - Displays a list of commands for the current \n";
            std::cout << "interface \n";
            std::cout << "\"menu\"/\"gm\" - Opens the game menu \n";
            std::cout << "\"status\"/\"st\" - Displays status update \n";
            std::cout << "\"travel\"/\"t\" - Travel to the other zone \n";
            std::cout << "\n";
            continue;
        }
        else if (input == "menu" || input == "gm")
        {
            gameMenu:
            std::cout << "\n";
            std::cout << "Game Menu: \n";
            std::cout << "1) Return to Game \n";
            std::cout << "2) In-Game Settings \n";
            std::cout << "0) Quit to Start Menu \n";
            std::cout << "Enter a number: ";
            for(;;)
            {
                getline (std::cin, input);
                if (input == "1")
                {
                    std::cout << "\n";
                    goto actionPrompt;
                }
                else if (input == "2")
                {
                    std::cout << "\n";
                    std::cout << "Sorry, the in-game settings are still in development. \n";
                    goto gameMenu;
                }
                else if (input == "0")
                {
                    std::cout << "\n";
                    std::cout << "Are you sure you want to end the current game and quit to the \n";
                    std::cout << "start menu? All progress will be lost. \n";
                    std::cout << "Enter q to quit or c to cancel back to the game menu: ";
                    for (;;)
                    {
                        getline (std::cin, input);
                        if (input == "q")
                        {
                            std::cout << "\n";
                            startMenu();
                        }
                        else if (input == "c")
                            goto gameMenu;
                        else
                        {
                            std::cout << "\"" << input << "\" is not a valid input. Please enter either q to quit to the \n";
                            std::cout << "start menu or c to cancel back to the game menu: "; continue;
                        }
                    }
                }
                else
                {
                    std::cout << "\"" << input << "\" is not a valid input. Please enter either 1, 2 or 0: "; continue;
                }
            }
        }
        else if (input == "status" || input == "st")
            statusUpdate();
        else if (input == "travel" || input == "t")
        {
            if (zone == "zone1")
            {
                std::cout << "\n";
                std::cout << "Would you like to travel to zone 2? y/n: ";
                for(;;)
                {
                    getline (std::cin, input);
                    if (input == "y")
                    {
                        std::cout << "\n";
                        std::cout << "You are now in zone 2. \n";
                        zone = "zone2";
                        statusUpdate();
                    }
                    else if (input == "n")
                    {
                        std::cout << "\n";
                        goto actionPrompt;
                    }
                    else
                    {
                        std::cout << "\"" << input << "\" is not a valid input. Please enter either y \n";
                        std::cout << "to travel to zone 2 or n to cancel: "; continue;
                    }
                }
            }
            else if (zone == "zone2")
            {
                std::cout << "\n";
                std::cout << "Would you like to travel back to zone 1? y/n: ";
                for(;;)
                {
                    getline (std::cin, input);
                    if (input == "y")
                    {
                        std::cout << "\n";
                        std::cout << "You are now in zone 1. \n";
                        zone = "zone1";
                        statusUpdate();
                    }
                    else if (input == "n")
                    {
                        std::cout << "\n";
                        goto actionPrompt;
                    }
                    else
                    {
                        std::cout << "\"" << input << "\" is not a valid input. Please enter either y \n";
                        std::cout << "to travel to zone 1 or n to cancel: "; continue;
                    }
                }
            }
        }

        //Alternative Inputs
        else if (input == "move" || input == "walk")
        {
            std::cout << "\n";
            std::cout << "It seems like you are trying to move to another location. \n";
            std::cout << "Try entering the \"travel\" command. \n";
            std::cout << "\n";
            continue;
        }
        else if (input == "map")
        {
            std::cout << "\n";
            std::cout << "You don't have a map. \n";
            std::cout << "\n";
            continue;
        }
        else if (input == "rest" || input == "sleep")
        {
            std::cout << "\n";
            std::cout << "You can't rest here. \n";
            std::cout << "\n";
            continue;
        }

        //Else (Invalid) Input
        else
        {
            std::cout << "\"" << input << "\" is not a valid input. You may enter \"help\" for a list of commands. \n";
            continue;
        }
    }
}
IMO, the reason you need to resort to goto is because your functions are doing way too much and your reliance on infinite loops (for(;;)) and because you have everything contained in your classes. In C++ not everything must (should) be contained within classes.

Oh and by the way you haven't got rid of all the recursive calls either.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void interface::statusUpdate()
{
...
    actionPrompt();
}

void interface::actionPrompt()
{
...
            statusUpdate();
...
                        statusUpdate();
...
                        statusUpdate();

...
}


There may be other places where you're still recursively calling something as well, but since I find it almost impossible to follow your logic I'm only guessing.

I know you don't want to hear this but you should really consider starting over. Your functions should do as little as possible, but do that "little" very well. Small single minded functions are much easier to test and troubleshoot than large rambling functions. And remember that not everything must be part of a class and you should strive to separate the user interface from the actual game logic.

Thank you for pointing all of that out. Being that I'm a total n00b though, the reason I haven't simplified my functions is because I don't really know where to relocate all that content and I still need a way for the content in the functions to be summoned, or "called" from virtually anywhere else in the game, and functions are the only way I know how to do that. Or perhaps you mean that I should just splice the functions into many smaller functions, I'm not sure.

Additionally, I would not doubt that you are right on having to start over but I currently lack the knowledge to rebuild a sufficient version. Again, I feel like a lot of this would be simplified if I could find some source code of a similarly designed game. At this rate, it feels like the online tutorials aren't helping because a lot of them are insufficient in describing the range and limits of the code in their topic. For example, one that quickly comes to mind is the article from this website on function recursion (http://www.cplusplus.com/articles/D2N36Up4/) that mentions nothing of the major risk of stack overflow from improper function recursion. Maybe I'm overlooking a crucial factor here, I dunno. At the very least though, i believe I can separate the user interfaces from the game logic. That would be a start.
Again, I feel like a lot of this would be simplified if I could find some source code of a similarly designed game. At this rate, it feels like the online tutorials aren't helping because a lot of them are insufficient in describing the range and limits of the code in their topic.

I suggest you find a good book that is teaching the language, online tutorials are not the best way to learn the language since they usually only cover a small fraction of a topic. The topic you linked is a good example, it just explains in the most basic way what recursion means. It doesn't even begin to explain why one would want to use recursion or any of the drawbacks of using recursion.

Being that I'm a total n00b though, the reason I haven't simplified my functions is because I don't really know where to relocate all that content and I still need a way for the content in the functions to be summoned, or "called" from virtually anywhere else in the game, and functions are the only way I know how to do that.

So what don't you understand?

At the very least though, i believe I can separate the user interfaces from the game logic. That would be a start.

How do you intend to do this given the previous quote? I would imagine more functions? Remember functions should do very little, usually one thing, and do that one thing very well. Small simple functions are much easier to troubleshoot and the logic is usually much easier to follow. Using all of those goto statements and all of those intentional endless loops make your logic almost impossible to follow. You really really need to simplify the logic and remember in C++ it is usually a bad practice to have everything contained inside some gigantic class, even classes should do as little as possible and should follow the "one responsibility principle". Here is a link describing a "design pattern" you may want to consider. And when reading this link make sure you pay close attention when it mentions things like " Open-Closed Principle" and “God object” (and many more such "topics"), you will probably want to research such topics if you don't understand what they mean. And remember that this is not the only way to accomplish the the goals of writing your program, many times there are multiple "design patterns" that may be combined to create one application (game).

I'm sorry, but where is the link? Also, in the meantime, I think I'm just going to spend most of my time finding the right book(s) for this.
OK, so I came up with a few ideas on how to handle these problems.

Something I just discovered recently are these things called C++ patterns. I wonder if they are worth looking into.

Another idea if anyone would be interested is if I create a simple flow chart of some of the in-game menus and let an experienced programmer start on some of the code. I think this would help a lot since it would allow me to get the picture of how user interfaces are supposed to be programmed.

Either way, out of all the project's development processes, coding has currently been the biggest issue for me. Aside from that, a recommended book I keep finding is this Beginning C++ Through Game Programming, 4th Ed., although it was the 2nd ed. we studied in high school. Needless to say, it was with this book that led me to my current situation in programming. I remember we only got to like chapter 5 or something and a lot of the concepts were hard to grasp without the help of the teacher. I guess I'll have to keep book searching.
C++ Book on Beginning Game Programming:

Michael Morrison - Beginning Game Programming (1st Edition)

http://www.informit.com/store/beginning-game-programming-9780672326592

Finished book - vector iterator fix: void GameEngine::CleanupSprites() { //Incrementally remove every sprite from memory vector <Sprite>::iterator siSprite; for (siSprite = m_vSprites.begin(); siSprite != m_vSprites.end(); siSprite++) delete (*siSprite);//Remove the vector elements m_vSprites.erase(m_vSprites.begin(), m_vSprites.end()); } http://www.cplusplus.com/forum/beginner/47420/
@rjphares,

Thanks for the link, I was able to order a copy (collectable) at a good price from Amazon US. It was less than half price for any of the new copies.

I have Morrison's previous book from 2003, https://www.amazon.com/Sams-Teach-Yourself-Programming-Hours/dp/067232461X/ and found it to be useful for regular Windows API games.

There are a couple of games/chapters that overlap, there are some differences that make the purchase worth it.

Two new chapters as well for the 2004 book.
Last edited on
Between the battle of the two Michaels, I think Dawson wins over, since his book (Beginning C++ Through Game Programming, 4th Ed.) is more well known, has a higher customer rating, and a new copy is about 1/3 of the price. Just some superficial comparisons, though.

Aside from that, I thought I'd give a shot at posting that aforementioned flowchart, containing a basic UI template for the game. This is about as bare bones as I can make it. This current version has the basic feedback loop between the two distinctive "game states": the start screen and in-game. It also has the game's core mechanic, the "action prompt". The flowchart is still pretty expansive as it is, so please bear with me on it.

https://drive.google.com/file/d/19b3FeRXTQPDWODwhtijjmppDhxAnYuR2/view?usp=sharing

The person who provides the most effective code will be thoroughly credited. Again, this would be highly useful since it will provide me some basic tools on how to write the rest of the UI. Until then, I'll be figuring out how to rewrite the code myself.

Lastly, if it'll help, I'll provide some UI display text of the mentioned interfaces in the flowchart to show how it's supposed to be displayed in the game (underscores represent an input prompt).

Start Menu:
Welcome to [insert game title]!
1) New Game
0) Quit Game
Enter a number: _

Action Prompt:
Enter a command: _

Game Menu:
Game Menu:
1) Return to Game
0) Quit to Start Menu
Enter a number: _

Quit Prompt:
Are you sure you want to quit? All progress will be lost.
Enter q to quit or c to cancel back to the game menu: _

invalid input: Start Menu/Game Menu:
That is not a valid input. Please enter either 1 or 0: _

invalid input: Action Prompt:
That is not a valid input. Please enter "gm" to open the game menu: _

invalid input: Quit Prompt:
That is not a valid input. Please enter either q to quit to the start menu 
or c to cancel back to the game menu: _

If you have any questions, please let me know.
Last edited on
Alright, so a lot has happened over the past month or so. The problem I noticed with my situation is that I can't figure out how effectively code the game's menu branching system. After trying goto's, nested for loops, and void functions with circular calling and recursion, I realized that they had inherent flaws, so now I need to try something new. I bought Dawson's book and read over most of the chapters, but still couldn't figure out how to code that menu branching system.

Recently though I learned about a concept known as data-driven programming after reading these two posts containing similar problems:

https://codereview.stackexchange.com/a/49636
http://www.cplusplus.com/forum/beginner/121532/#msg673329

Using this method could really improve my code structure, such as separating the data from the game logic. My current objective now is finding out how to apply it to the framework version of the game I posted above and revising my code structure from there. My first attempt will be at trying to create a "Number Choice Menu" template object to implement on a lot of the menus such as the Start Menu and Game Menu. At this point then I'll have to figure out some basics like how to apply vectors, references or pointers to this new "template style" format. I will try to post any of my findings here. If there is another approach I can take though besides attempting data-driven code, someone, please speak out.
yes.

Edit: Try to actually think about how characters, items, etc. will be stored. To put it bluntly, all you have here is "Press X to read more of the story".

Add some content and new [programming] challenges to solve. Yes, you may have some issues with functions circling around and calling each other, but it's all the same problem... adding more walls of text, more menus, more 0-parameter functions won't help you progress.

Some ideas:
- storing a player
- thinking about what other "objects" a player may need
- file i/o for saving and loading
- zones -- what are they composed of?

Start breaking things up into logical parts, multiple files, etc.
Last edited on
Pages: 12