Thread: Module Development for Game Design - By Jeff Verkoeyen

  1. #1
    Lead Moderator kermi3's Avatar
    Join Date
    Aug 1998
    Posts
    2,595

    Module Development for Game Design - By Jeff Verkoeyen

    Kermi3

    If you're new to the boards, welcome and reading this will help you get started.
    Information on code tags may be found here

    - Sandlot is the highest form of sport.

  2. #2
    S Sang-drax's Avatar
    Join Date
    May 2002
    Location
    Göteborg, Sweden
    Posts
    2,072
    Objects in a game are also very good to represent with abstract base classes.

    Code:
    class Object
    {
    public:
    
      Object();
    
      virtual void process() = 0;
    
      bool isAlive();
    
      int getPriority();
    private:
      int priority;
      bool alive();
    };
    
    //Other abstract subclasses
    class GraphicObject;
    class ConcreteObject;
    Then the game loop can process every object in the game using a container:

    Code:
    std::list<Object*> objectList= ...
    
    while (true)
    {
      sort(objectList);  //Sort by priority
      for each (object <- objectList)
      {
         obj->process();
         if (!obj->isAlive)
           objectList.remove(obj);
      }
    }
    New types of enemies, weapons etc. can be added to the game without recompiling the game loop or almost anything else.
    Last edited by Sang-drax : Tomorrow at 02:21 AM. Reason: Time travelling

  3. #3
    vae victus! skorman00's Avatar
    Join Date
    Nov 2003
    Posts
    594
    The modular Game class is a great method to use in any project, especially a party game consisting of several mini games.

    As with game entities as Sang-drax indicated, it is sometimes useful to create an abstraction layer on aspects of game logic, rendering, or any other component using similar methods. This is most beneficial when their is a high risk of problems with the chosen technology being used.

    These are common practices in other software industries, but, unfortunately, still foriegn to several game developers.

  4. #4
    Carnivore ('-'v) Hunter2's Avatar
    Join Date
    May 2002
    Posts
    2,879
    That's a neat and efficient system to use. However, how could this be applied to making menus (an important module to include in any game)? What if you wish for your game to remain running in the background while you access a menu, i.e. you don't want it to shut down every time you go to the menu screen? The system works fine if you simply want the game to change states, but it seems to me that having overlapping states might require a more complex mechanism - perhaps a module loop discretely nested in the main game module's Execute() function. Even then though, it would probably pause/stall the game while accessing the menu. Does anyone have better suggestions? (Or is multithreading always the answer to every question in life?)
    Last edited by Hunter2; 02-09-2005 at 11:39 AM.
    Just Google It. √

    (\ /)
    ( . .)
    c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination.

  5. #5
    vae victus! skorman00's Avatar
    Join Date
    Nov 2003
    Posts
    594
    Code:
    Module* oldMod=gamemod;
    if((gamemod=gamemod->ExecuteModule())!=oldMod)
    {
        lastMod=oldMod;
        lastMod->Shutdown();
        gamemod->Initialize();
    }
    He pointed out that this bit of code can be modified to fit needs. Directly before, or after this check, you can add a loop to control the menus, and exchange information to the game module through several methods. Personally, I think a singleton model would work well in such a situation.

  6. #6
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Ahhhhhhhhhhhhhhh!!!

    Virtuals. I avoid them like the plague in game programming. Don't use virtual functions.

  7. #7
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    You can overdo anything, and avoiding virtuals in one of these things. What alternative approach do you suggest? Virtual calls are faster than switches, unless they're implemented as jump maps - which is far less extensible.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  8. #8
    Carnivore ('-'v) Hunter2's Avatar
    Join Date
    May 2002
    Posts
    2,879
    >>Virtuals. I avoid them like the plague in game programming. Don't use virtual functions.
    May I ask why? It's not like loading/unloading modules is a time-critical operation running in a tight loop anyway. The time spent in actual initialization and destruction will almost certainly overshadow virtual call overhead by such a degree that it becomes neglible.
    Just Google It. √

    (\ /)
    ( . .)
    c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination.

  9. #9
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Virtuals can result in a lot of function call overhead and often times they are misused to the point that this side effect begins to affect the performance of the game. It's probably not critical in applications but it is inside of a main game loop.

    I was going to implement a renderer using virtual functions because it seemed the place to do so. However after reading several books and articles on the topic I decided against it. Instead the rendering is done inside of one main render function. The render function used to call the virtual render function of the class. The problem is that this resulted in a lot of function call overhead inside of a very time critical loop which was quite noticeable. Not only did I have to remove the virtuals but I also had to be careful about how/if I copied structures when rendering objects. What I eventually came up with was this:
    • Since Direct3D is essentially a state machine there are only so many 'useful' render states. These can be preserved using mechanisms provided in Direct3D called state blocks or you can implement them on your own.
    • The renderer should draw all objects from one vertex buffer
    • The renderer should call SetTexture() only as many times as is needed and no more.
    • The renderer should call SetTransform() only as many times as is needed and no more.
    • The renderer should NOT call out to any other code to render objects.
    • The renderer should render similar objects in batches.
    • The renderer should NOT check the current state block.
    • The renderer should NOT have to check any conditionals in order to properly render batches
    • Switching batches and states should be a simple matter of incrementing an integer which acts as an index


    What this amounts to (so far) is this:

    Prior to rendering
    • Cull objects based on frustrum and add vertices to master list if object passes test - add vertices depending on z order and/or priority of object (alpha blended objects must be rendered in correct order or they wont look right)
    • Add object state information to master object state vector
    • Add object transform to world transformation stack
    • Set the vertex buffer up so that vertices that use the same texture are sequentially arranged inside of the buffer
      ...
      ...


    Rendering
    • Retrieve and setup block state from vector of states to be rendered
    • Retrieve index range information for this batch of primitives from object state vector
    • Retrieve primitive type for this batch from object state vector
    • Retrieve texture for this batch from object state vector and call SetTexture()
    • Retrieve world/view transform from matrix stack
    • (Optional)Retrieve vertex shader ptr from effect file for this batch from object state vector
    • (Optional)Retrieve reflection flags (if any) from object state vector
    • Set all shaders/states based on object state and shader info
    • Render the batch
    • Increment batch number counter
    • Repeat process until all batches have been rendered


    What I'm trying to do is sequentially render everything. This amounts to simply incrementing a vector or an integer that indexes into mutliple vectors. As long as everything is lined up correctly in the vectors it should work. Same principle as when rendering bitmaps. You want to linearily traverse the array instead of doing a multiply to find every pixel in the bitmap.

    Fact is this. If you call a virtual render function each time and that render function sets up all the states for an object, then if you have 600 objects on screen you will be rendering each object one at a time and setting the state 600 times, setting the texture 600 times (even if some share the same texture), setting the world/view 600 times, etc, etc.

    So perhaps this isn't just a matter of not using virtuals..it's a matter of once you enter the main render loop...don't leave it until you are done with the scene. It's not easy to set it up this way but Direct3D works a lot better with one huge batch of primitives than with several hundred small batches of primitives. Virtuals already lend themselves to some call overhead and as you see I'm trying to eliminate almost all of the calling overhead. Calls to SetTransform() and SetTexture() cannot be avoided but a good engine will only call them when absolutely necessary. I left some of the list blank because there are certain things I'm still trying to hammer out with this structure.

    That's the method behind my madness and my reason for not using virtuals. And no, I haven't figured out how to get all of this to click yet but I will. I'm having a lot of problems with the world/view transformation - no object will occupy the same space at the same time. So you must always change the translation. But if you use a matrix stack you can effectively do the multiply for the object, pop the stack, and get back to the original matrix. This prevents you from having to compute the inverse to get back to the original matrix.

    Stack on entry to Render:

    ..Base World/View Matrix ( World is identity)


    Stack on first batch:

    ..Transformation/scaling matrix for batch of objects
    ..Base World/View matrix

    So you see that even if you have a complex model with elbows and joints you only have to track how many times you pushed a new matrix onto the stack. Pop off that many and you are automatically back at the original matrix which would transform an object to 0,0,0 in world space. There are other ways to do this as well.
    Last edited by VirtualAce; 02-11-2005 at 05:42 AM.

  10. #10
    S Sang-drax's Avatar
    Join Date
    May 2002
    Location
    Göteborg, Sweden
    Posts
    2,072
    Well, it's not exatly the virtual function call itself which kills the performance then. It's more drawing 600 objects at once versus drawing them one at a time.

    And if you use virtual functions like Jeff Verkoeyen suggested in the article, you won't be able to notice any performance difference.
    Last edited by Sang-drax : Tomorrow at 02:21 AM. Reason: Time travelling

  11. #11
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    It's a matter of executing function calls inside of a render loop.

  12. #12
    Carnivore ('-'v) Hunter2's Avatar
    Join Date
    May 2002
    Posts
    2,879
    If I'm not mistaken, it isn't inside a render loop - it's a mechanism by which you can switch between game modes (i.e. main menu, playing game, high scores, whatever). The render loop would be placed inside the overloaded virtual Execute() function of one module, not vice versa.
    Just Google It. √

    (\ /)
    ( . .)
    c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination.

  13. #13
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    BTW, bubba, each call into DirectX is a virtual function call...
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  14. #14
    Software Developer jverkoey's Avatar
    Join Date
    Feb 2003
    Location
    New York
    Posts
    1,905
    It's completely up to the coder where/how to implement that code. I use it inside of a render function that only gets called once per frame. I personally have not noticed any large performance hit on any of my games by using this system and have found that the amount of code readability/reusability is increased tremendously.

    However, if you are truly worried about speed, you could just have it so each module has its own render loop and returns from that loop when it's finished. I personally would find this to be more of a hassle than anything....but whatever floats your boat.

  15. #15
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    BTW, bubba, each call into DirectX is a virtual function call...
    I was not under the impression that COM was using virtual function calls since COM is a binary standard and not true C++.
    Even though everything is derived from IUnknown it is not the same as a C++ class.
    Please expand on this.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Find Injected DLLs In A Process?
    By pobri19 in forum Windows Programming
    Replies: 35
    Last Post: 02-06-2010, 09:53 AM
  2. Function basics
    By sjleonard in forum C++ Programming
    Replies: 15
    Last Post: 11-21-2001, 12:02 PM