Polymorphism, Classes, Inheritance, Enumerators etc

Discussion about everything. New games, 3d math, development tips...
Post Reply
dejai
Posts: 522
Joined: Sat Apr 21, 2007 9:00 am

Polymorphism, Classes, Inheritance, Enumerators etc

Post by dejai »

Hello everyone,
as you may well know I am a n00b at C++ and I wanted to sort some stuff out and I thought I may as well figure this out here. How much is to much. How should I restrict my code within functions, should I have a function for everything I can think of or limit it to purpose.

Also in my classes should my constructors deal with the creation of the irrlicht device etc, or should I use the constructor to declare variables etc and save a boot function to declare the device etc.

Should I use a object of my class to run my game, GameManager Game. Well I think this one answers itself. But should I use the object to call each function like
Game.boot();
Game.play();

Or like I do currently should I just use
Game.boot();
and then
boot() when it ends goes straight to the play();

I have heard about base classes and classes steaming of this via inheritance how does this exactly work, I know I may have father, child classes or Human and john. but how can this relate to game programming, for example how can I get this to work with a game manager (or should I even do this?) e.g Class GameManager // Base Class, Class GameManagerAudio.

Should I even use polymorphisms in Game Coding, it seems to be great at confusing people or should I limit it to only really obvious situations like
void calculate (int a, int b);
void calculate (float a, float b);

What is the best way to manage the game loop? What I do at the moment is declare a enumerator in my GameManager called States make a instance of this State GameState and then in my GameLoop, if GameState == MENU then goto the menu function.

or if GameState == MENU_AUDIO the goto menuaudio() and within that function at the end of its purpose i have Gamestate == Menu so the sound plays then goes into the menu.

How does the inheritance work behind the base class principle, and what is dimond inheritance, I know that its when the inheritance links back up in a diamond but is this a problem or a good thing?

Should I use arguments within my functions within a game, and how and why?

Thanks for all the help, I know its a lot of n00b but someone has to beat it out of me, I am trying but answering this may be like running my n00b out onto a highway and hitting him with a mac truck.

Thanks!
Programming Blog: http://www.uberwolf.com
dejai
Posts: 522
Joined: Sat Apr 21, 2007 9:00 am

Post by dejai »

Oh also I am doing a course at AIE on Game programming and reading C++ for dummies and I have STL Programming from the ground up. In other words I am trying.
Programming Blog: http://www.uberwolf.com
FuzzYspo0N
Posts: 914
Joined: Fri Aug 03, 2007 12:43 pm
Location: South Africa
Contact:

Post by FuzzYspo0N »

Im gonna try reply best i can, lol
How should I restrict my code within functions, should I have a function for everything I can think of or limit it to purpose.
I never restirct my code i let it run free :P hah, i think limiting your code to purpose is logical, having a function

Code: Select all

add(a, b) 
{
          return a+b;
}
can be useful, because it has a set purpose.
but having a function like

Code: Select all

doMaths()
{
     int tmp = ga+gb;
     tmp *= 5;
     int tmp1 = gc + gd;
}
thats not the best option, you have to code repetitively to get a result which, with one extra function can make your code a lot easier to create, read and manage.
This doesnt mean seperate EVERY single thing into its own function, for example. in my Project SCR i am using the following functions for the menu :
Its not a seperate class, as it is part of the g_game class already (see, the menu is what spawns the game, in my opinion it is somewhat a parent of whatever the game is running at the time. All aspects of most games spawn from the main menu)

Now, i have a g_game::Init(fullscreen,sound,driver,etc) function
That handles HOW i want the game to initialise. Either way it inistialises ALL the game code initialises there, including the menu. That doesnt mean 100 lines of random code... i Have a function called g_m_loadMenuAssets() which loads the menu, a g_m_resetMenu() to make sure all animations and stuff are set right, and i call g_game::run() which manages the game state as you speicified (case GS_MENU , GS_INGAME, GS_LOADING)

I dont know if the above helps, but im hoping it sheds SOME light on seperation of code from each other.
Also in my classes should my constructors deal with the creation of the irrlicht device etc, or should I use the constructor to declare variables etc and save a boot function to declare the device etc.
This all depends on what you like. I prefer to make my variables public to my game class.. so i can always refer to it as g_game->device g_game->driver

It makes sense because its global, all ALL aspects of your main game code can see it. My GUI class falls under the game code, but atm is external so i say fs_gui::Init(ittlichtdevice device) which gives me acces to every feature of my game engine, with one passed variable. Passing your device around to external classes is how you manage to use the variables within your game code, such as driver (device->getVideoDriver())

