Sign in to follow this  
nullsquared

Is my main.cpp good or did I over do it?

Recommended Posts

nullsquared    126
How's my main.cpp file? I think it's good, but maybe it's just too short?
#include "CGameManager.h"

int main(int argc, char *argv[])
{
    CGameManager gMainGame;

    if (!gMainGame.GetStatus())
        return gMainGame.GetStatus();

    while (gMainGame.Handle())
        gMainGame.Render();

    return gMainGame.GetStatus();
}

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
Frankly I wouldn't allocate CGameManager on the stack like that. That's my personal taste.

Also depending on the return value of Handle() probably isn't the best way to determine if your game is still running. Probably would want something more specific like CGameManager::IsRunning().

What's the 'g' in gMainGame? Clearly, it's a local not a global which is what I would expect the 'g' to mean.

Obviously you have a lot of initialization in your constructor. I don't like that pattern; most other people don't either.

Share this post


Link to post
Share on other sites
acraig    471
I notice that your main loop is just:
gMainGame.Render();

To me that is a bit misleading because to me Render is "Render Graphics". This does not mention anything about where:

Input is handled.
Sound is handled.
Game AI/logic is handled.
Networking ( if in use ) is handled.


I assume all this handled in the Render function but a better name might be Tick or Step.

Share this post


Link to post
Share on other sites
nullsquared    126
Quote:
Original post by Undeadlnsanity
Haha, brilliant! I'd hate to see what CGameManager.h looked like though.


CGameManager.h: 32 lines with #ifndef ... #define ... #endif.

This is supposed to be a ping pong game, but one just started. It's splitted into 11 files along with main.cpp, since it has an SDL wrapper. It's input, events, init', deint', and sprite. CGameManager just handles stuff because I don't like main(...). *cough* She and I had problems. *cough*

The engine is supposed to be somewhat 'reusable' next time, so I don't have to write sloppy stuff.

There isn't "ALOT" initialization in CGameManager::CGameManager. Just:

CGameManager::CGameManager(): m_SCREEN_W(640), m_SCREEN_H(480), m_SCREEN_BPP(32), m_Status(true)
{
if (!m_MainApp.Init(SDL_INIT_VIDEO))
{
m_Status = false;
return;
}

if (!m_MainApp.InitWindow(m_SCREEN_H, m_SCREEN_W, m_SCREEN_BPP, SDL_HWSURFACE | SDL_DOUBLEBUF))
{
m_Status = false;
return;
}

SDL_WM_SetCaption("Crazy Pong! ~Agi~", NULL);
}



So, any other ideas?

P.S. 'g' for 'game'. I didn't know other people recognized 'g' as 'global'.

Share this post


Link to post
Share on other sites
nullsquared    126
Quote:
Original post by acraig
I notice that your main loop is just:
gMainGame.Render();

To me that is a bit misleading because to me Render is "Render Graphics". This does not mention anything about where:

Input is handled.
Sound is handled.
Game AI/logic is handled.
Networking ( if in use ) is handled.


I assume all this handled in the Render function but a better name might be Tick or Step.


Noo... Not exactly. What's gMainGame.Handle() in there for? [smile]

EDIT: Handle(...), not Run(...) ;)!

EDIT: It's EDIT, not DIT ;)))!

Share this post


Link to post
Share on other sites
superpig    1825
Why not move all that initialisation out of the constructor and into something like CGameManager::Initialise()? That way you could return true or false directly, and you wouldn't need the extra status variable.

Share this post


Link to post
Share on other sites
nullsquared    126
Quote:
Original post by superpig
Why not move all that initialisation out of the constructor and into something like CGameManager::Initialise()? That way you could return true or false directly, and you wouldn't need the extra status variable.


A fake init() function? That's what the constructor is for, initialization! And I need m_Status to return in main, so I don't return any ugly 0's. Plus I can use m_Status as a check, too.

Share this post


Link to post
Share on other sites
deathwearer    367
Quote:
Original post by agi_shi
Quote:
Original post by superpig
Why not move all that initialisation out of the constructor and into something like CGameManager::Initialise()? That way you could return true or false directly, and you wouldn't need the extra status variable.


A fake init() function? That's what the constructor is for, initialization! And I need m_Status to return in main, so I don't return any ugly 0's. Plus I can use m_Status as a check, too.


The constructor is more used to Init your attributes (not sure of the english word) to their starting values. e.g m_bGameRunning = true;

The SDL Initialisation should be in a function because this way it can return if the Init was succesfull or no.

Share this post


Link to post
Share on other sites
nullsquared    126
Quote:
Original post by deathwearer
Quote:
Original post by agi_shi
Quote:
Original post by superpig
Why not move all that initialisation out of the constructor and into something like CGameManager::Initialise()? That way you could return true or false directly, and you wouldn't need the extra status variable.


A fake init() function? That's what the constructor is for, initialization! And I need m_Status to return in main, so I don't return any ugly 0's. Plus I can use m_Status as a check, too.


The constructor is more used to Init your attributes (not sure of the english word) to their starting values. e.g m_bGameRunning = true;

The SDL Initialisation should be in a function because this way it can return if the Init was succesfull or no.


Initializers lists are for that.

