Thread: So now...

  1. #16
    Call me AirBronto
    Join Date
    Sep 2004
    Location
    Indianapolis, Indiana
    Posts
    195
    Since every one is on the topic of inheritence and its use tell me this. You are all saying that multi level inheritence is very bad, which i agree with, but what about having an object inheriting from a bunch of singular classes.
    BobMcGee123 said:
    This isn't to say, however, that I haven't had a single object derive from multiple other objects.
    I thought multiple inheritence in any case was a bad idea for games. I know that inheriting from a multi layer object would be worse but isent it still bad to ues multiple inheritence?
    Last edited by loopshot; 12-14-2005 at 09:19 PM.

  2. #17

    Join Date
    May 2005
    Posts
    1,042
    That isn't multi-level/layer inheritance.

    It's only bad because it isn't as useful, in my experience, as other methods. Do whatever you want.
    I'm not immature, I'm refined in the opposite direction.

  3. #18
    ---
    Join Date
    May 2004
    Posts
    1,379
    Yeah, uses for multiple inheritance is rare and if it is used it just adds complexity to the design IMO. That's why Java doesn't allow it.

  4. #19
    Absent Minded Programmer
    Join Date
    May 2005
    Posts
    968
    Finding faults in your language is worrysome...

    It's like finding out that the sheet metal you're using for your car has holes in it - no good!
    Sometimes I forget what I am doing when I enter a room, actually, quite often.

  5. #20
    Call me AirBronto
    Join Date
    Sep 2004
    Location
    Indianapolis, Indiana
    Posts
    195
    These are not necessarily bad, just not very good for games. People have found very good ways to use the virtual aspect of C++ and multiple inheritance out side the realm of games. In addition, I still don’t say that using pure virtual functions is necessary bad for games, remember that article about modular game programming. Every DirectX function is virtual, so it’s not slow at all when used correctly. Don’t you remember the discussion of that article Bubba?

  6. #21
    Deprecated Dae's Avatar
    Join Date
    Oct 2004
    Location
    Canada
    Posts
    1,034
    I have a case where I think virtual functions are required. I'm a newbie so I can't seem to find a way to make it work otherwise. Lets say you have a game that allows you to switch (in options) the graphics library from Direct3D to OpenGL and visa versa. Now you'd like to keep the scripting the same for either case whether or not its D3D or OGL. Lets take a Vector class for example, I dont care if its correct, and its not the way I'd do it, its just for example.

    Code:
    class IObject
    {
    private:
    	static CVector* m_Center; //would be the abstract class
    
    public:
    	IObject() : m_Center(new D3DVector) {} //initially set to D3D
    	static CVector* GetCoords() { return m_Center; }
    
    };
    
    class D3DVector
    {
    private:
    	d3dVector m_xCoord;
    	d3dVector m_yCoord;
    	d3dVector m_zCoord;
    
    public:
    	void SetX(d3dVector p_x) { m_xCoord = p_x; }
    };
    
    class OGLVector
    {
    private:
    	glVector m_xCoord;
    	glVector m_yCoord;
    	glVector m_zCoord;
    
    public:
    	void SetX(glVector p_x) { m_xCoord = p_x; }
    };
    
    int main()
    {
    	CVector* Vector = IObject::GetCoords(); //returns D3DVector atm
    
    	Vector.SetX(new d3dVector);
    	Vector.SetX();
    	Vector.SetAll(new d3dVector, new d3dVector, new d3dVector);
    	Vector.GetX();
    }
    I don't see any way of allowing the call to IObject::GetCoords() result in either D3D or OGL, based on whichever is set at the moment, without of course making a CVector abstract class (virtual).

    I also have another issue where if I used a vector class like this, then when switching from D3D to OGL or visa versa, every coord would be set to 0 or incorrect - so I would have to do some operations to convert from D3D to OGL or vv. That or I could check everywhere to attempt using a union (which I'm hoping would work, but I know know). Hell I don't know maybe I could just store floats and set d3dVector to the corresponding float and return that.

    Also, between using an extra if statement or function call, or virtual function, which would be the best choice for speed?
    Warning: Have doubt in anything I post.

    GCC 4.5, Boost 1.40, Code::Blocks 8.02, Ubuntu 9.10 010001000110000101100101

  7. #22
    Absent Minded Programmer
    Join Date
    May 2005
    Posts
    968
    I found uses for virtual constructors, but nothing more...

    If you want a class factory design you *need* virtual constructors, I'll show you some code...

    Code:
    class Control
    {
    };
    
    class PushControl : public Control
    {
    };
    
    class Factory
    {
     public:
       // Returns Factory subclass based on classKey.  Each
       // subclass has its own getControl() implementation.
       // This will be implemented after the subclasses have
       // been declared.
       static Factory * getFactory(int classKey);
    
       virtual Control * getControl() const = 0;
    };
    
    class ControlFactory : public Factory 
    {
     public:
       virtual Control * getControl() const
       {
         return new PushControl();
       }
    };
    
    Factory * Factory::getFactory(int classKey)
    {
       // Insert conditional logic here.  Sample:
       switch(classKey)
       {
         default:
           return new ControlFactory();
       }
    }
    I think this is a singleton class factory design...

    One Factory class handles all class factories, you can have a scene_object factory, or a GUI factory, etc etc...
    Last edited by Shamino; 12-15-2005 at 08:44 AM.
    Sometimes I forget what I am doing when I enter a room, actually, quite often.

  8. #23
    Deprecated Dae's Avatar
    Join Date
    Oct 2004
    Location
    Canada
    Posts
    1,034
    It looks like that link would work, a way to get around requiring an abstract class for the objects. Thats not a Singleton though, you would have to store an instance of itself and new if the instance is null, otherwise just return the instance in order to do that.

    ATM I'm using a Template Method (concrete class) for each "System", which DX (DirectX) libs, or OL (Other Library - SDL/OpenGL), etc. derive from that. Which means I can switch between say DirectInput and SDL without losing data. Then I'm using a Singleton (CSystem class) as a Singleton Factory of Template Method classes (concrete classes).

    Code:
    class CSystem
    {
    private:
        enum m_eLibChoice {NONE, DX, OL};
        static m_eLibChoice m_eRenderLib;
        static m_eLibChoice m_eSoundLib;
        static m_eLibChoice m_eInputLib;
    
        //static CTimerSystem* m_CTimer;
        static ISoundSystem* m_Sound;
        static IRenderSystem* m_Render;
        static IInputSystem* m_Input;
        static LLObjectSystem* m_Object;
        static CSystem* m_Instance;
    
    protected:
        CSystem(); // only allow instantiation from within the this or derived classes
    
    public:
        void SwitchRenderSystem();
        void ReleaseRenderSystem();
        static IRenderSystem* Render();
    
        void SwitchSoundSystem();
        void ReleaseSoundSystem();
        static ISoundSystem* Sound();
    
        void SwitchInputSystem();
        void ReleaseInputSystem();
        static IInputSystem* Input();
    
        //static CTimerSystem* Timer();
    
        void ReleaseObjectSystem();
        static LLObjectSystem* Object();
    
        static CSystem* Instance();
    };
    
    ////////////////////////////////////////////////////////////////////////////////
    
    CSystem::CSystem() {}
    
    CSystem* CSystem::m_Instance = 0;
    IRenderSystem* CSystem::m_Render = 0;
    ISoundSystem* CSystem::m_Sound = 0;
    IInputSystem* CSystem::m_Input = 0;
    LLObjectSystem* CSystem::m_Object = 0;
    CSystem::m_eLibChoice CSystem::m_eRenderLib = NONE;
    CSystem::m_eLibChoice CSystem::m_eSoundLib = NONE;
    CSystem::m_eLibChoice CSystem::m_eInputLib = NONE;
    
    ///////////////////////////////// MAIN /////////////////////////////////////////
    
    CSystem* CSystem::Instance()
    {
        if(m_Instance == 0)
            m_Instance = new CSystem();
    
        return m_Instance;
    }
    
    //////////////////////////////// RENDER ////////////////////////////////////////
    
    IRenderSystem* CSystem::Render()
    {
        if(!m_Render)
            if(m_eRenderLib == DX)
                m_Render = new DX::CRenderSystem();
            else if(m_eRenderLib == OL)
                m_Render = new OL::CRenderSystem();
    
        return m_Render;
    }
    
    void CSystem::SwitchRenderSystem()
    {
        if(m_eRenderLib == DX) {
            m_Render = new OL::CRenderSystem();
            m_eRenderLib = OL;
        } else {
            m_Render = new DX::CRenderSystem();
            m_eRenderLib = DX;
        }
    
        //call updates required
    }
    
    void CSystem::ReleaseRenderSystem()
    {
        if(m_Render)
            delete m_Render;
        m_Render = 0;
    
        m_eRenderLib = NONE;
    }
    
    //ETC
    
    namespace OL
    {
    
    class CRenderSystem : public IRenderSystem
    {
    private:
        unsigned int m_uiWindowWidth;
        unsigned int m_uiWindowHeight;
    
        float m_fAngle;
    
    protected:
    
    public:
        CRenderSystem(void) {}
        virtual ~CRenderSystem(void) {}
    
        bool Init(void);
        bool Shutdown(void);
        void SetupProjection(unsigned int, unsigned int);
        void Prepare(float);
        void Draw(void);
    
        void DrawObject(NObject*);
    };
    I think I need to revamp it though. I'll read up some more on design patterns first. I think Metaclasses might be what I want.
    Warning: Have doubt in anything I post.

    GCC 4.5, Boost 1.40, Code::Blocks 8.02, Ubuntu 9.10 010001000110000101100101

  9. #24
    Absent Minded Programmer
    Join Date
    May 2005
    Posts
    968
    Here is my Object building manager (its not accurately named as of yet)

    NOTE: Largely Incomplete
    Code:
    template <typename T>
    struct Build{
        //
        // Callback functor for buttons to make buildings
        //
        void operator()(int PlayerNum, int x, int y, int z)
    	{
            //
            // Creates building type T at x,y under ownership of player
            owner.buildings.push_back(building);
            game.objects.push_back(building);
    
            Object  *Building= NULL;
    
    		switch (PlayerNum)
    		{
    		case GAME_MASTER:
                                     // insert conditional operators here
    			Building = new T(PlayerNum, x, y, z);
    			break;
    		case PLAYER_ONE:
    			break;
    		    Building = new T(PlayerNum, x, y, z);
    		case PLAYER_TWO:
    			break;
    	           Building = new T(PlayerNum, x, y, z);
    		case PLAYER_THREE:
    			break;
    	           Building = new T(PlayerNum, x, y, z);
    		case PLAYER_FOUR:
    			break;
    	           Building = new T(PlayerNum, x, y, z);
    		case PLAYER_FIVE:
    			break;
    		case PLAYER_SIX:
    			break;
    	           Building = new T(PlayerNum, x, y, z);
    		case PLAYER_SEVEN:
    			break;
    	           Building = new T(PlayerNum, x, y, z);
    		case PLAYER_EIGHT:
    			break;
    	           Building = new T(PlayerNum, x, y, z);
    		case WORLD:
    			break;
    	           Building = new T(PlayerNum, x, y, z);
    		}
    
                //
                // these next two lines are better off in the 
                //  T constructor
                //
     
        }
    };
    Ultimately I would call it like this

    Code:
    barracks_button.onClick = new Build<barracks>();
    I think this is about as OO as it gets (though I could probably have a player template, I think that is a point where the OO would get redundant), at least when it comes to adding objects to your renderer..

    when we call the new Build<barracks>, we grab the model data held in barracks and send it to a vector to be managed and rendered...

    We will also send it to another vector that will handle only collision detection...
    Last edited by Shamino; 12-15-2005 at 01:39 PM.
    Sometimes I forget what I am doing when I enter a room, actually, quite often.

  10. #25
    Deprecated Dae's Avatar
    Join Date
    Oct 2004
    Location
    Canada
    Posts
    1,034
    Yeah thats incomplete, and is it even correct?

    Almost all of your cases are empty because I think you meant to have that stuff in the case, but have the break on the wrong line.

    You're passing an integer PlayerNum, and how does that compare to a constant enum choice?

    What are you pushing at the beginning of the operator() (that doesn't have a capital B)?

    EDIT: I see the idea.. but I don't think it would work and I'd at least get the concept to work for real (or else you don't know if its possible) before leaving it as even pseudo code.
    Last edited by Dae; 12-15-2005 at 02:09 PM.
    Warning: Have doubt in anything I post.

    GCC 4.5, Boost 1.40, Code::Blocks 8.02, Ubuntu 9.10 010001000110000101100101

  11. #26
    Absent Minded Programmer
    Join Date
    May 2005
    Posts
    968
    lol i whipped that code up just now, didn't realize where I put the breaks..
    Sometimes I forget what I am doing when I enter a room, actually, quite often.

  12. #27
    Absent Minded Programmer
    Join Date
    May 2005
    Posts
    968
    It's basically pseudocode atm, let me repost it.
    Not 100% if it works or not, it's based upon something someone gave me at GameDev...

    I know that the pushback calls in this thing are all goofy, i don't even have an owner.buildings vector, but i will figure it all out in time...
    Code:
    template <typename T>
    struct Build{
        //
        // Callback functor for buttons to make buildings
        //
        void operator()(Player::PLAYER_NUMBER, int x, int y, int z)
    	{
            //
            // Creates building type T at x,y under ownership of player
    
    
            Object  *Building= NULL;
    
    		switch (Player::PLAYER_NUMBER)
    		{
    		case GAME_MASTER:
    				Building = new T(Player::PLAYER_NUMBER, x, y, z);
    			break;
    		case PLAYER_ONE:
    				Building = new T(Player::PLAYER_NUMBER, x, y, z);
    			break;
    		case PLAYER_TWO:
    
    	           Building = new T(Player::PLAYER_NUMBER, x, y, z);
    			break;
    		case PLAYER_THREE:
    
    	           Building = new T(Player::PLAYER_NUMBER, x, y, z);
    			break;
    		case PLAYER_FOUR:
    			break;
    	           Building = new T(Player::PLAYER_NUMBER, x, y, z);
    
    		case PLAYER_FIVE:
    	           Building = new T(Player::PLAYER_NUMBER, x, y, z);
    			break;
    		case PLAYER_SIX:
    
    	           Building = new T(Player::PLAYER_NUMBER, x, y, z);
    			break;
    		case PLAYER_SEVEN:
    
    	           Building = new T(Player::PLAYER_NUMBER, x, y, z);
    			break;
    		case PLAYER_EIGHT:
    
    	           Building = new T(Player::PLAYER_NUMBER, x, y, z);
    			break;
    		case WORLD:
    		
    	           Building = new T(Player::PLAYER_NUMBER, x, y, z);
    			break;
    		}
    
                //
                // these next two lines are better off in the 
                //  T constructor
                //
             owner.buildings.push_back(building);
            game.objects.push_back(building);
        }
    };
    If you want to see the whole thing that is currently up to date with an explaination go here:

    http://www.gamedev.net/community/for...opic_id=364152

    Reply Number 8
    Last edited by Shamino; 12-15-2005 at 02:41 PM.
    Sometimes I forget what I am doing when I enter a room, actually, quite often.

  13. #28
    Deprecated Dae's Avatar
    Join Date
    Oct 2004
    Location
    Canada
    Posts
    1,034
    Oh, I see. Yeah what he posted is nice. It doesn't solve the exact problem of losing data though, as you can see in your code you are assigning T to Object (and if T is a subclass you would be losing data, assuming Object isn't concrete [which if it was this entire thing wouldn't be necessary]).

    Also logically storing T in an Object* is pointless if you're only adding buildings (owner.buildings.push_back(building);). You could just make it Building* aBuilding; and then push that back to objects/buildings. Basicly it doesn't solve anything.

    Cool, in one of your posts (http://www.gamedev.net/reference/art...rticle2097.asp) that had a template method with function pointers - that looked useful (maybe not for the Object structure, but for something).

    What I meant in my last post is you have it defined Object *Building= NULL;, but you are calling owner.buildings.push_back(building);, without a capital b in building. Also FOUR's break is off.

    I'm going to start reading Design Patterns again, and see if GD can help me figure out my problem with Object and deriving from it.
    Warning: Have doubt in anything I post.

    GCC 4.5, Boost 1.40, Code::Blocks 8.02, Ubuntu 9.10 010001000110000101100101

  14. #29
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    This:
    Code:
    void operator()(Player::PLAYER_NUMBER, int x, int y, int z)
    	{
            //
            // Creates building type T at x,y under ownership of player
    
    
            Object  *Building= NULL;
    
    		switch (Player::PLAYER_NUMBER)
    		{
    		case GAME_MASTER:
    				Building = new T(Player::PLAYER_NUMBER, x, y, z);
    			break;
    		case PLAYER_ONE:
    				Building = new T(Player::PLAYER_NUMBER, x, y, z);
    			break;
    		case PLAYER_TWO:
    
    	           Building = new T(Player::PLAYER_NUMBER, x, y, z);
    			break;
    		case PLAYER_THREE:
    
    	           Building = new T(Player::PLAYER_NUMBER, x, y, z);
    			break;
    		case PLAYER_FOUR:
    			break;
    	           Building = new T(Player::PLAYER_NUMBER, x, y, z);
    
    		case PLAYER_FIVE:
    	           Building = new T(Player::PLAYER_NUMBER, x, y, z);
    			break;
    		case PLAYER_SIX:
    
    	           Building = new T(Player::PLAYER_NUMBER, x, y, z);
    			break;
    		case PLAYER_SEVEN:
    
    	           Building = new T(Player::PLAYER_NUMBER, x, y, z);
    			break;
    		case PLAYER_EIGHT:
    
    	           Building = new T(Player::PLAYER_NUMBER, x, y, z);
    			break;
    		case WORLD:
    		
    	           Building = new T(Player::PLAYER_NUMBER, x, y, z);
    			break;
    		}
    
                //
                // these next two lines are better off in the 
                //  T constructor
                //
             owner.buildings.push_back(building);
            game.objects.push_back(building
    ...
    ...
    is a disaster.

  15. #30
    Absent Minded Programmer
    Join Date
    May 2005
    Posts
    968
    I know I know Bubba, I've been suggested like 5 different possible ways of solving my problem and i keep trying to use them and failing miserably, I think i just need to take two steps back...
    Sometimes I forget what I am doing when I enter a room, actually, quite often.

Popular pages Recent additions subscribe to a feed