Pointer not working?!

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
pszlachetka
Posts: 23
Joined: Mon Aug 30, 2004 12:30 am

Pointer not working?!

Post by pszlachetka »

I'm trying to call a function in the CGame class to change the game state, and is says the function is undeclared. I changed the function being called just to do a test, and it still says it's undeclared. The pointer is clearly of the CGame type. Here's the exact error message:

C:\Documents and Settings\Owner\Desktop\POLISH PONG\CTitleScreen.cpp In member function `virtual bool CTitleScreen::OnEvent(irr::SEvent)':
89 C:\Documents and Settings\Owner\Desktop\POLISH PONG\CTitleScreen.cpp `setGameState' undeclared (first use this function)
(Each undeclared identifier is reported only once for each function it appears in.)

Thanks for any help I can get!

CGame.h

Code: Select all

#ifndef CGame_H_
#define CGame_H_

//Include Irrlicht header file and use its namespaces
#include <irrlicht.h>

using namespace irr;

using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;

//Include title screen header, which includes the CGameState header.

#include "CTitleScreen.h"

#include "CTwoPlayerGame.h"

//forward declaration of the event receiver, so the CGame class knows what
//that the event receiver class exists
class CMyEventRec;

class CGame
{
    public:
        
    CGame();
    ~CGame();//drops the irrlicht device
    
    /*This will initialize both the CGame class, and the event receiver class.
    It will dynamically create a new event receiver class to the pointer in the private
    section of the CGame class. e.g. CMyEventRec* myEventRec; a "this" pointer will be
    passed into its constructor. It will then initialize all the usual Irrlicht pointers*/
    void CGame_Init();
    
    //Will call on the current gamestate's Render function
    void Render();
    
    //Will call on the current gamestate's Update function
    bool Update();
    
    //usual Irrlicht engine pointers
    IrrlichtDevice*    device;
    ISceneManager*     sceneMgr;
    IVideoDriver*      driver;
    IGUIEnvironment*   guiEnv;
    
    //The pointer to the current gamestate
    CGameState*         currentGameState;
    
    //The pointer which the event receiver class is allocated to
    CMyEventRec*        eventRec;
    
    void setGameState( int y );
    
    bool OnEvent( SEvent event );
    
    /////////////////////////////////////////////////
    /////////////GAME SPECIFIC FUNCTIONS/////////////
    /////////////////////////////////////////////////
    
    //Nothing as of yet.
     
};
////////////////////////
//EVENT RECEIVER CLASS//
////////////////////////

class CMyEventRec : public IEventReceiver
{   
    //Pointer to the CGame class
    CGame*        ptrCGame;
    
    //Declare the CGame class a friend of this class
    //friend class CGame;
    public:
        
    //Constructor takes a pointer to the CGame class as a parameter, and assigns
    //it to CGame* ptrCGame;
    CMyEventRec( CGame* gam ){ ptrCGame = gam; }
    
    //Destructor does nothing so far
    ~CMyEventRec();
    
    //The virtual OnEvent function
    virtual bool OnEvent( SEvent event );
    
    //Engine pointers inside the event receiver class
    IrrlichtDevice*    ptrDevice;
    ISceneManager*     ptrMgr;
    IVideoDriver*      ptrDriver;
    IGUIEnvironment*   ptrGUI;  
    
    
    ///////////////////////////////////////////////////////
    //////////////////GAME SPECIFIC STUFF//////////////////
    ///////////////////////////////////////////////////////

    //Nothing as of yet
    
    private:
    
}; 
    
#endif
CGame.cpp

Code: Select all

#include "CGame.h"

//Does nothing.
CGame::CGame()
{
}

//The destructor drops the irrlicht device
CGame::~CGame()
{
    device->drop();
}

//Initialization function
void CGame::CGame_Init()
{
    //allocate a new event receiver class
    eventRec = new CMyEventRec( this ); 
    
    //Create device
    device = createDevice( EDT_OPENGL, 
                           dimension2d<s32>( 640, 480 ), 
                           32, 
                           false, 
                           false, 
                           0 );
                           
    device->setEventReceiver( eventRec );
                           
    //Set a window caption
    device->setWindowCaption(L"POLISH PONG - Peter Szlachetka");
    
    //Initialize the engine pointers                                             
    sceneMgr = device->getSceneManager();
    driver = device->getVideoDriver();
    guiEnv = device->getGUIEnvironment();
    
    //Create the title screen upon execution
    currentGameState = new CTitleScreen( device, sceneMgr, driver, guiEnv, this );
}

//Main render function. It calls on the current game state's render fnction
void CGame::Render()
{
    currentGameState->Render();
}

//Main update function. It calls on the current game state's update function
bool CGame::Update()
{
    currentGameState->Update();
}

//CGame OnEvent function calls on the current game state's OnEvent function
bool CGame::OnEvent( SEvent event )
{
    if( currentGameState )
    {
        currentGameState->OnEvent( event );
    }    
}

