Game Engine Design Questions

Discussion in 'C++' started by Mark, Jan 11, 2008.

  1. Mark

    Mark Guest

    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.
    Mark, Jan 11, 2008
    #1
    1. Advertising

  2. Mark wrote:
    > [... 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
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
    Victor Bazarov, Jan 11, 2008
    #2
    1. Advertising

  3. Mark

    Mark Guest

    On Jan 11, 2:31 pm, "Victor Bazarov" <> wrote:
    > 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.
    Mark, Jan 12, 2008
    #3
  4. * 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

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
    Alf P. Steinbach, Jan 12, 2008
    #4
  5. Mark

    Mark Guest

    On Jan 11, 5:55 pm, "Alf P. Steinbach" <> wrote:
    > 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.
    Mark, Jan 12, 2008
    #5
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. BlackHawke
    Replies:
    12
    Views:
    1,548
    Andrew Thompson
    Jan 26, 2004
  2. judith
    Replies:
    0
    Views:
    1,626
    judith
    Nov 1, 2006
  3. Max Kubierschky
    Replies:
    10
    Views:
    1,821
    pabloreda
    Mar 31, 2007
  4. Advertiser for `2D Games Development Central`

    {Game Development} 2D Game Development Central

    Advertiser for `2D Games Development Central`, May 7, 2008, in forum: Java
    Replies:
    2
    Views:
    399
    RedGrittyBrick
    May 8, 2008
  5. dex
    Replies:
    24
    Views:
    642
Loading...

Share This Page