view states are now managed by a stack + bugfixing

- when one defines DECL_ENUM_LAST it is possible to check whether a string for
	a give enum exists
- making sure ships are alive when they are spawned
- added warning concerning QueueEvent and TriggerEvent (one shall avoid the
	latter)
main
Martin Felis (schakeline) 2010-11-27 20:56:38 +01:00
parent f8e5b7e873
commit 3340471c61
15 changed files with 114 additions and 55 deletions

View File

@ -15,7 +15,7 @@ BEGIN_ENUM(GameEntityType)
DECL_ENUM_ELEMENT(GameEntityTypeRocket), DECL_ENUM_ELEMENT(GameEntityTypeRocket),
DECL_ENUM_ELEMENT(GameEntityTypeAsteroid), DECL_ENUM_ELEMENT(GameEntityTypeAsteroid),
DECL_ENUM_ELEMENT(GameEntityTypeShipPart), DECL_ENUM_ELEMENT(GameEntityTypeShipPart),
DECL_ENUM_ELEMENT(GameEntityTypeLast) DECL_ENUM_LAST(GameEntityType)
} }
END_ENUM(GameEntityType) END_ENUM(GameEntityType)
@ -30,7 +30,8 @@ BEGIN_ENUM(ViewState)
DECL_ENUM_ELEMENT(ViewStateShowHighscore), DECL_ENUM_ELEMENT(ViewStateShowHighscore),
DECL_ENUM_ELEMENT(ViewStateEnterPlayername), DECL_ENUM_ELEMENT(ViewStateEnterPlayername),
DECL_ENUM_ELEMENT(ViewStateOptions), DECL_ENUM_ELEMENT(ViewStateOptions),
DECL_ENUM_ELEMENT(ViewStateGameOver) DECL_ENUM_ELEMENT(ViewStateGameOver),
DECL_ENUM_LAST(ViewState)
} }
END_ENUM(ViewState) END_ENUM(ViewState)
@ -38,6 +39,7 @@ BEGIN_ENUM(GameState)
{ {
DECL_ENUM_ELEMENT(GameStateRunning), DECL_ENUM_ELEMENT(GameStateRunning),
DECL_ENUM_ELEMENT(GameStatePaused), DECL_ENUM_ELEMENT(GameStatePaused),
DECL_ENUM_LAST(GameState)
} }
END_ENUM(GameState) END_ENUM(GameState)

View File

@ -12,7 +12,8 @@ BEGIN_ENUM(Event)
DECL_ENUM_ELEMENT(EventLevelComplete), DECL_ENUM_ELEMENT(EventLevelComplete),
DECL_ENUM_ELEMENT(EventChangeGameState), DECL_ENUM_ELEMENT(EventChangeGameState),
DECL_ENUM_ELEMENT(EventGameOver), DECL_ENUM_ELEMENT(EventGameOver),
DECL_ENUM_ELEMENT(EventShipExplode) DECL_ENUM_ELEMENT(EventShipExplode),
DECL_ENUM_LAST (Event)
} }
END_ENUM(Event) END_ENUM(Event)

View File

