So I've been working on this little SDL framework, if you can even call it that, which will hopefully make my life a little easier when I'm making some simple games. At the moment I'm trying to get some sort of a state manager up and running. As the title says, I'm having difficulty fixing some warnings and errors.
I know it's appreciated by most if I refrain from posting irrelevant code, but the truth is that I'm not quite sure what code is irrelevant. So I'll post the whole shebang. It's not _that_ much and I've done my best on the comments.
States.txt
States are used to separate the global states a game can be in (say, the front-end menu, ingame, the help menu etc).
States are implemented by using three classes: StateBase, State and
StateManager.
- StateBase is an abstract base class that provides functions for handling
events and logic and for rendering screens. The states will then inherit
from this class.
- State is a handle class that takes responsibility for handling the
complexity created by polymorphic use of states.
- StateManager manages a State stack. The idea of the State stack is that the
top element of the stack is the state that is in use (the so-called current
stack).
StateBase.h
#ifndef STATEBASE_H
#define STATEBASE_H
//Descr: The abstract base class of all the states.
/////////////////////////////////////////////////////////////////////
#include "SDL/SDL.h"
class StateBase {
friend class State;
public:
virtual ~StateBase();
virtual bool HandleEvents() = 0;
virtual bool HandleLogic() = 0;
virtual bool RenderScreen(SDL_Surface*) = 0;
protected:
// Clone() makes a copy of the object it is called from and returns
// a pointer that points to that copy.
virtual StateBase* Clone() const = 0;
};
#endif
State.h and State.cpp
#ifndef STATE_H
#define STATE_H
//Descr: State is a handle class for the classes that derive from
// the abstract base class Statebase. It's purpose is to hide the
// complexity caused by polymorphic use of the classes from the user.
/////////////////////////////////////////////////////////////////////
#include "StateBase.h"
// State ID's are unique labels that are given to states. Additional
// states that are created should have their own ID.
enum StateId {
STATE_NULL, // Not an actual state. Used to communicate "no state".
STATE_FEMENU, // The front-end menu state.
STATE_INGAME // Ingame state. Should be sufficient for simple games.
};
class State {
public:
// Needed constructors and assignment operator.
State(StateId sid);
State& operator=(const State& sc);
~State() { delete s; }
// All the work is simply forwarded to the state pointed to by s.
bool HandleEvents() { return s->HandleEvents(); }
bool HandleLogic() { return s->HandleLogic(); }
bool RenderScreen(SDL_Surface* surf) { return s->RenderScreen(surf); }
private:
// s points to an actual state.
StateBase* s;
};
#endif
#include "State.h"
#include "InGame.h"
#include <stdexcept>
using std::invalid_argument;
State::State(StateId sid)
{
switch (sid) {
/*case STATE_FEMENU:
s = new FEMenu;
break;*/
case STATE_INGAME:
s = new InGame;
break;
default:
throw invalid_argument("The state ID is invalid.");
}
}
State& State::operator=(const State& sc)
{
// If the object isn't being assigned to itself
if (&sc != this) {
// delete the current state object pointed to
delete s;
// and point to a clone of the other state object.
s = sc.s->Clone();
}
return *this;
}
StateManager.h and StateManager.cpp
#ifndef STATEMANAGER_H
#define STATEMANAGER_H
//Descr: The statemanager manages a stack of states. It can change
// states in three ways: by pushing a state on top of the
// current state, by popping the current state on the stack and
// by replacing the current state with a new one.
//Notes: The current state is always the top element of the stack.
/////////////////////////////////////////////////////////////////////
#include "State.h"
#include <stack>
class StateManager {
// Type to describe methods of state changing.
enum ChangeMethod {
CM_NULL,
CM_REPLACE,
CM_PUSH,
CM_POP
};
public:
// Initialize the implementation variables.
StateManager(): nextStateId(STATE_NULL), isKilled(false), changeMethod(CM_NULL) { }
// Set next state, which will replace the current state.
bool NextStateReplace(StateId newState);
// Set next state, which will be stacked on top of the current one.
void NextStatePush(StateId newState);
// Set next state to be the state under the current state in the stack,
// deleting the current state in the process.
bool NextStatePop();
// Actually change to the next state, if there is one.
bool ChangeState();
// Returns a reference to the current state.
State& CurrentState() { return stateStack.top(); }
// Kill the statemanager.
void Kill() { isKilled = true; }
// Check if the statemanager has been killed.
bool IsKilled() { return isKilled; }
private:
std::stack<State> stateStack;
StateId nextStateId;
bool isKilled;
ChangeMethod changeMethod;
};
#endif
#include "StateManager.h"
using std::stack;
bool StateManager::NextStateReplace(StateId newState)
{
if(stateStack.empty() == false) {
nextStateId = newState;
changeMethod = CM_REPLACE;
return true;
} else
return false;
}
void StateManager::NextStatePush(StateId newState)
{
nextStateId = newState;
changeMethod = CM_PUSH;
}
bool StateManager::NextStatePop()
{
if(stateStack.size() > stack<State>::size_type(1)) {
changeMethod = CM_POP;
return true;
} else
return false;
}
bool StateManager::ChangeState()
{
switch(changeMethod) {
case CM_NULL:
return false;
case CM_REPLACE:
stateStack.top() = State(nextStateId);
break;
case CM_PUSH:
stateStack.push(State(nextStateId));
break;
case CM_POP:
stateStack.pop();
break;
}
nextStateId = STATE_NULL; // RESET
changeMethod = CM_NULL; // RESET
return true;
}
I've created a state called Ingame to test the framework:
InGame.h and Ingame.cpp
#ifndef INGAME_H
#define INGAME_H
#include "StateBase.h"
#include "Button.h"
class InGame: public StateBase {
public:
InGame() { quit = new Button("quit.png", 20, 20); }
~InGame() { delete quit; }
bool HandleEvents();
bool HandleLogic();
bool RenderScreen(SDL_Surface*);
protected:
InGame* Clone() const { return new InGame(*this); }
private:
Button* quit;
};
#endif
#include "InGame.h"
bool InGame::HandleEvents()
{
return true; // Not yet finished...
}
bool InGame::HandleLogic()
{
return true; // Not yet finished...
}
bool InGame::RenderScreen(SDL_Surface *)
{
return true; // Not yet finished...
}
I'm getting the following output:
Quote:Compiling...
main.cpp
SDLVideo.cpp
Ingame.cpp
c:\program files\microsoft visual studio 8\vc\include\xlocnum(590) : warning C4312: 'type cast' : conversion from 'uintptr_t' to 'void *' of greater size
c:\program files\microsoft visual studio 8\vc\include\xlocnum(566) : while compiling class template member function 'std::istreambuf_iterator<_Elem,_Traits> std::num_get<_Elem,_InIt>::do_get(_InIt,_InIt,std::ios_base &,std::ios_base::iostate &,void *&) const'
with
[
_Elem=char,
_Traits=std::char_traits,
_InIt=std::istreambuf_iterator>
]
c:\program files\microsoft visual studio 8\vc\include\xlocnum(1365) : see reference to class template instantiation 'std::num_get<_Elem,_InIt>' being compiled
with
[
_Elem=char,
_InIt=std::istreambuf_iterator>
]
c:\program files\microsoft visual studio 8\vc\include\xlocnum(590) : warning C4312: 'type cast' : conversion from 'uintptr_t' to 'void *' of greater size
c:\program files\microsoft visual studio 8\vc\include\xlocnum(566) : while compiling class template member function 'std::istreambuf_iterator<_Elem,_Traits> std::num_get<_Elem,_InIt>::do_get(_InIt,_InIt,std::ios_base &,std::ios_base::iostate &,void *&) const'
with
[
_Elem=wchar_t,
_Traits=std::char_traits,
_InIt=std::istreambuf_iterator>
]
c:\program files\microsoft visual studio 8\vc\include\xlocnum(1371) : see reference to class template instantiation 'std::num_get<_Elem,_InIt>' being compiled
with
[
_Elem=wchar_t,
_InIt=std::istreambuf_iterator>
]
State.cpp
c:\program files\microsoft visual studio 8\vc\include\xlocnum(590) : warning C4312: 'type cast' : conversion from 'uintptr_t' to 'void *' of greater size
c:\program files\microsoft visual studio 8\vc\include\xlocnum(566) : while compiling class template member function 'std::istreambuf_iterator<_Elem,_Traits> std::num_get<_Elem,_InIt>::do_get(_InIt,_InIt,std::ios_base &,std::ios_base::iostate &,void *&) const'
with
[
_Elem=char,
_Traits=std::char_traits,
_InIt=std::istreambuf_iterator>
]
c:\program files\microsoft visual studio 8\vc\include\xlocnum(1365) : see reference to class template instantiation 'std::num_get<_Elem,_InIt>' being compiled
with
[
_Elem=char,
_InIt=std::istreambuf_iterator>
]
c:\program files\microsoft visual studio 8\vc\include\xlocnum(590) : warning C4312: 'type cast' : conversion from 'uintptr_t' to 'void *' of greater size
c:\program files\microsoft visual studio 8\vc\include\xlocnum(566) : while compiling class template member function 'std::istreambuf_iterator<_Elem,_Traits> std::num_get<_Elem,_InIt>::do_get(_InIt,_InIt,std::ios_base &,std::ios_base::iostate &,void *&) const'
with
[
_Elem=wchar_t,
_Traits=std::char_traits,
_InIt=std::istreambuf_iterator>
]
c:\program files\microsoft visual studio 8\vc\include\xlocnum(1371) : see reference to class template instantiation 'std::num_get<_Elem,_InIt>' being compiled
with
[
_Elem=wchar_t,
_InIt=std::istreambuf_iterator>
]
StateManager.cpp
Button.cpp
c:\program files\microsoft visual studio 8\vc\include\xlocnum(590) : warning C4312: 'type cast' : conversion from 'uintptr_t' to 'void *' of greater size
c:\program files\microsoft visual studio 8\vc\include\xlocnum(566) : while compiling class template member function 'std::istreambuf_iterator<_Elem,_Traits> std::num_get<_Elem,_InIt>::do_get(_InIt,_InIt,std::ios_base &,std::ios_base::iostate &,void *&) const'
with
[
_Elem=char,
_Traits=std::char_traits,
_InIt=std::istreambuf_iterator>
]
c:\program files\microsoft visual studio 8\vc\include\xlocnum(1365) : see reference to class template instantiation 'std::num_get<_Elem,_InIt>' being compiled
with
[
_Elem=char,
_InIt=std::istreambuf_iterator>
]
c:\program files\microsoft visual studio 8\vc\include\xlocnum(590) : warning C4312: 'type cast' : conversion from 'uintptr_t' to 'void *' of greater size
c:\program files\microsoft visual studio 8\vc\include\xlocnum(566) : while compiling class template member function 'std::istreambuf_iterator<_Elem,_Traits> std::num_get<_Elem,_InIt>::do_get(_InIt,_InIt,std::ios_base &,std::ios_base::iostate &,void *&) const'
with
[
_Elem=wchar_t,
_Traits=std::char_traits,
_InIt=std::istreambuf_iterator>
]
c:\program files\microsoft visual studio 8\vc\include\xlocnum(1371) : see reference to class template instantiation 'std::num_get<_Elem,_InIt>' being compiled
with
[
_Elem=wchar_t,
_InIt=std::istreambuf_iterator>
]
Generating Code...
Compiling manifest to resources...
Linking...
!!!FIXEDState.obj : error LNK2019: unresolved external symbol "public: virtual __thiscall StateBase::~StateBase(void)" (??1StateBase@@UAE@XZ) referenced in function __unwindfunclet$??0InGame@@QAE@XZ$0 FIXED!!!
StateManager.obj : error LNK2019: unresolved external symbol __imp___CrtDbgReportW referenced in function "public: class State const & __thiscall std::_Deque_const_iterator,1>::operator*(void)const " (??D?$_Deque_const_iterator@VState@@V?$allocator@VState@@@std@@$00@std@@QBEABVState@@XZ)
C:\Projects\Application\Debug\Application.exe : fatal error LNK1120: 2 unresolved externals
Yikes! If anyone could shed some light on the matter, that would be great.
On a different note, if you happen to read the code and you believe It's a bad design or you think it's bad in some other way, I'd love to hear from you. I'm always trying to improve, so I welcome all constructive criticism.
[Edited by - atRoot on August 4, 2007 4:26:45 PM]