Sign in to follow this  
Angelic Ice

Improving my Class Structure

Recommended Posts

Hello forum!

 

I was wondering if the class structure I pursue might bite me back.

 

Once my game starts, the main instantiates a game-engine class.

I'm worried about this name, as it not clear what exactly this class does.

 

Nonetheless, this class owns the game states and updates them. It also owns the window class.

It shall be a collection of all important components: Music, renderer, states, ...

 

And I feel as this is way too much for a single class.

As I want one class to do one job. Owning states, checking for events, updating states, returning the window, .... seems way too much.

 

About the states:

Should I have a state-storage-, state-loader- and state-updater class?

And where should these reside in? If I decide to stop using the game-engine class, from where would I access all of these?

From state-component-class? And where should this reside in?

 

What about the window-class?

As there will be a renderer for textures and whatnot, how to part these?

Should the window-class own the renderer?

 

I've seen so many different ways of treating classes' jobs.

Sometimes, people tend to give draw()-methods to the window-class itself. Therefore, no further class-encapsulation.

But more bloated classes.

 

If there are any interesting ways of structuring these, I would be really curious to see them : )

 

Share this post


Link to post
Share on other sites

I'm sure there are people on here who are better on this topic than I am, but so far this is basically what I've done. I have a main to make it clear where the entry point is. It sets up the game loop and calls all the classes to get things rolling. It starts by calling an Operating System class to do things like setup a process to run in and a window to draw in. Then I have either an OpenGLGame class or a DirectXGame class depending on which I'm using. That class initializes the API and gives me a device and such. It has a child class which is called the Game class which inherits from the API class. The Game class is really the only class that should ever be modified in my design. Modifying the Game class is how you program the game. The other classes are intended to be packed away in a library and never changed (unless you want to make a change to how the system works). The Game class is the only class I have that uses inheritance. And it uses inheritance so that it inherits all the functionality of the system while obfuscating it, so that you can get straight to work.

 

There's also a GameTimer class. The main loop picks up the game time and passes it to the Game class when that loop calls the Update() and Draw() methods of the Game class.

 

There's a keyboard handler class to handle input for the DX version. From what I've heard, there is no "good" way to handle the keyboard in DX. You can use the Windows event loop and this seems to be what is expected, but I hear there are problems with going down that route. So, I use DX8 to handle the keyboard, since that was the last version that handled the keyboard. I really would like to know what Microsoft is thinking there. For OGL I'm using GLFW and so keyboard handling is greatly simplified.

 

I have a Texture class. Neither DX nor OGL have much support for handling image files. For DX I think I'm using DDS since that's about the only thing it supports natively. For OGL I'm using FreeImage which supports quite a few file types.

 

I have a Shader class, which is probably the one that needs the most work and if I ever have to redesign something here, I would expect that to be the place that needs it. I haven't done enough crazy shader stuff to really test this class and see how it holds up to that kind of environment. What I've got is pretty straight forward to load the shader file and compile it and make the shader available for drawing.

 

That's pretty much it for the core thus far. I probably need to add a Sound class but it's been low on the priority list so far.

 

Oh! My model class. For various reasons I have two model classes. One of the reasons is that I've posted this code on my website as an example of how you can get started with DX11 or OGL4.5. I have a HandMadeModel class where you give it a vertex and index buffer in order to create the object, largely because this kind of demonstrates the concept of how to handle drawing in game objects without getting into the complexities. So, it's a far more simple example.

 

The other class is really two classes. One is the model loader which right now takes the human readable model file (my own custom file format built from data exported directly from Blender using a custom script). It basically compiles that data and feeds the actual model class. I haven't dug into that code recently (in about a year or so), but I know I have a way of saving the Model class data out to a binary file for fast loading. It basically serializes the model class. Once that data is loaded into the model class, it just writes all the data structures of the class out to disk, optimizing the loading process the next time the model needs to be loaded, bypassing the human readable file which is an order of magnitude slower. These two classes, the model compiler and the model class, are probably some of the most complicated code in the whole works short of the DX COM code itself.

 

But all of this forms a basic engine with the idea that the aforementioned code is basically a library that you call rather than code to be modified.

 