If you use it like that , it makes a lot more code so inside my fsgui class i make a IrrlichtDevice* fsgui_globaldevice; and within my gui::init code i just say fsgui_globaldevice = device; which comes from the g_game class.

Also,
its up to where u initialise your device and variables, most logically i would use the function that u already have made for that, g_game::Init(fullscreen,sound,driver,etc)
This means you have all the information you need(you can also read the setttings file, for resolution and other settings) apllying it all to the new device you are creating.
Should I use a object of my class to run my game
this speaks for itself as u say. my main.cpp code only has the following concept :

Code: Select all

#include "game_engine.h"

void main()
{
    g_game* game;

    game->init(); //my init class has a blank init as well (explained next time)
    game->run();
    game->shutdown();
}
init loads all the relevant stufff for the game to begin (ie the menu) and then runs the main loop, checking states for what to render (and i use a function for that too)

I guess, i would more easily exaplin with code. Let me get SCR code tidyed and commented and i will upload it to show you how i wud administrate the game states in a state machine that is simplistic for games, but extendable for most things.
inheritance
I think its a matter of understanding what the point of inheritance is. A simple example as u said is human.
EVERY single human on this planet, has a mass. they also have a weight.

Code: Select all

class human{

public :

        int getMass();
        int getWeight();

private:

   int weight; 
   int mass;

}
now i need a Male class, for the male human, he is a human, so he also has a weight and mass. This means i dont have to go and REcreate all the same functions i can inherit them from my human class.
so,

Code: Select all

class male : human
{
     public:

    private:
}
a blank class? it actually has stuff in it , for example.
male* John;
now i may call John->getWeight() and John->getHeight() because they are human after all.

It makes sense to use inheritance for most things, the trick is figuring out what the base class has that EVERY single element below it will have as well. Thats where polymorphism and overriding functions comes in too.

Example : A male has a height to weight ratio, based on his age. A females height to wieght ratio is different (it uses a different constant). For example

Code: Select all

int human::calculateHeightWeightRatio()
{
     //some fake calculation for a standard object, such as a plank, with a weight and height.
     
     return weight/height;
}

int male::calculateHeightWeightRatio()
{
    //now a male has a different formula to compensate for muscles and body fat, which dont affect the height so its a very specific formula but the base class needs the same function

    return (weight/height) * massindex * 1.2; //all fake stuff
}
Its not polymorphism its just important understanding it.

Polymorphism has some great uses, ESPECIALLY in games... here is a VERY simple use of polymorphism and overloading.

Code: Select all

function loadAssets();  //this function loads assets according to the function u are calling

void loadAssets(guiname,guisize,position); //loads a std GUI layout
void loadAssets(mapname,mapsize,playercount); //loads a multiplayer map for the game
Its a simple and crap example, but your code is a lot more functional then having 50 classes for game asset loading, when u only have one overloaded function it can work for all version of the function.
I dunno if im rambling or helping, i had a spare second. lol
dejai
Posts: 522
Joined: Sat Apr 21, 2007 9:00 am

Post by dejai »

Thanks for all the help, I would love to see that source you were talking about, I am looking for a finished structred game. I might look at the old irrWizard source as well.

um one other quick question,
Public, Private and Protected. I know that Public is available to everything within it and that protected is available to friends of that class but what is the purpose and use of this.

Also in my GameManager.h it looks like this

Code: Select all

// GameManager.h
#ifndef H_GAMEMANAGER
#define H_GAMEMANAGER

#include "Library.h"

// Irrlicht Namespace
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;

// IrrKlang Namespace
using namespace irrklang;

// Game Manager Class
class GameManager: public IEventReceiver
{
      public:
             enum State // The States of the Game
             {
                  INTRO,
                  INTRO_AUDIO,
                  MENU,
                  MENU_AUDIO,
                  MENU_SUPPORT,
                  MENU_CREDITS,
                  CREDITS_AUDIO,
                  GAME_AUDIO,
                  GAME,
                  EXIT
                  
             };
             
             State GameState; // Initialize the Game
             
             
             // Declare Irrlicht Device and Environment
             IrrlichtDevice* device;
             ISceneManager* smgr;
             IGUIEnvironment* gui;
             IVideoDriver* driver;
             ISoundEngine* engine;
             
             // Audio Declarations
             ISoundSource* IntroAudio;
             ISoundSource* MenuAudio;
             ISoundSource* GameAudio;
             ISoundSource* CreditsAudio;
             
             //Button Declaration
             IGUIButton *Play_Button;
             IGUIButton *Support_Button;
             IGUIButton *Options_Button;
             IGUIButton *Credits_Button;
             IGUIButton *Quit_Button;
             IGUIButton *Menu_Button;
             
             // Font Declaration
             IGUIFont* font_gui;
             
