Virtual Functions in a Class

D.V.D

Make a wish
Reaction score
73
Hello, I was looking at virtual functions and I was trying to use them to structure my gaming project to have the option of running multiple engines based on which was chosen upon startup or part way through with the use of a framework that gets overridden by the needed engine code. This would benefit not having to create a new visual studio project for every little graphics stuff I want to test out. The idea goes like this, I have a class that has the OpenGL engine running and it has virtual functions for rendering, or when a mouse is clicked, or when a keyboard event occurs, or any other standard glut functionality.
Code:
class GameFramework {
 
    public:
   
        virtual void OnMouseClick ();
        virtual void OnKeyboard ();
        virtual void OnRender ();
        //...etc
   
    private:
 
};
I have an object of this framework class created in the main.cpp function which executes the game loop and initializes the program. Now I want to have these functions get overwritten by some other game engines, but I don't want to have to specify which one gets overwritten in the code, but upon starting the program. So it would kinda be like a demo window pops up and asks you to choose which game to run out of a list of options, each one potentially overwritting the main frameworks functions but it isn't decided which one does so until I choose one in the demo program.
Code:
class GameFramework {
 
    public:
   
        virtual void OnMouseClick ();
        virtual void OnKeyboard ();
        virtual void OnRender ();
        //...etc
       
        void startup () {
            create window
            float chosen getinput();
            make class options[chosen] override class
        }
       
    private:
       
        std::vector <&GameEngine> options;
       
};
How would I do this because from my understanding, I'd have to do something like this:
Code:
class GameFramework :: Prespecified Game Engine {
 
    public:
   
        virtual void OnMouseClick ();
        virtual void OnKeyboard ();
        virtual void OnRender ();
        virtual void OnStartup ();
        //...etc
       
        void startup () {
            run OnStartup();
        }
       
    private:
       
        std::vector <&GameEngine> options;
       
};
Is there a way of getting around this? Im pretty sure there is, I just couldn't seem to figure it out.
 

camelCase

The Case of the Mysterious Camel.
Reaction score
362
Now I want to have these functions get overwritten by some other game engines, but I don't want to have to specify which one gets overwritten in the code, but upon starting the program.

I don't quite get what you're getting at..
You're going to have to specify which methods are overridden anyway..

That's the whole point of inheritance.
Code:
GameEngine* ge = nullptr;
int i = getInput();
switch (i) {
    case 0:
        ge = new GameEnginePacman();
        break;
    case 1:
        ge = new GameEngineMario();
        break;
    case 2:
        ge = new GameEngineSonic();
        break;
    default:
        //error
        return 0;
}
ge->run();
//run() continues until exit, in which case we exit the main loop
return 0;

If you don't want to override a method, you can choose not to. Just.. Simply don't.
You only HAVE to override methods that you specify as "pure virtual" or "abstract".
Code:
virtual void someMethod () = 0;

If you really want to do it like how I think you want to do it..
Code:
class GameEngine {
    public:
        void setMouseHandler (MouseHandler* handler);
        void setKeyboardHandler (KeyboardHandler* handler);
        void setRenderHandler (RenderHandler* handler);
 
        void run () {
            //Loop
                if (mouseHandler != nullptr) { mouseHandler->execute(); }
                if (keyboardHandler != nullptr) { keyboardHandler->execute(); }
                if (renderHandler != nullptr) { renderHandler->execute(); }
                //Sleep or sth
            //Endloop
        }
};
 

D.V.D

Make a wish
Reaction score
73
Sorry E3 was happening and I went completely off track. A bit off topic but man the way graphics have progressed in some games is outstanding! Especially seeing some of the fottage from ac4 and bf4 and the sony exclusives. Sucks for people like me who one day dream to program an engine like that even if it is impossible at this stage.

From your first example, Im having a bit of trouble understanding but would something like this be correct?

