Structure of classes in good Game Engine?

Started by
45 comments, last by Cygon 11 years, 10 months ago

  • Forfeit logging altogether. I've done this in my code. I'm going all-out with assertions for pedantically checking internal states and exceptions for any usage error. Since the point of logging is to help you find the cause of errors quickly, by not letting any inconsistency, bad return code or missing capability slip under the carpet you remove the need for logging.


This is what I do. It's easier to find bugs in the debugger, go figure. And Asserts make your program stop and tell you why IMMEDIATELY. There's no combing through log files to find out why your geometry isn't showing up. Simply add an Assert. You can easily remove asserts from release code when you know your stuff works, by using #define.
Advertisement
Logging is one of the few singletons I have in my game engine, for the simple reason I haven't figured out a sane way to replace it with a non-singleton.
I usually have a function for logging, but I can see the appeal of passing a pointer/reference to a logger to a constructor, because it allows the user of the class to provide any logger they want (a null logger, a logger that prints out to a file, a logger that prints out to stdout, a logger that verifies that the log agrees with some expected text...). This is particularly useful for regression testing.

If you have 38 minutes to burn, consider watching this video.

What I remember from watching it many months ago is that he proposes using polymorphism instead of if statements. The idea is to have two types of code:

  1. The core objects, which make use of pointers to base classes for anything they need (the talk uses Java, so the language is a bit different).
  2. The initialization code, which hooks together the core objects.

His point is that most if statements in code of type 1 can be beneficially replaced with a polymorphic call, the main benefit being ease of testing.

I am not sure how much I buy this method of development, but I would love to try it sometime.

Do you need an object to do that? That's where the free-function comes in for me.


No, not necessarily.


I'd prefer to avoid the uneccesary inheritance here and keep your different log back-ends decoupled:


That's actually very similar to how I used to do it, until I discovered that it's useful to be able to do more than just call "log" from user code. In particular invoking the open and close methods (more importantly the close method) on my logging channels from the logger object, using named channels, dynamically setting named properties on logging channels from configuration dialogs, enumerating channels, dynamically remove channles, etc. The interface that I use isn't exactly as simple as what I posted, but basically all that is necessary to implement is the log method unless the channel wants to expose properties, open/close, or a handful of other functionality. A series of function objects could do the same thing, but that gets quickly gets messy and harder to maintain.
I found this to be a good read: http://accu.org/index.php/journals/246

I haven't personally implemented it, but he addresses several pros/cons in detail.
Why the hell are people so terrified of namespaces?


//SysLogger.h
namespace SysLogger {
extern int loggedItems;
int initialize(char* somedata, int someother);
void logSomething(char* herpderp);
};



//SysLogger.cpp
#include "SysLogger.h"

int SysLogger::loggedItems = 0;
static int fd = -1;

static int miscHelperFunction() {
return foo;
}

int SysLogger::initialize(char* somedata, int someother) {
herpderpSystem = new Foo;
fd = herpderpSystem->makeLogFile();
return 4;
}

void SysLogger::logSomething(char* herpderp) {
loggit(fd, herpderp);
++loggedItems;
}
void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

This is what I do. It's easier to find bugs in the debugger, go figure. And Asserts make your program stop and tell you why IMMEDIATELY.


No they don't. They may stop and tell you that you have a bug, but unless your bugs are extremely well behaved and occur directly at the assert site, they can't tell you anything about why you have a bug or where it's at.

[quote name='sss_abaker' timestamp='1340134846' post='4950694']
This is what I do. It's easier to find bugs in the debugger, go figure. And Asserts make your program stop and tell you why IMMEDIATELY.


No they don't. They may stop and tell you that you have a bug, but unless your bugs are extremely well behaved and occur directly at the assert site, they can't tell you anything about why you have a bug or where it's at.
[/quote]

This is partially true. Asserts make sense and should be used extensively. The reason that an assertion fails however can be hidden somewhere else in the code, it could even have happened several frames ago. Also asserts are usually removed from release code which simply crashes the program for your customers without any information. IMHO log files are invaluable tools for bug fixing after release.
Boy am I gonna be yelled at...

Are you adamant you will only have one logger?
Being so it should be available from pretty much everywhere?
Passing around references seems pointless?

So... why not static?

I think you should avoid to overdesign, the simplest solution is usually the best one, if it gets the job done and doesn't impact your development speed, go for it.
Game making is godlike

LinkedIn profile: http://ar.linkedin.com/pub/andres-ricardo-chamarra/2a/28a/272


I found the service locator pattern (as described here http://gameprogrammingpatterns.com/service-locator.html) a good alternative to the singleton. Its still very global but not that restrictive anymore.

This topic is closed to new replies.

Advertisement