Everything is basically only one level deep and doesn't use inheritance. I've used inheritance pretty sparingly. I've heard that it's better to design things that way and not go more than 2 or 3 levels deep.

 

The intent is to modify the Game class to create games. The Game class obviously has visibility into it's parent but also to pretty much all the other classes in one way or another.

 

I tried to make the OGL version follow the same design as the DX version, but that didn't quite work out. I made several changes to the design when I rewrote it in OGL after DX. OGL lends itself to libraries a lot more than DX. In the DX version I pretty much just used C++, the Windows SDK, and DX. Everything else was pretty much built from scratch. In the OGL version I'm making pretty extensive use of libraries. The startup and initialization is far more simple with GLFW.

 

OGL seems to not be designed for Object Oriented Programming. I've kind of forced it into that paradigm. And that affected things like my choice of which library to use for image files. The one suggested to me would not work apparently because of the small amount of inheritance I have in the program. It seemed to get confused about whether it was dealing with the parent or the child. I switched to a different library and it works fine after spending a couple days trying to get the first one to work.

 

I haven't rewritten the Model classes for the OGL version yet. So far it just has the HandMadeModel class. (And I renamed that class since I can't seem to settle on a good name for it). I think much of the main model classes will be copy and paste code, but some of the drawing code and what not will have to be changed for OGL.

 

The OGL version has a bit more going on with error handling.

 

The DX version has a Skybox class. I'm debating on whether to even include that in the OGL version. There are countless ways to do a skybox (sphere, dome, whatever). The Skybox could be done with either the HandMadeObject class or the main model class, by just making a cube and texturing it inside out. In the engine itself there probably doesn't need to be a class dedicated to that.

 

Then again, I could see making a terrain class. Maybe I just need to make a separate library for those types of things.

 

At some point, I want to make a InputHandler class which would handle keyboard and game pad input. I already have this functionality. But I might want to make a class to obfuscate the details and allow re-mapping of functionality. Right from the start, the XBox 360 controller and the PS4 controller map completely different. DirectX handles the 360 controller natively, but I'm not sure you can get it to recognize any other controller or if you can make other controllers work outside of making them emulate the 360 controller. In OGL I have the functionality through GLFW. In GLFW the two controllers feed data in using the same variables, but they are mapped completely different. So, pulling the trigger on one is equivalent to something like moving the joystick on the other. So, an InputHandler class that maps game functionality according to which controller you have would be nice. Plus, the user may just want to remap the buttons in the game to their preference.

 

I could possibly see having a class that maintains game state and/or handles game events. This is about the level where I'm starting to think such a class is outside of the scope of the engine and getting into making the actual game. By the time I start getting into those questions, I'm probably going to read "Game Programming Patterns" and take the advice there I imagine.

Edited by BBeck

Share this post


Link to post
Share on other sites

Personally, class composition has never failed me yet. In my opinion, as long as you compose your game engine class with large, distinct, and specialized subsystems, you will save yourself a lot of headache in the future. Composition also helps reduce (sometimes even eliminates) coupling. Anybody is free to disagree with me on this, but I wouldn't worry about the size of the game engine class as long as you can justify and argue that all of the subsystems are logically coherent. Also make sure you aren't adding functionality that you aren't going to use; that is the source of class bloating. Also make sure to document, document, document.

 

With respect to your structure, if you have a renderer, I would make that a component of your window class since, to me, graphics apart from a window to contain them wouldn't make sense. I would then make the window class a component of a window manager class that can handle multiple windows (good for split screens, cameras, etc.). The window manager then becomes apart of the game engine.

 

GAME_ENGINE<-WINDOW_MANAGER<-WINDOW<-RENDERER

 

The state manager would be another subsystem of the game engine. Storing, loading, and updating the state is a job for the state manager.

 

GAME_ENGINE<-STATE_MANAGER

 

Handling sound would be a job for the sound manager and that goes into the game engine.

 

GAME_ENGINE<-SOUND_MANAGER

 

With this scheme, each subsystem just does what it does without having to be concerned with the other subsystems. The game engine, then, is really more of a container than anything else; it provides the client with the interfaces to the stuff on the inside.

Edited by nGamer

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this