Jump to content
  • Advertisement
Sign in to follow this  
Tispe

How to structure a game in OOP

This topic is 2012 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, I have rewritten my project several times to adapt to new game structures. I do this to conform to rules such as, no static or global variables, no singleton patterns and the single responsibility principle.

 

The application consist of class objects. I often find myself creating a "super" class to only make one instance of it. Such as a Renderer class. This class handles the window, resolution, fullscreen toggle and draws the scene.

 

Another class is the Asset Manager, one instance is created and it handles loading files and preparing them for later use. It keeps an array of all assets. Since the Asset Manager needs the device to create resources (VB, IB, Textures) in the managed pool, I keep a private pointer to the device in Asset Class and make a copy in the constructor. This cross object dependancy is to conform to the "rules", maybe there is a better solution?

 

The Entity class has one instance, it has a list of (pointers to) Player objects (struct). These player structs contain information such as what Skeleton to use, what Mesh to use, and character variables.

 

When rendering I pass the list of Entities to the renderer which looks up the Asset Manager for the resources and draws them as described in the Player object. 

 

There are also other classes such as the animator and gui but I kept those out to keep it short. Is this a good game structure? What should I pay attention to, and are there any other game structures I should consider?

 

The pseudo-code:

main(){
InputOutputClass IO;
DeviceClass Renderer;
AssetClass Assets(Renderer.GetDevice());
EntityClass Entities;
GuiClass Gui(Renderer.GetDevice());

MainLoop(Renderer, Assets, Entities, IO, Gui);

}
Edited by Tispe

Share this post


Link to post
Share on other sites
Advertisement

Sorry that has got to be the absolute worst reason to rewrite your code

 

Totally agree 100%.  The only reason you should rewrite this stuff is if you find it stops you from extending your game or is inflexible in some way.   Refactoring just to avoid other peoples opinions of what is bad software engineering is just a time suck when what you should be concentrating on is getting things done.

Sure some people don't like statics, globels or singletons but that doesn't mean they should be avoided entirely.  Each has its use cases.

 

Share this post


Link to post
Share on other sites

I often find myself creating a "super" class to only make one instance of it. 

 

Premature abstraction is the object-oriented root of all evil.

 

Use a good refactoring tool, go over the code and try to remove all unnecessary abstractions. Then, go over the code again and see if you find code duplications. Those are the candidate points for introducing new abstractions. Repeat this process a few times and you should end up with a much cleaner framework.

Share this post


Link to post
Share on other sites

But if I don't bundle things into an object, I would have to either keep them global or have massive amounts of arguments to pass around, creating a huge web of dependancies. Is it bad to make a class if only one instance will be made from it? Surely classes are not only for abstraction?

Share this post


Link to post
Share on other sites

The render class holds everything from device to shaders. It's the glue between my assets and the Graphics API. And in this class I have functions like 'ChangeResolution(MyStruct Params)' and Render(MyClass *Entities).

 

I read that the only difference between struct and class is that members are public in struct by default and private in classes by default. So changing they key word 'class' to 'struct' has no meaning.

 

Bundling stuff in classes or structs is the same, but is it proper to use it in this case?

Share this post


Link to post
Share on other sites

Yes, it's good practice to put your state inside of objects, even if there's only one instance of the class. The question is of course where to put each individual variable. If you're not satisfied with the architecture but you don't know what to do, one approach is to just shuffle the code around and see what happens. Experiment with merging and splitting classes and functions. Look for new names, and try to make them as concrete as possible. Poke around and see if you find any redundant duplications or code smells. It usually takes a few iterations before the architecture settles.

Share this post


Link to post
Share on other sites

It sounds to me like you have a lot of questions but few answers.  If you want my opinion, before you start coding, take a step back and draw your application on paper.  Make sure you understand the interactions between the different subsystems, and how you want them to communicate with eachother.  Get a real understanding of how you WANT the system to work, then you can refine your design.  However, if you just jump in and start making a mess, and hope to figure it out as you go along, you're going to run into problems, and just make your code messier.

 

These are some things I like to avoid in my design:

  • Global state.  There's just no need.  Any situation where a Singleton is a solution, there is often a better solution that doesn't use a Singleton.  This is an opinion I formed after using Singletons for a long time, and gradually realizing how evil they are the hard way.  
  • Avoid global event systems.  They are a nightmare to debug.  Prefer a callback/delegate architecture.  Another thing I had to learn the hard way.
  • Make sure your subsystems are compartmentalized.  For instance, there is no reason for a sound object to contain a pointer to a physics object.  Keep your systems separate and join them using a higher level interface.
  • Make your APIs easy to understand, and difficult to use incorrectly.

Good luck.

Share this post


Link to post
Share on other sites

  • For instance, there is no reason for a sound object to contain a pointer to a physics object.  Keep your systems separate and join them using a higher level interface.

 

Well, this is where it gets tricky for me. The APIs for sound and graphics are different systems. I can encapsulate them in my own classes and simplify the interfaces for my use. But for example there has to be a place in the code where a sound is triggered when the animation passes a point. We are now far down a method in the animation class and we discover that we need to trigger a sound. Where is the pointer to the sound interface when we are in the animation system?

 

Globals?

Singletons?

Coupling by having a pointer to the sound system as a member in the animation class?

 

Having a higher level interface that calls the DoAnimation() method, I need return values in order to call DoSound() afterwards. But I just shuffle the burden up the food chain. Now I have to code a ton of different states that must be passed and returned and bloat the calling code, making it more complex.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!