@ -132,13 +132,18 @@ bool Cmd_ControllerAttack (std::vector<std::string> args) {
assert (ControllerInstance); assert (ControllerInstance);
// only continue if the game is running // only continue if the game is running
if (GetModel()->GetGameState() != GameStateRunning) if (GetModel()->GetGameState() != GameStateRunning) {
Engine::LogDebug ("Not running attack as game is not running");
return false; return false;
}
ShipEntity* player_entity = (ShipEntity*) Engine::GetEntity (Engine::GetPlayerEntityId ()); ShipEntity* player_entity = (ShipEntity*) Engine::GetEntity (Engine::GetPlayerEntityId ());
if (player_entity) { if (player_entity) {
player_entity->Attack (); player_entity->Attack ();
return true; return true;
} else {
Engine::LogError ("Could not attack: player entity not found");
} }
return false; return false;

View File

@ -287,8 +287,10 @@ int Model::DoLoadLevel (const char* filename) {
bool is_player; bool is_player;
level_file >> is_player; level_file >> is_player;
if (is_player) if (is_player) {
mPlayerEntityId = entity->mId; mPlayerEntityId = entity->mId;
Engine::LogDebug ("Entity with id '%d' is player", entity->mId);
}
level_file >> entity->mPhysicState->mPosition[0]; level_file >> entity->mPhysicState->mPosition[0];
level_file >> entity->mPhysicState->mPosition[1]; level_file >> entity->mPhysicState->mPosition[1];
@ -352,6 +354,19 @@ int Model::DoSaveLevel (const char* filename) {
return 0; return 0;
} }
void Model::ProceedToNextLevel () {
Engine::LogDebug ("Proceeding to next level %d", mCurrentLevelIndex + 1);
mCurrentLevelIndex++;
if (mCurrentLevelIndex + 1 == mLevelList.size()) {
Engine::EventBasePtr gameover_event (new Engine::EventBase());
gameover_event->mEventType = EventGameOver;
QueueEvent (gameover_event);
} else {
DoLoadLevel(mLevelList[mCurrentLevelIndex].c_str());
}
}
void Model::SetGameState (const unsigned int &state) { void Model::SetGameState (const unsigned int &state) {
mLastGameState = mGameState; mLastGameState = mGameState;
@ -365,17 +380,7 @@ void Model::SetGameState (const unsigned int &state) {
bool Model::OnLevelComplete() { bool Model::OnLevelComplete() {
Engine::LogMessage ("Level complete!"); Engine::LogMessage ("Level complete!");
mCurrentLevelIndex++; ProceedToNextLevel();
if (mCurrentLevelIndex + 1 == mLevelList.size()) {
Engine::EventBasePtr gameover_event (new Engine::EventBase());
gameover_event->mEventType = EventGameOver;
QueueEvent (gameover_event);
} else {
DoLoadLevel(mLevelList[mCurrentLevelIndex].c_str());
}
SetGameState(GameStatePaused);
return true; return true;
} }
@ -444,7 +449,7 @@ void Model::OnKillEntity (const Engine::EntityBase *entity) {
if (mAsteroids.size() == 0) { if (mAsteroids.size() == 0) {
Engine::EventBasePtr level_complete_event (new Engine::EventBase()); Engine::EventBasePtr level_complete_event (new Engine::EventBase());
level_complete_event->mEventType = EventLevelComplete; level_complete_event->mEventType = EventLevelComplete;
TriggerEvent (level_complete_event); QueueEvent (level_complete_event);
} }
} }
} }

View File

@ -10,16 +10,22 @@ class Model : public Engine::ModelBase {
public: public:
virtual ~Model() {}; virtual ~Model() {};
virtual void Process(); virtual void Process();
int DoLoadLevel (const char* filename); virtual void SetGameState (const unsigned int &state);
int DoSaveLevel (const char* filename); float GetWorldWidth ();
float GetWorldHeight ();
/* Event handler */
bool OnLevelComplete(); bool OnLevelComplete();
bool OnGameOver(); bool OnGameOver();
/** \brief Resets values from a previous game */ /** \brief Resets values from a previous game */
void OnNewGame (); void OnNewGame ();
void OnShipExplode (); void OnShipExplode ();
virtual void SetGameState (const unsigned int &state); /* Level loading etc. */
int DoLoadLevel (const char* filename);
int DoSaveLevel (const char* filename);
void ProceedToNextLevel ();
int GetPlayerLives () { return mPlayerLives; }; int GetPlayerLives () { return mPlayerLives; };
unsigned int GetPoints () { return mPoints; }; unsigned int GetPoints () { return mPoints; };
std::string GetPlayerName() { return mPlayerName; }; std::string GetPlayerName() { return mPlayerName; };
@ -28,9 +34,7 @@ class Model : public Engine::ModelBase {
mPlayerName = name; mPlayerName = name;
}; };
float GetWorldWidth (); /* Highscore */
float GetWorldHeight ();
struct HighscoreEntry { struct HighscoreEntry {
HighscoreEntry(): name ("unknown"), points (0) { }; HighscoreEntry(): name ("unknown"), points (0) { };
HighscoreEntry (const char *e_name, const unsigned int e_points): HighscoreEntry (const char *e_name, const unsigned int e_points):
@ -40,7 +44,6 @@ class Model : public Engine::ModelBase {
unsigned int points; unsigned int points;
}; };
/* Highscore */
void LoadHighscoreList (); void LoadHighscoreList ();
void SaveHighscoreList (); void SaveHighscoreList ();
unsigned int AddHighscoreEntry(const std::string &name, const unsigned int points); unsigned int AddHighscoreEntry(const std::string &name, const unsigned int points);

View File

@ -11,7 +11,7 @@ struct ShipEntityPhysicState : public Engine::EntityPhysicState {
ShipEntityPhysicState () { ShipEntityPhysicState () {
mType = GameEntityTypeShip; mType = GameEntityTypeShip;
mBaseType = Engine::EntityBaseTypeActor; mBaseType = Engine::EntityBaseTypeActor;
mAcceleration = 10.; mAcceleration = 10.;
mMaxSpeed = 10.; mMaxSpeed = 10.;
mRotationSpeed = 180.; mRotationSpeed = 180.;
@ -37,6 +37,7 @@ struct ShipEntity: public Engine::EntityBase {
mType = GameEntityTypeShip; mType = GameEntityTypeShip;
mBaseType = Engine::EntityBaseTypeActor; mBaseType = Engine::EntityBaseTypeActor;
mAlive = true;
mState = Idle; mState = Idle;
mAttackTimer = 0.; mAttackTimer = 0.;
} }

View File

@ -523,17 +523,22 @@ void View::DrawUiGamePaused() {
if (Engine::GUI::Button (1, "Resume Game", screen_right * 0.5 - 100, 200, button_width, button_height)) { if (Engine::GUI::Button (1, "Resume Game", screen_right * 0.5 - 100, 200, button_width, button_height)) {
PopViewState(); PopViewState();
}
if (Engine::GUI::Button (2, "Abort Game", screen_right * 0.5 - 100, 250, button_width, button_height)) {
while (mViewStateStack.size())
PopViewState();
PushViewState(ViewStateGameRunning);
GetModel()->SetGameState(GameStateRunning); GetModel()->SetGameState(GameStateRunning);
} }
if (Engine::GUI::Button (3, "Quit", screen_right * 0.5 - 100, 330, button_width, button_height)) { if (Engine::GUI::Button (2, "Options", screen_right * 0.5 - 100, 250, button_width, button_height)) {
PushViewState (ViewStateOptions);
}
if (Engine::GUI::Button (3, "Abort Game", screen_right * 0.5 - 100, 300, button_width, button_height)) {
while (mViewStateStack.size())
PopViewState();
PushViewState(ViewStateMainMenu);
GetModel()->SetGameState(GameStatePaused);
}
if (Engine::GUI::Button (4, "Quit", screen_right * 0.5 - 100, 380, button_width, button_height)) {
Engine::RunCommand("quit"); Engine::RunCommand("quit");
} }
} }

View File

@ -76,8 +76,11 @@ class View : public Engine::ViewBase {
return mViewStateStack.top(); return mViewStateStack.top();
} }
void PopViewState () { void PopViewState () {
// Warning: you must not query for an invalid enum with
// GetStringENUM_NAME!
Engine::LogDebug("Popping ViewState: %s remainging: %u", GetStringViewState(mViewStateStack.top()), mViewStateStack.size());
mViewStateStack.pop(); mViewStateStack.pop();
Engine::LogDebug ("Popped ViewState top is now:%s", GetStringViewState(mViewStateStack.top()));
} }
// \todo [high] add Resource Manager! // \todo [high] add Resource Manager!

View File

@ -21,7 +21,8 @@ BEGIN_ENUM(EngineStatus)
DECL_ENUM_ELEMENT(EngineStatusRunning), DECL_ENUM_ELEMENT(EngineStatusRunning),
DECL_ENUM_ELEMENT(EngineStatusStopping), DECL_ENUM_ELEMENT(EngineStatusStopping),
DECL_ENUM_ELEMENT(EngineStatusStopped), DECL_ENUM_ELEMENT(EngineStatusStopped),
DECL_ENUM_ELEMENT(EngineStatusDestroying) DECL_ENUM_ELEMENT(EngineStatusDestroying),
DECL_ENUM_LAST(EngineStatus)
} }
END_ENUM(EngineStatus) END_ENUM(EngineStatus)
@ -30,7 +31,8 @@ BEGIN_ENUM(LogLevel)
DECL_ENUM_ELEMENT(LogLevelDebug), DECL_ENUM_ELEMENT(LogLevelDebug),
DECL_ENUM_ELEMENT(LogLevelWarning), DECL_ENUM_ELEMENT(LogLevelWarning),
DECL_ENUM_ELEMENT(LogLevelMessage), DECL_ENUM_ELEMENT(LogLevelMessage),
DECL_ENUM_ELEMENT(LogLevelError) DECL_ENUM_ELEMENT(LogLevelError),
DECL_ENUM_LAST(LogLevel)
} }
END_ENUM(LogLevel) END_ENUM(LogLevel)
@ -38,7 +40,8 @@ BEGIN_ENUM(FontJustification)
{ {
DECL_ENUM_ELEMENT(FontJustificationRight), DECL_ENUM_ELEMENT(FontJustificationRight),
DECL_ENUM_ELEMENT(FontJustificationCenter), DECL_ENUM_ELEMENT(FontJustificationCenter),
DECL_ENUM_ELEMENT(FontJustificationLeft) DECL_ENUM_ELEMENT(FontJustificationLeft),
DECL_ENUM_LAST(FontJustification)
} }
END_ENUM(FontJustification) END_ENUM(FontJustification)