Code:
    struct GameEngine {
        public:
            virtual void OnMouseEvent ();
            virtual void OnKeyboardEvent ();
            virtual void OnRenderEvent ();
       
            void gameloop () {
                OnMouseEvent();
                OnKeyboardEvent();
                OnRenderEvent();
            }
    };
   
    struct Mario :: GameEngine {
        public:
            void OnMouseEvent () {
                ..Do stuff
            }
            void OnKeyboardEvent () {
                ..Do stuff etc.
            }
       
    }
   
    // struct Sonic, struct Pacman, etc.
   
    void main () {
        GameEngine* ge = nullptr; // Btw what is this? Is this just null?
        int i = getInput();
        switch (i) {
            case 0:
                ge = new Mario;
            case 1:
                ge = new Sonic;
            case 2:
                ge = new Pacman;
            default:
                return 0;
        }
        ge.gameloop();
        return 0;
    }

What's important to me is that no matter what game engine is running, it is all abstracted to the GameEngine struct so then I don't have to modify the stuff in the main function. Instead I only have to add the new game to the list if I want to add a new sonic or pacman game for example. Im very sure Im doing it wrong above because from what I understand, it works the other way for virtual functions. Rather than having all virtual structs go into the main struct, its the main struct that gets put into all the other structs that use him. Is there a way to do it the first way specified? (Im sorry its really hard for me to explain it so I'll post an example of the way I think its supposed to be, where as I want to reverse the order):

Code:
    struct GameEngine {
        public:
            virtual void OnMouseEvent ();
            virtual void OnKeyboardEvent ();
            virtual void OnRenderEvent ();
       
            void gameloop () {
                OnMouseEvent();
                OnKeyboardEvent();
                OnRenderEvent();
            }
    };
   
    struct Mario :: GameEngine {
        public:
            void OnMouseEvent () {
                ..Do stuff
            }
            void OnKeyboardEvent () {
                ..Do stuff etc.
            }
       
    }
   
    // struct Sonic, struct Pacman, etc.
   
    void main () {
        int i = getInput();
        switch (i) {
            case 0:
                Mario* ge = new Mario;
            case 1:
                Sonic* ge = new Sonic;
            case 2:
                Pacman* ge = new Pacman;
            default:
                return 0;
        }
        ge.gameloop();
        return 0;
    }
 

s3rius

Linux is only free if your time is worthless.
Reaction score
130
I think what you want to do is:

Code:
//This is your original game framework class
class GameFramework {
    public:
        virtual void OnMouseClick () = 0;
        virtual void OnKeyboard () = 0;
        virtual void OnRender () = 0;
        //...etc
   
        void startup () {
            create window
            float chosen getinput();
            make class options[chosen] override class
        }
   
    private:
        std::vector <&GameEngine> options;
};
 
class PacMan : public GameFramework{
    public:
        //Override functions
        virtual void OnMouseClick (){
            //Pacman doesn't use mouse, so nothing here
        }
        virtual void OnKeyboard (){
            if(key pressed was Down Arrow)
                pac.moveDownOneTile();
            if(key pressed was Up Arrow)
                ...
        }
        virtual void OnRender (){
            //render environment
            //render pac man
        }
     
    private:
        PacMan pac;
}
 
class SomeShooter : public GameFramework{
    public:
        //Override functions
        virtual void OnMouseClick (){
            if(mouse is over an enemy)
                //kill enemy
        }
        virtual void OnKeyboard (){
            //walking etc ..
        }
        virtual void OnRender (){
            //render environment
            //render enemies
            //render player
        }
     
    private:
        Player player;
        std::vector<Enemies> ..
        ..
}
 
//main function
void main(){
    GameFramework* game = new SomeShooter();
 
    while(true){
        if(keyboard was pressed) game->OnKeyboard();
        if(mouse was clicked) game->OnMouse();
        game->OnRender();
    }
}

But in the end you'll end up writing a ton of code again anyway. A comprehensive framework is much more sophisticated and much larger than that.
 

D.V.D

Make a wish
Reaction score
73
That seems to be what Im trying to do! Thanks Ill try it out. I understand its gotta be way more sophisticated and what not, but this is a start. Plus now I don't have to make a new project for every little demo I want to test out. Anyway's what would a comprehensive framework for games really need? You have an class for context, game and gameengine. Then if you want you could create a class for a standard forward and deferred render's that are part of game engine. Then you could include different techniques for each part of the render (lighting, reflection, depth pass, etc.). This helps mix stuff up and in theory, you can run a certain game and its assets with different techniques for lets say shadow mapping with the change of a constant or something like that. I have a long way to go before any of this stuff becomes the reality I want it to be, but if Im going to start, I thought having the framework finished first would help a lot in not having to redo code later on.
 

camelCase

The Case of the Mysterious Camel.
Reaction score
362
[ljass]nullptr[/ljass] is the type-safe version of the NULL macro.
Code:
#define NULL 0
class Class {};
 
int someMethod (int i);
int someMathod (Class* c);
 
int main () {
    Class* c;
    //The following are the same
    c = 0;
    c = NULL;
    c = nullptr;
 
    //The following shows the difference
    int i;
    i = 0; //Valid
    i = NULL; //Also valid
    i = nullptr; //Error
 
    someMethod(0); //someMethod(int)
    someMethod(NULL); //someMethod(int)
    someMethod(nullptr); //someMethod(Class*)
    return 0;
}
 

s3rius

Linux is only free if your time is worthless.
Reaction score
130
I thought having the framework finished first would help a lot in not having to redo code later on.

It won't :D
I started working on my own engine, GameSerf, like two years ago. Everytime I started a new project with this engine, I noticed that something was bad/missing. So I've rewritten everything several times. Nothing is as it was when I started.
After a while you get a basic grasp of what you actually need your engine to be able to, and how to implement it. I think that's best done via trying it out.

If you like to indulge in the topic, I have a nice resource.
Here's an excellent thesis about a OpenGL-based rendering engine. The first few pages are in German, but after that it's English.
Of course this is far beyond what you need for a small game engine, but in principle it's the same. And it gives nice insight into what a fully-fledged engine would look like if you were to focus on flexibility.
 

Accname

2D-Graphics enthusiast
Reaction score
1,462
I've given up on flexibility.
I tried to make my engine as flexible as possible but it took so damn much time i would have never finished my actual project.
Its sad but true.
 

D.V.D

Make a wish
Reaction score
73
It won't :D
I started working on my own engine, GameSerf, like two years ago. Everytime I started a new project with this engine, I noticed that something was bad/missing. So I've rewritten everything several times. Nothing is as it was when I started.
After a while you get a basic grasp of what you actually need your engine to be able to, and how to implement it. I think that's best done via trying it out.

If you like to indulge in the topic, I have a nice resource.
Here's an excellent thesis about a OpenGL-based rendering engine. The first few pages are in German, but after that it's English.
Of course this is far beyond what you need for a small game engine, but in principle it's the same. And it gives nice insight into what a fully-fledged engine would look like if you were to focus on flexibility.

Im looking through it now, complicated stuff :p but what I meant by a framework was never the complicated stuff they have here, but just something that ties in all the engines so I don't have to rewrite the main.cpp function to create the specified engine/game. It just seemed like an easier alternative to having new projects for each new technique/demo/tutorial I wanted to try out. Still, Ill give your pdf a read, maybe not all of it just because how long it is but to get an idea of what they're doing. If anything I might try implementing what they're doing this summer :D

I've given up on flexibility.
I tried to make my engine as flexible as possible but it took so damn much time i would have never finished my actual project.
Its sad but true.

Yeah, flexibility seems to be one of those extremely time consuming processes where having multiple people working on an engine starts to become extremely handy. We all want to program our own crysis graphics haha :p
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Staff online

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top