             // Texture Declaration
             ITexture* logo_texture;
             ITexture* menu_texture;
             ITexture* credits_header;
             ITexture* menu_header;    
             
      
             // Game Function Declaration
             
             //System Functions
             void boot(void);
             void loader(void);
             void exit(void);
             
             // Loaders
             void audioloader(void);
             void textureloader(void);
             
             // Game Gui Functions
             void logo(void);
             void logoaudio(void);
             void menu(void);
             
             void menusupport(void);
             void menuoptions(void);
             void menucredits(void);
             void menuaudio(void);
             void creditsaudio(void);
             
             //Game Functions
             void game(void);
             void mapspawn(void);
             void movement(void);
             void gameaudio(void);
             void hud(void);
             void ai(void);
             void gameloop(void);
             
      bool OnEvent(const SEvent& event)
      {
      if (event.EventType == EET_GUI_EVENT)
      {
         s32 id = event.GUIEvent.Caller->getID();
         

         switch(event.GUIEvent.EventType)
         {

         case EGET_BUTTON_CLICKED:

            if (id == 101)
            {
            GameState == GAME_AUDIO;
             break;
            }

            if (id == 102)
            {


              break;
            }

            if (id == 103)
            {
                   
                   
              break;
            }
            if (id == 104)
            {
                   GameState = CREDITS_AUDIO;
                  break;
            }
            if (id == 105)
            {
                 device->drop();
                 engine->drop();
                  break;
                   
            }
            if (id == 106)
            {
                   GameState = MENU_AUDIO;
            }

            break;
             default:
            break;
         }
      }

      return false;
   } 
      
      
};

#endif

In my Int Main its a simple as you discussed, Game.boot(); or Game->boot();

Now, what is currently happening is the game goes to boot and it sets the values for all the devices. And then it goes to a loader which loads all the texutres and sounds. Then it goes to a intro screen and then a menu.

The Enumerators are used as IF statments within the gameloop e.g
if (GameState == MENU)
{
menu();
}

But is this wrong to do seeing as the Menu() uses gui->addImage and gui->addButton.

In other words should I have more than one game loop for different things. And should I have 2 devices one for the menu and one for the game?
Thanks
Programming Blog: http://www.uberwolf.com
CuteAlien
Admin
Posts: 9926
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Post by CuteAlien »

dejai wrote: um one other quick question,
Public, Private and Protected. I know that Public is available to everything within it and that protected is available to friends of that class but what is the purpose and use of this.
Actually friends can even access private data ;-)
One purpose is encapsulation. In short you can say - the less access a class has from the outside the easier will it be to use it.
You simply don't have to look anymore at anything protected or private when using the class. Another reason you try to have as little public functions as possible is that by making functions public you sort of tell everyone (including yourself) that this functions are ok to use from everywhere. So as soon as you change one of those it means every place where you used the function needs also to be changed.
Another purpose is access control. For example you see often that all variables are protected and have get/set functions to access them. It's disputed if this is a good thing to do, but the reason is that every access to those variables now goes through a point which you control. So if you make for example your 'GameState' private and use getter/setters you could make sure that you change the menu correspondingly each time the gamestate is changed. You will no longer accidentally change it and forget to update the gui.
For a start I would say use private for everything unless you can't avoid to make something protected/public.
dejai wrote: In other words should I have more than one game loop for different things. And should I have 2 devices one for the menu and one for the game?
Thanks
You should only have one gameloop and also only one device.
You can use update functions if you need more things which run all the time. Like UpdateGui(), UpdateSound(), etc. which are called in your gameloop.

One general hint: Make small classes.
Having one big class GameManger which does everything is a bad idea in the long run. You wouldn't need classes at all in this case.
The most obvious thing to do in your case is to split off the gui and the sound. Just put everything belonging to the gui in one class and everything about sound in another. Then create two objects for those classes in your mainclass. Later on you will probably want to split classes even further. For example you usually have one class for every dialog.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
fireside
Posts: 158
Joined: Thu Dec 01, 2005 10:55 pm

Post by fireside »

This is just my way of doing it, but I start building fences when too many sheep are in the pasture so to speak. If I write similar code more than once, I make a function. If things start getting messy, I make a class to get rid of some of it. I think the inheritance thing is overdone, but you really need it when you put similar objects in the same container.
Your number one concern is not writing a game bigger than you can finish. As you write more games, you'll develop a reusable system.
dejai
Posts: 522
Joined: Sat Apr 21, 2007 9:00 am

Post by dejai »

Ok thanks for all the help, I have been looking at the irrwizard framework, and to Start of I think I will have the following classes:

CGame(Base Class)
CGameGUI
CGameAudio