Share this post


Link to post
Share on other sites
Zahlman    1682
Throw an exception if something goes wrong in the constructor. Since that's obviously not supposed to happen, it's a valid use of the exception (assuming you can make the ctor exception-safe). Also, the status is *not* going to be "failed" after the main loop ends - if it's possible for something seriously wrong(TM) to happen during that loop, you could throw an exception from there, too. That gets rid of the need for GetStatus() entirely (and it was buggy: (a) it gets called twice at the beginning and we don't know right now that it doesn't have side effects; (b) the return from main is supposed to be 0, i.e. a 'false' value, if everything went ok. The reasoning on that one is that there is only one way for everything to be ok and multiple ways to fail, so the unique 0 value is used for success and non-zero values for error codes. Also sprach POSIX.)

Also, I'd give the game constructor a chance to look at the command-line arguments - you may want that later :)


#include <vector>
#include <string>
#include <exception> // or should it be <stdexcept>?
#include <iostream>
using namespace std;

int main(int argc, char *argv[]) {
vector<string> arguments(argv, argv + argc); // I think that's right
try {
// I vote against Hungarian notation and I especially hate the 'C'
// prefix for classes. Also, this instance is *not* a global.
GameManager mainGame(arguments);
while (mainGame.doLoop()); // why complicate the interface more than that?
} catch (exception& e) {
cout << "OH NOES!!!11 " << e.what() << endl;
return -1; // some sort of error.
// You could use your own exception class and give it a .errorCode()
// function or something.
}
// 0 is returned implicitly here if no exception happened.
}

Share this post


Link to post
Share on other sites
helix    301
That's roughly similar to many of our game main functions. There is an application class that handles all the good stuff and main basically instantiates it, inits it, and then runs or calls its game loop. Occasionally we have to add a few more lines of crap in there for various technologies we need to use and so on.

At any rate, if you encapsulate everything well into your game manager, it's all good.

Share this post


Link to post
Share on other sites
nullsquared    126
Quote:
Original post by Zahlman
Throw an exception if something goes wrong in the constructor. Since that's obviously not supposed to happen, it's a valid use of the exception (assuming you can make the ctor exception-safe). Also, the status is *not* going to be "failed" after the main loop ends - if it's possible for something seriously wrong(TM) to happen during that loop, you could throw an exception from there, too. That gets rid of the need for GetStatus() entirely (and it was buggy: (a) it gets called twice at the beginning and we don't know right now that it doesn't have side effects; (b) the return from main is supposed to be 0, i.e. a 'false' value, if everything went ok. The reasoning on that one is that there is only one way for everything to be ok and multiple ways to fail, so the unique 0 value is used for success and non-zero values for error codes. Also sprach POSIX.)

Also, I'd give the game constructor a chance to look at the command-line arguments - you may want that later :)


#include <vector>
#include <string>
#include <exception> // or should it be <stdexcept>?
#include <iostream>
using namespace std;

int main(int argc, char *argv[]) {
vector<string> arguments(argv, argv + argc); // I think that's right
try {
// I vote against Hungarian notation and I especially hate the 'C'
// prefix for classes. Also, this instance is *not* a global.
GameManager mainGame(arguments);
while (mainGame.doLoop()); // why complicate the interface more than that?
} catch (exception& e) {
cout << "OH NOES!!!11 " << e.what() << endl;
return -1; // some sort of error.
// You could use your own exception class and give it a .errorCode()
// function or something.
}
// 0 is returned implicitly here if no exception happened.
}


That would just change my code entirely.

How the heck is one variable 'buggy'? It's true. Then, say something fails. It becomes false. The constructor ends before you know it. You check for falsity. Yes, ehh? You end main(). That's it.

Passing main()'s arguments to the constructor may be needed, but if you think about it realy realy hard, you can always provide some other option to change options since I'm not going to run the program from the command line every single time.

Since when was main() needed to return 0? What main() returns is useful for other programs, but nothing else. And if other programs need my program's return code then I wrote them. All I could do then is check if main was fasle or true. Much, much, easier.

Share this post


Link to post
Share on other sites
Conner McCloud    1135
Quote:
Original post by agi_shi
Since when was main() needed to return 0?

Since always. Its a long standing standard, and it is generally bad form to write off standards just because you don't see the point. This particular standard is even promoted by the language itself...if the program reaches the end of main without returning anything, valid execution is assumed and 0 is returned implicitly.

CM

Share this post


Link to post
Share on other sites
Cygon    1219
I don't think a file can be 'too short' in C++ ;)

Creating your CGameManager on the stack is a good idea, if you ask me. That way, your destructor can perform cleanup work in case an exception ends the game.

My main tends to look like this:

int main(int argc, const char *argv[]) {
using namespace std;

try {

// Run a new instance of our game
MyGame(vector<string>(argv, argv + argc)).run();

}
catch(const exception &e) {
cerr << e.what() << endl;

#ifndef NDEBUG
// In debug mode, give the debugger a chance to break
throw;
#endif

return -1;
}

return 0;
}



My applications always have a class with the name of the application itself that have a run() method or an overloaded function operator. Therein you will find the main loop, or whatever is needed to keep the application alive.

-Markus-

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this