View File

@ -15,21 +15,24 @@
* *
*/ */
#undef DECL_ENUM_LAST
#undef DECL_ENUM_ELEMENT #undef DECL_ENUM_ELEMENT
#undef BEGIN_ENUM #undef BEGIN_ENUM
#undef END_ENUM #undef END_ENUM
#ifndef GENERATE_ENUM_STRINGS #ifndef GENERATE_ENUM_STRINGS
#define DECL_ENUM_LAST( ENUM_NAME ) ENUM_NAME ## Last
#define DECL_ENUM_ELEMENT( element ) element #define DECL_ENUM_ELEMENT( element ) element
#define BEGIN_ENUM( ENUM_NAME ) typedef enum tag##ENUM_NAME #define BEGIN_ENUM( ENUM_NAME ) typedef enum tag##ENUM_NAME
#define END_ENUM( ENUM_NAME ) ENUM_NAME; \ #define END_ENUM( ENUM_NAME ) ENUM_NAME; \
const char* GetString##ENUM_NAME(enum tag##ENUM_NAME index); \ const char* GetString##ENUM_NAME(enum tag##ENUM_NAME index); \
const char* GetString##ENUM_NAME(unsigned int index); const char* GetString##ENUM_NAME(unsigned int index);
#else #else
#define DECL_ENUM_LAST( ENUM_NAME ) #ENUM_NAME
#define DECL_ENUM_ELEMENT( element ) #element #define DECL_ENUM_ELEMENT( element ) #element
#define BEGIN_ENUM( ENUM_NAME ) const char* gs_##ENUM_NAME [] = #define BEGIN_ENUM( ENUM_NAME ) const char* gs_##ENUM_NAME [] =
#define END_ENUM( ENUM_NAME ) ; \ #define END_ENUM( ENUM_NAME ) ; \
const char* GetString##ENUM_NAME(enum \ const char* GetString##ENUM_NAME(enum \
tag##ENUM_NAME index){ return gs_##ENUM_NAME [index]; } \ tag##ENUM_NAME index){ if (index < 0 || index > ENUM_NAME ## Last) return "Unknown Enum"; return gs_##ENUM_NAME [index]; } \
const char* GetString##ENUM_NAME(unsigned int index){ return gs_##ENUM_NAME [index]; } const char* GetString##ENUM_NAME(unsigned int index){ if (index < 0 || index > ENUM_NAME ## Last) return "Unknown Enum"; return gs_##ENUM_NAME [index]; }
#endif #endif

