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,463
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.
  • Ghan Ghan:
    Howdy
  • Ghan Ghan:
    Still lurking
    +3
  • The Helper The Helper:
    I am great and it is fantastic to see you my friend!
    +1
  • The Helper The Helper:
    If you are new to the site please check out the Recipe and Food Forum https://www.thehelper.net/forums/recipes-and-food.220/
  • Monovertex Monovertex:
    How come you're so into recipes lately? Never saw this much interest in this topic in the old days of TH.net
  • Monovertex Monovertex:
    Hmm, how do I change my signature?
  • tom_mai78101 tom_mai78101:
    Signatures can be edit in your account profile. As for the old stuffs, I'm thinking it's because Blizzard is now under Microsoft, and because of Microsoft Xbox going the way it is, it's dreadful.
  • The Helper The Helper:
    I am not big on the recipes I am just promoting them - I use the site as a practice place promoting stuff
    +2
  • Monovertex Monovertex:
    @tom_mai78101 I must be blind. If I go on my profile I don't see any area to edit the signature; If I go to account details (settings) I don't see any signature area either.
  • The Helper The Helper:
    You can get there if you click the bell icon (alerts) and choose preferences from the bottom, signature will be in the menu on the left there https://www.thehelper.net/account/preferences
  • The Helper The Helper:
    I think I need to split the Sci/Tech news forum into 2 one for Science and one for Tech but I am hating all the moving of posts I would have to do
  • The Helper The Helper:
    What is up Old Mountain Shadow?
  • The Helper The Helper:
    Happy Thursday!
    +1
  • Varine Varine:
    Crazy how much 3d printing has come in the last few years. Sad that it's not as easily modifiable though
  • Varine Varine:
    I bought an Ender 3 during the pandemic and tinkered with it all the time. Just bought a Sovol, not as easy. I'm trying to make it use a different nozzle because I have a fuck ton of Volcanos, and they use what is basically a modified volcano that is just a smidge longer, and almost every part on this thing needs to be redone to make it work
  • Varine Varine:
    Luckily I have a 3d printer for that, I guess. But it's ridiculous. The regular volcanos are 21mm, these Sovol versions are about 23.5mm
  • Varine Varine:
    So, 2.5mm longer. But the thing that measures the bed is about 1.5mm above the nozzle, so if I swap it with a volcano then I'm 1mm behind it. So cool, new bracket to swap that, but THEN the fan shroud to direct air at the part is ALSO going to be .5mm to low, and so I need to redo that, but by doing that it is a little bit off where it should be blowing and it's throwing it at the heating block instead of the part, and fuck man
  • Varine Varine:
    I didn't realize they designed this entire thing to NOT be modded. I would have just got a fucking Bambu if I knew that, the whole point was I could fuck with this. And no one else makes shit for Sovol so I have to go through them, and they have... interesting pricing models. So I have a new extruder altogether that I'm taking apart and going to just design a whole new one to use my nozzles. Dumb design.
  • Varine Varine:
    Can't just buy a new heatblock, you need to get a whole hotend - so block, heater cartridge, thermistor, heatbreak, and nozzle. And they put this fucking paste in there so I can't take the thermistor or cartridge out with any ease, that's 30 dollars. Or you can get the whole extrudor with the direct driver AND that heatblock for like 50, but you still can't get any of it to come apart
  • Varine Varine:
    Partsbuilt has individual parts I found but they're expensive. I think I can get bits swapped around and make this work with generic shit though
  • Ghan Ghan:
    Heard Houston got hit pretty bad by storms last night. Hope all is well with TH.
  • The Helper The Helper:
    Power back on finally - all is good here no damage
    +2
  • V-SNES V-SNES:
    Happy Friday!
    +1

      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