Game Engine Design Questions

M

Mark

I'm writing a game engine and I would like some opinions on the way I
have set it up (good or bad), and how I might improve it.

I'm using OpenGL which utilizes callbacks for events (such as when a
mouse is moved or clicked, the window is displayed or resized, a
keyboard button is pressed, etc). I can only pass in static functions
to the callback functions, which means I can't place the callback
functions inside an appropriate class (my title screen, map editor,
and actual game all have different keyboard functions, display
functions, etc, so it would make sense to separate them into the their
respective classes).

So, my first idea was to place the callback functions in the
appropriate classes but make them all static. However, I needed to
address member variables within those classes, so I had to make all
the member variables static too. This meant I could only have one
instance of each class, which wasn't much of a problem since it
wouldn't make much sense to have more than one title screen, or game
editor, running at the same time. However, what if I wanted to have
multiple dialog boxes popping up over top of each other? That might
cause a problem down the road. Also, it's a major pain to make
everything static, since I have to declare everything twice (once
inside the class, and once outside the class, making use of the double-
colon notation).

Then I had the clever idea of making a "callback wrapper". Each of my
classes (title screen, map editor, etc) inherits this class. The
callback wrapper sets each callback function to a static function,
which "reroutes" the call to a member function. I keep a stack of each
object that is created and call the member function of the object that
is on top of the stack. When the object is destroyed, I pop it off
the stack, and the callback reverts to the previous object. In the
scenario I described above, the top-most dialog box would have
control. This also eliminates the annoyance of having static
variables, and some other tedious aspects. However, I now have 11
object stacks (one for each callback so that one object might get
control of the keyboard, but another might have control of display). I
don't think that will consume too much memory though, since I wouldn't
expect more than about 5 "layers" of dialogs/windows. But I do need to
create an extra stack and wrapper every time I want to add a new
callback.

I'm fairly pleased with the second solution, but comments are welcome.

This however lead me to a new "evil". With the way I have it now, I
create a map editor by calling "new Editor()". This automatically
gives the editor control over displaying, the keyboard, etc., as long
as those functions are defined, otherwise the previous class maintains
control. When I "close" the editor (by hitting escape) I call "delete
this", and the callback wrapper automatically gives control back to
the previous class. My concern is that generally objects should not be
in control of deleting themselves. Might this be an exception? The
other question has to do with memory leaks. What if the user wants to
directly close the program from within the map editor? The map editor
is a layer on top of the title screen. So if I just call "delete this"
and then exit(0) from inside the map editor, the title screen would
never get destroyed, would it? Or is everything freed when a program
exits?

That's all for now, thanks for taking the time to read this.
 
V

Victor Bazarov

Mark said:
[... first solution, second solution ...]

I'm fairly pleased with the second solution, but comments are welcome.

Looks acceptable. If your objects are really "stacked" on top of
each other, why not follow the same concept in the object model?
I think you did OK.
This however lead me to a new "evil". With the way I have it now, I
create a map editor by calling "new Editor()". This automatically
gives the editor control over displaying, the keyboard, etc., as long
as those functions are defined, otherwise the previous class maintains
control.

Now, you need to think that if your object covers everything, you
might want to make it control everything but not necessarily by
doing anything meaningful. If something only responds to 'Enter'
key (and no buttons exist in that window), you still might want to
"capture" the mouse, but simply ignore any events...
When I "close" the editor (by hitting escape) I call "delete
this", and the callback wrapper automatically gives control back to
the previous class. My concern is that generally objects should not be
in control of deleting themselves. Might this be an exception?

You could do it that way. Or you could simply let the program know
that your eidtor is no longer in business. As soon as this event
is dispatched (queued), the program will delete the editor at the
moment of processing that event.

It is usually better that the _owner_ disposes of objects it owns.
The
other question has to do with memory leaks. What if the user wants to
directly close the program from within the map editor?

The signal goes to the program, the program shuts down the editor,
then closes.
The map editor
is a layer on top of the title screen. So if I just call "delete this"
and then exit(0) from inside the map editor, the title screen would
never get destroyed, would it? Or is everything freed when a program
exits?

That's unspecified in the language.

V
 
M

Mark

You could do it that way. Or you could simply let the program know
that your eidtor is no longer in business. As soon as this event
is dispatched (queued), the program will delete the editor at the
moment of processing that event.

It is usually better that the _owner_ disposes of objects it owns.

Just thinking about this for a bit. I have a Main class that simply
brings up the TitleScreen at the start of the program.

Main::Main()
{
new TitleScreen();
}

Since it created the TitleScreen, it should be responsible for
deleting it. So, I could set up a pointer like

TitleScreen *ts = new TitleScreen();

and then I could

delete ts;

When it's done. That's fine. But how is the TitleScreen supposed to
signal the Main class? There is no function that returns to Main, Main
is no longer control of the idle() loop, so it can't periodically
check for any boolean flags. The only thing I can think of is to set
up yet another callback. When TitleScreen decides its done, it calls
some function in Main to let it know that it's done. But that means
that TitleScreen also needs to know who created it, so it can call the
appropriate function, so then I need to do something like

TitleScreen *ts = new TitleScreen(this);

Don't I? Is that really a better solution?

It does however, solve the other problem of cleaning up. If
TitleScreen can inform Main that it's done, then it doesn't need to
call exit(0) and Main can properly finish deleting any other data.

I guess then I should ask, what is the best way for me to make my
objects communicate to each other? (Can anyone point me to an
article?) I've never had to do anything quite like that before.
Now, you need to think that if your object covers everything, you
might want to make it control everything but not necessarily by
doing anything meaningful. If something only responds to 'Enter'
key (and no buttons exist in that window), you still might want to
"capture" the mouse, but simply ignore any events...

I just include an empty function. That way it keeps control, but
doesn't do anything.
 
A

Alf P. Steinbach

* Mark:
I have a Main class that simply
brings up the TitleScreen at the start of the program.

Main::Main()
{
new TitleScreen();
}

Since it created the TitleScreen, it should be responsible for
deleting it. So, I could set up a pointer like

TitleScreen *ts = new TitleScreen();

and then I could

delete ts;

When it's done. That's fine. But how is the TitleScreen supposed to
signal the Main class? There is no function that returns to Main, Main
is no longer control of the idle() loop, so it can't periodically
check for any boolean flags.

The above looks very much like functions. It's seems you're using
constructors as functions. There are some cases where that is
appropriate, but I think you would be better served by doing

void titleScreen()
{
// ...
}

int main()
{
titleScreen();
}

Cheers, & hth.

- Alf
 
M

Mark

The above looks very much like functions. It's seems you're using
constructors as functions. There are some cases where that is
appropriate, but I think you would be better served by doing

void titleScreen()
{
// ...
}

int main()
{
titleScreen();
}


Not all my constructors look like that. Some of them need to set
member variables, which isn't possible with a static function.
Basically, I'm making the constructors responsible for doing all the
loading, which is necessary to do before calling any of the display(),
idle(), keyboard() etc functions. The reason I made Main() a class was
so that I could have a base layer for my callback functions. For
example, it's in charge of the reshape() function, which none of the
other "layers" need to override. It also prevents errors when
attempting to pop off the TitleScreen (accessing empty stacks), since
the Main class should never be deleted. It did occur to me that I was
using the constructors a bit like ordinary functions, but I think it
makes more sense when they do all the loading.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

Forum statistics

Threads
473,769
Messages
2,569,577
Members
45,052
Latest member
LucyCarper

Latest Threads

Top