View File

@ -9,7 +9,12 @@ namespace Engine {
bool RegisterListener (Module *listener_module, const int event_type); bool RegisterListener (Module *listener_module, const int event_type);
/** \brief Calls all event listeners to handle the events */ /** \brief Calls all event listeners to handle the events */
bool QueueEvent (const EventBasePtr &event); bool QueueEvent (const EventBasePtr &event);
/** \brief Calls the listener handlers immediately */ /** \brief Calls the listener handlers immediately
*
* \warning It is safer to use QueueEvent() instead as the event
* \warning handlers are called at a safely defined time and
* \warning there is a lower risk deleting entities that still
* \warning might be in use somewhere! */
bool TriggerEvent (const EventBasePtr &event); bool TriggerEvent (const EventBasePtr &event);
} }

View File

@ -80,8 +80,10 @@ void Logging::Log (LogLevel level, const char *str, ...) {
mLogFileOut << "Error occured: Aborting!" << std::endl; mLogFileOut << "Error occured: Aborting!" << std::endl;
mLogFileOut.flush(); mLogFileOut.flush();
mLogFileOut.close(); mLogFileOut.close();
exit (-1);
} }
// we abort if there was an error
assert (level != LogLevelError);
} }
void Logging::SetLogPrintLevel (LogLevel print_level) { void Logging::SetLogPrintLevel (LogLevel print_level) {

View File

@ -58,21 +58,28 @@ void ModelBase::Process () {
entity_iter++; entity_iter++;
} while (entity_iter != mEntities.end()); } while (entity_iter != mEntities.end());
/*
// Update the timers // Update the timers
for (TimerIter timer_iter = mTimers.begin(); timer_iter != mTimers.end(); timer_iter++) { for (TimerIter timer_iter = mTimers.begin(); timer_iter != mTimers.end(); timer_iter++) {
timer_iter->second.Update(mDeltaSec); timer_iter->second.Update(mDeltaSec);
timer_iter++; timer_iter++;
} }
*/
// simulate the world // simulate the world
mPhysics->Simulate (mDeltaSec, this); mPhysics->Simulate (mDeltaSec, this);
// remove killed entities assert (mKilledEntities.size() <= mEntities.size());
unsigned int i;
for (i = 0; i < mKilledEntities.size(); i++)
UnregisterEntity (mKilledEntities[i]);
mKilledEntities.clear(); // remove killed entities
if (mKilledEntities.size() > 0) {
unsigned int i;
LogDebug ("There are %d entities to kill", mKilledEntities.size());
for (i = 0; i < mKilledEntities.size(); i++)
UnregisterEntity (mKilledEntities[i]);
mKilledEntities.clear();
}
} }
EntityBase* ModelBase::CreateEntity (int type) { EntityBase* ModelBase::CreateEntity (int type) {
@ -94,10 +101,10 @@ EntityBase* ModelBase::CreateEntity (int type) {
void ModelBase::RegisterEntity (EntityBase* entity) { void ModelBase::RegisterEntity (EntityBase* entity) {
unsigned int id = entity->mId; unsigned int id = entity->mId;
LogDebug ("Registering Entity with id '%d'", id); LogDebug ("Registering Entity with id '%u' and type '%u'", id, entity->mType);
if (mEntities.find(id) != mEntities.end ()) { if (mEntities.find(id) != mEntities.end ()) {
LogError ("Replacing Entity with id '%d'", id); LogError ("Replacing Entity with id '%u' and type '%u'", id, entity->mType);
} }
if (entity->mPhysicState) if (entity->mPhysicState)
@ -109,14 +116,18 @@ void ModelBase::RegisterEntity (EntityBase* entity) {
void ModelBase::KillEntity (const unsigned int id) { void ModelBase::KillEntity (const unsigned int id) {
std::map<unsigned int, EntityBase*>::iterator iter = mEntities.find (id); std::map<unsigned int, EntityBase*>::iterator iter = mEntities.find (id);
LogDebug ("Killing entity with id '%u'", id);
if (iter == mEntities.end ()) { if (iter == mEntities.end ()) {
LogError ("Could not kill Entity with id '%d': Entity not found!", id); LogError ("Could not kill Entity with id '%u': Entity not found!", id);
return; return;
} else { } else {
EntityBase *entity = iter->second; EntityBase *entity = iter->second;
LogDebug ("Entity pointer = 0x%u", entity);
// call the event handler // call the event handler
OnKillEntity (entity); OnKillEntity (entity);
LogDebug ("Entity pointer (after kill) = 0x%u", entity);
if (entity->mPhysicState) { if (entity->mPhysicState) {
entity->mPhysicState->mAlive = false; entity->mPhysicState->mAlive = false;
@ -130,6 +141,7 @@ void ModelBase::UnregisterEntity (const unsigned int id) {
std::map<unsigned int, EntityBase*>::iterator iter = mEntities.find (id); std::map<unsigned int, EntityBase*>::iterator iter = mEntities.find (id);
if (iter == mEntities.end ()) { if (iter == mEntities.end ()) {
LogDebug ("iter id=%u entitypointer=0x%x type=%d", iter->first, iter->second, iter->second->mType);
LogError ("Could not unregister Entity with id '%d': Entity not found!", id); LogError ("Could not unregister Entity with id '%d': Entity not found!", id);
return; return;
} else { } else {
@ -180,6 +192,9 @@ void ModelBase::ClearEntities () {
} }
mEntityIdCounter = 0; mEntityIdCounter = 0;
// we alsohave to clear the vector of killed entities!
mKilledEntities.clear();
} }
unsigned int ModelBase::GetPlayerEntityId () { unsigned int ModelBase::GetPlayerEntityId () {
@ -291,6 +306,7 @@ EntityPhysicState * GetEntityPhysicState (unsigned int id) {
return NULL; return NULL;
} }
/*
void StartTimer(const std::string &id, float sec) { void StartTimer(const std::string &id, float sec) {
if (!ModelInstance) { if (!ModelInstance) {
LogError ("Couldn't execute GetEntity(): Model not initialized!"); LogError ("Couldn't execute GetEntity(): Model not initialized!");
@ -306,6 +322,7 @@ bool CheckTimer(const std::string &id) {
return ModelInstance->CheckTimer(id); return ModelInstance->CheckTimer(id);
} }
*/
} }

View File

@ -3,7 +3,7 @@
#include "Engine.h" #include "Engine.h"
#include "EntityBase.h" #include "EntityBase.h"
#include "Timer.h" // #include "Timer.h"
namespace Engine { namespace Engine {
@ -80,6 +80,7 @@ class ModelBase : public Module {
}; };
unsigned int GetGameState () { return mGameState; }; unsigned int GetGameState () { return mGameState; };
/*
void StartTimer(const std::string &id, float msec) { void StartTimer(const std::string &id, float msec) {
TimerIter cur_timer = mTimers.find(id); TimerIter cur_timer = mTimers.find(id);
if (cur_timer != mTimers.end()) { if (cur_timer != mTimers.end()) {
@ -102,6 +103,7 @@ class ModelBase : public Module {
return cur_timer->second.Query(); return cur_timer->second.Query();
} }
*/
protected: protected:
/** \brief Initializes the system */ /** \brief Initializes the system */
@ -128,8 +130,10 @@ class ModelBase : public Module {
/** \brief contains all Engine::Entities that ceased to exist */ /** \brief contains all Engine::Entities that ceased to exist */
std::vector<unsigned int> mKilledEntities; std::vector<unsigned int> mKilledEntities;
/*
std::map<std::string, Timer> mTimers; std::map<std::string, Timer> mTimers;
typedef std::map<std::string, Timer>::iterator TimerIter; typedef std::map<std::string, Timer>::iterator TimerIter;
*/
unsigned int mEntityIdCounter; unsigned int mEntityIdCounter;
unsigned int mPlayerEntityId; unsigned int mPlayerEntityId;

View File

@ -9,11 +9,11 @@ unsigned int GetPlayerEntityId ();
/** \brief Returns the duration of the frame in seconds */ /** \brief Returns the duration of the frame in seconds */
float GetFrameDuration (); float GetFrameDuration ();
/** \brief Starts a timer with the given id that expires after sec seconds */ // /** \brief Starts a timer with the given id that expires after sec seconds */
void StartTimer(const std::string &id, float sec); // void StartTimer(const std::string &id, float sec);
//
/** \brief Checks whether a timer expired */ // /** \brief Checks whether a timer expired */
bool CheckTimer(const std::string &id); // bool CheckTimer(const std::string &id);
} }