void CGame::setGameState( int y )
{
    switch( y )
    {
        case 3:
            {
                currentGameState = 0;
                currentGameState = new CTwoPlayerGame( device, sceneMgr, driver, guiEnv, this );
                break;
            }
    }
}         

//////CMyEventRec class functions///////

//Main event function, calls the CGame's OnEvent function
bool CMyEventRec::OnEvent( SEvent event )
{
    return ptrCGame->OnEvent( event );
}

/////////////////////////////////////////////////////////////
////////////////////GAME SPECIFIC STUFF//////////////////////
/////////////////////////////////////////////////////////////

//nothing as of yet
CTitleScreen inherites from the base CGameState class.
CGameState.h

Code: Select all

#ifndef CGameState_H_
#define CGameState_H_

#include <irrlicht.h>

using namespace irr;

using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;

class CGame;

//This class serves as the base class for the gamestates. They inherit the functions and pointers
//from this class, and redefine the functions to their particular needs.

class CGameState
{
    public:
    
    //Constructor takes in the engine pointers, and sets its own localized engine pointers    
    CGameState( IrrlichtDevice* dev, ISceneManager* mgr, IVideoDriver* driv, IGUIEnvironment* guienv, CGame* gam );
    virtual ~CGameState() {};
    
    //Virtual update function, the gamestates inherit this, and have their own version
    virtual bool Update() = 0;
    
    //Virtual render function, the gamestates inherit this, and have their own version
    virtual void Render() = 0;
    
    //Virtual OnEvent function, the gamestates inherit this, and have their own version
    virtual bool OnEvent( SEvent event ) = 0;
   
    protected:
    
    CGame* GS_CGame;
    
    //INHERITED engine pointers        
    IrrlichtDevice*    GS_device;
    ISceneManager*     GS_sceneMgr;
    IVideoDriver*      GS_driver;
    IGUIEnvironment*   GS_guiEnv;
    
    enum GAMESTATE{ TITLESCREEN = 1, ONEPLAYER, TWOPLAYER, CREDITS };
    
    GAMESTATE GameState;
        
};

#endif
GS_CGame pointer is initialized in the constructor.
CGameState.cpp

Code: Select all

#include "CGameState.h"

//Sets the engine pointers. That's it.
CGameState::CGameState( IrrlichtDevice* dev, ISceneManager* mgr, IVideoDriver* driv, IGUIEnvironment* guienv, CGame* gam )
{
    GS_CGame = gam;
    
    GS_device = dev;
    
    GS_sceneMgr = mgr;
    
    GS_driver = driv;
    
    GS_guiEnv = guienv;    
}
CTitleScreen inherites GS_CGame pointer.
CTitleScreen.h

Code: Select all

#ifndef CTitleScreen_H_
#define CTitleScreen_H_


//Include the CGameState class, since CTitleScreen is being derived from it
#include "CGameState.h"

//This class will control the title screen. It will contain all the resources needed for
//the title screen.

//It inherites the engine pointers from the CGameState class, as well as the Update,
//Render, and OnEvent functions, and redefines them to suit its own needs.
class CTitleScreen : public CGameState
{
    public:
    
    //Constuctor sets engine pointers in the ->CGameState<- class
    CTitleScreen( IrrlichtDevice* dev, ISceneManager* mgr, IVideoDriver* driv, IGUIEnvironment* guienv, CGame* gam );
    
    //Will clean up after title screen is destroyed.
    ~CTitleScreen();
    
    //Will return true if the device is running, and the driver points to something
    bool Update();
    
    //Draws the stuff
    void Render();
    
    //Handles the events for the title screen
    bool OnEvent( SEvent event );
   
    private:
 
};

#endif 
The problem is in the event handler, when the button with the id of 103 is clicked. GS_CGame->blah doesn't work.

CTitleScreen.cpp

Code: Select all

#include "CTitleScreen.h"

//Constructor passes the engine pointers to the CGameState class!
CTitleScreen::CTitleScreen( IrrlichtDevice* dev, ISceneManager* mgr, IVideoDriver* driv, IGUIEnvironment* guienv, CGame* gam ) : CGameState( dev, mgr, driv, guienv, gam )
{
    GameState = TITLESCREEN;
    
    GS_guiEnv->addButton( rect<s32>( 300, 300, 350, 325 ), 0, 101, L"Quit" );
    
    GS_guiEnv->addButton( rect<s32>( 275, 250, 325, 275 ), 0, 103, L"2 Player" );
      
}

//Cleans up its inherited engine pointers.
CTitleScreen::~CTitleScreen()
{
    GS_device = 0;
    GS_sceneMgr = 0;
    GS_driver = 0;
    GS_guiEnv = 0;
}