But Should I make another class for the Game itself, and should I use that extra class for my loop?
so CGame..

Thanks for the help :D I am looking at the irrWizard framework and this is certainly helping me :D
Programming Blog: http://www.uberwolf.com
Morgawr
Posts: 95
Joined: Wed Sep 26, 2007 7:04 pm

Post by Morgawr »

Nice topic... let me have a go at it too :P

I'm programming a game myself, it's my very first game and it's gonna be an rpg (yeah I know, a quite "big" project, but I don't expect to finish it anytime soon anyways) and after a LOT of thinking I came up with this idea:

In my main.cpp my game has the initialization for everything (yeah I know you might disagree, since you all have uber small mains which call game classes, but what's the point in using a totally different class and just have the main with 3 lines of code? let's use it I say! :roll: ) and then inside the main I initialize a fixed number of "scene" classes, all of a different type inherited from the MotherScene class. This MotherScene class is just a pure virtual class with the most basic virtual function every scene needs (like virtual void run(); or virtual void initScene(); or virtual void loadNextScene(); ). Then I have another huge (yes it's huge but that's how it's gonna be) class called MainDatabase class, it keeps the basic informations regarding EVERY scene in the game, so it will keep the coordinates for the character, the number of items in the inventory, but also the last FMV played and the number of enemies killed for example. But most important of all, it keeps track of the current scene playing (using a currentSceneID variable).

Then in my main, as I said, I have one object for every class, then cycle through a switch inside a loop (the Game loop) which checks using the database object to see the scene I am into in that moment, then enters in the appropriated draw loop and handles the appropriated events. When a scene changes (using the loadNextScene(); function) it changes the currentSceneID variable inside MainDatabase class, so the following loop will change too.

I know that is a weird way of doing it (at least in my opinion, after reading your methods) but that's the most versatile thing I could think of all by myself, there are probably better ways of doing it but I already started this way :roll:

what do you think?

Also if I want to add scene types I can just add that in the main and go through a check in the loop, without having to modify huge parts of codes... and for the savegames I can just store the MainDatabase object into a file and then load it, it will resume the game from the part I had saved it :lol: opinions?
MasterGod
Posts: 2061
Joined: Fri May 25, 2007 8:06 pm
Location: Israel
Contact:

Post by MasterGod »

@Morgawr: Having MainDatabase class to save info about every object in the scene is not a good opinion IMO but every object should save information bout itself.
Making a "MainDatabase" class for save game and such could be better but still should be designed smartly..
Image
Dev State: Abandoned (For now..)
Requirements Analysis Doc: ~87%
UML: ~0.5%
Morgawr
Posts: 95
Joined: Wed Sep 26, 2007 7:04 pm

Post by Morgawr »

MasterGod wrote:@Morgawr: Having MainDatabase class to save info about every object in the scene is not a good opinion IMO but every object should save information bout itself.
Making a "MainDatabase" class for save game and such could be better but still should be designed smartly..
Every class has its own data stored in it when I'm using it, it's just that when I need to destory (aka change) every scene to start another scene, I didn't know where to put those important information (like if I open the item menu, then when I exit it I should go back where I was -the town map for example- and that info can't be found in the map scene class because it's been destroyed already so i just take the info from the database and store them into the mapscene class). That way I can just have one object for every scene class, without making multiple object of the same class (like, If i have 5 fmvs, I don't have to make 5 MovieScene objects, I just allocate and play them when I need, all in the same MovieScene object).

Obviously yes, the MainDB class will be structured in the right way, else it'd just be a huge mess :roll:
MasterGod
Posts: 2061
Joined: Fri May 25, 2007 8:06 pm
Location: Israel
Contact:

Post by MasterGod »

Morgawr wrote:
MasterGod wrote:@Morgawr: Having MainDatabase class to save info about every object in the scene is not a good opinion IMO but every object should save information bout itself.
Making a "MainDatabase" class for save game and such could be better but still should be designed smartly..
Every class has its own data stored in it when I'm using it, it's just that when I need to destory (aka change) every scene to start another scene, I didn't know where to put those important information (like if I open the item menu, then when I exit it I should go back where I was -the town map for example- and that info can't be found in the map scene class because it's been destroyed already so i just take the info from the database and store them into the mapscene class). That way I can just have one object for every scene class, without making multiple object of the same class (like, If i have 5 fmvs, I don't have to make 5 MovieScene objects, I just allocate and play them when I need, all in the same MovieScene object).

Obviously yes, the MainDB class will be structured in the right way, else it'd just be a huge mess :roll:
Now it sounds more useable, good thinking :)
Image
Dev State: Abandoned (For now..)
Requirements Analysis Doc: ~87%
UML: ~0.5%
Post Reply