//Its own update function, if the device is running, and the driver points to
//something, return true, otherwise return false.
bool CTitleScreen::Update()
{
    if( GS_device->run() && GS_driver )
    {
        return true;
    }
    else
    {
        return false;
    }
}    

//Its own render function, draws the stuff.
void CTitleScreen::Render()
{
    //Looking for quality, not speed.
    GS_driver->setTextureCreationFlag( ETCF_OPTIMIZED_FOR_QUALITY, true );
    
    ////////////////BEGIN RENDERING////////////////
    GS_driver->beginScene(true, true, SColor(0,100,100,100));
    
    //Displays background.
    GS_driver->draw2DImage( GS_driver->getTexture( "titleBMP.bmp" ), position2d<s32>(0,0) );
    
    GS_guiEnv->drawAll();
    
    GS_sceneMgr->drawAll();
    
    GS_driver->endScene();
}    

//Its own OnEvent function, handles the events that occur during the title screen gamestate
bool CTitleScreen::OnEvent( SEvent event )
{
    if( event.EventType == EET_KEY_INPUT_EVENT && !event.KeyInput.PressedDown )
    {
        switch( event.KeyInput.Key )
        {
            case KEY_ESCAPE: 
                 { 
                     GS_device->closeDevice(); 
                     break; 
                 }
        }
    }
    
    if (event.EventType == EET_GUI_EVENT)
    {
        s32 id = event.GUIEvent.Caller->getID();
        
        switch(event.GUIEvent.EventType)
        {
            case EGET_BUTTON_CLICKED:
            {
                if (id == 101)
                {
                    GS_device->closeDevice();
                    return true;
                }
                
                if( id == 103)
                {
                    GameState = TWOPLAYER;
                    GS_device->closeDevice();
                    GS_CGame->setGameState( GameState );
                    return true;
                }    
                
            }
        }
    }    
    return false;
}           
Tyn
Posts: 932
Joined: Thu Nov 20, 2003 7:53 pm
Location: England
Contact:

Post by Tyn »

CGameState hasn't included CGame.h so it doesn't know it exists. If you include it then it should work.
pszlachetka
Posts: 23
Joined: Mon Aug 30, 2004 12:30 am

Post by pszlachetka »

I put in a forward declaration of CGame ( e.g. class CGame; ) in the CGameState.h file, so that it knows that a class named CGame exists. It doesn't need to know how it work or anything, it just needs to know it exists. So I just have a pointer of CGame type, which should work. I cannot include CGame.h in the CGameState class because it will create a cyclic dependency. Any other suggestions?

-Peter
T101
Posts: 44
Joined: Thu Jul 29, 2004 4:41 pm

Post by T101 »

You really don't need to declare the CGame methods in CGameState.h

Ask yourself this question:
Where do I need to have the declaration of the method?

The answer is of course: where I call the method, so...

put the CGame.h include in the CGameState.cpp
pszlachetka
Posts: 23
Joined: Mon Aug 30, 2004 12:30 am

Post by pszlachetka »

I put #include "CGame.h" into the CGameState.cpp, same error. :(
Any other ideas?

-Peter
Tyn
Posts: 932
Joined: Thu Nov 20, 2003 7:53 pm
Location: England
Contact:

Post by Tyn »

In CGame.h

Code: Select all

    //The pointer to the current gamestate 
    CGameState*         currentGameState; 
In CGameState.h

Code: Select all

CGame* GS_CGame;
This obviously won't work without including CGame.h, so you add:

In CGameState.h

Code: Select all

#include "cgame.h"
Arg! Cross reference! Because CGameState uses CGame, CGame cannot know about CGameState or the compiler will be stuck in an endless loop. You will have to rethink your code structure, it would help you a lot to draw it out on a bit of paper. The only way a function can tell the calling class or function anything is by returning something, it is blind to anything behind it.
Guest

Post by Guest »

Hmmm. Now that I've had another look at the error message:
you should include cgame.h in ctitlescreen.cpp not in cgamestate.cpp.
My bad. Sorry about that.

Tyn: I guess this is why there is a convention of splitting the declarations and implementations into separate files. You don't need to know the size of a class in order to store a pointer for it.
You do need to know the definition of a class in order to access its member vars/methods.
So I think the Idea of using a forward declare such as Peter is using is viable. You only need to know the size of a pointer to allocate space for a pointer (such as the pointers in the CGame and CGameState classes).

Peter: I think this should work, provided you put the cgame.h include in CTitleScreen.cpp.
Although I personally would not make things so complicated. If you only ever allocate one CGame at a time, why not make it a global object? I.e. declare it somewhere high up in your main.cpp (or wherever you have your main loop) and declare it as extern in all the other cpp files.
That way, the same syntax is used as with member variables (when called from the same class), you save yourself some hassle with this sort of circular references, and you save a level of pointer indirection. Instead of accessing CGameState->CGame->var you simply access CGame->var.

T101
Post Reply