From 3340471c6145b25db8389caccd50f02543bbfb50 Mon Sep 17 00:00:00 2001 From: "Martin Felis (schakeline)" Date: Sat, 27 Nov 2010 20:56:38 +0100 Subject: [PATCH] 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) --- asteroids/AsteroidsEnums.h | 6 ++++-- asteroids/AsteroidsEvents.h | 3 ++- asteroids/ControllerCommands.cc | 7 ++++++- asteroids/Model.cc | 31 ++++++++++++++++++------------- asteroids/Model.h | 17 ++++++++++------- asteroids/ShipEntity.h | 3 ++- asteroids/View.cc | 21 +++++++++++++-------- asteroids/View.h | 5 ++++- engine/EngineEnums.h | 9 ++++++--- engine/EnumToString.h | 7 +++++-- engine/EventBaseGlobal.h | 7 ++++++- engine/Logging.cc | 4 +++- engine/ModelBase.cc | 33 +++++++++++++++++++++++++-------- engine/ModelBase.h | 6 +++++- engine/ModelBaseGlobal.h | 10 +++++----- 15 files changed, 114 insertions(+), 55 deletions(-) diff --git a/asteroids/AsteroidsEnums.h b/asteroids/AsteroidsEnums.h index 375c403..dd54f2e 100644 --- a/asteroids/AsteroidsEnums.h +++ b/asteroids/AsteroidsEnums.h @@ -15,7 +15,7 @@ BEGIN_ENUM(GameEntityType) DECL_ENUM_ELEMENT(GameEntityTypeRocket), DECL_ENUM_ELEMENT(GameEntityTypeAsteroid), DECL_ENUM_ELEMENT(GameEntityTypeShipPart), - DECL_ENUM_ELEMENT(GameEntityTypeLast) + DECL_ENUM_LAST(GameEntityType) } END_ENUM(GameEntityType) @@ -30,7 +30,8 @@ BEGIN_ENUM(ViewState) DECL_ENUM_ELEMENT(ViewStateShowHighscore), DECL_ENUM_ELEMENT(ViewStateEnterPlayername), DECL_ENUM_ELEMENT(ViewStateOptions), - DECL_ENUM_ELEMENT(ViewStateGameOver) + DECL_ENUM_ELEMENT(ViewStateGameOver), + DECL_ENUM_LAST(ViewState) } END_ENUM(ViewState) @@ -38,6 +39,7 @@ BEGIN_ENUM(GameState) { DECL_ENUM_ELEMENT(GameStateRunning), DECL_ENUM_ELEMENT(GameStatePaused), + DECL_ENUM_LAST(GameState) } END_ENUM(GameState) diff --git a/asteroids/AsteroidsEvents.h b/asteroids/AsteroidsEvents.h index 8fdd373..9335fc8 100644 --- a/asteroids/AsteroidsEvents.h +++ b/asteroids/AsteroidsEvents.h @@ -12,7 +12,8 @@ BEGIN_ENUM(Event) DECL_ENUM_ELEMENT(EventLevelComplete), DECL_ENUM_ELEMENT(EventChangeGameState), DECL_ENUM_ELEMENT(EventGameOver), - DECL_ENUM_ELEMENT(EventShipExplode) + DECL_ENUM_ELEMENT(EventShipExplode), + DECL_ENUM_LAST (Event) } END_ENUM(Event) diff --git a/asteroids/ControllerCommands.cc b/asteroids/ControllerCommands.cc index 87446ec..486204e 100644 --- a/asteroids/ControllerCommands.cc +++ b/asteroids/ControllerCommands.cc @@ -132,13 +132,18 @@ bool Cmd_ControllerAttack (std::vector args) { assert (ControllerInstance); // 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; + } ShipEntity* player_entity = (ShipEntity*) Engine::GetEntity (Engine::GetPlayerEntityId ()); if (player_entity) { player_entity->Attack (); return true; + } else { + Engine::LogError ("Could not attack: player entity not found"); + } return false; diff --git a/asteroids/Model.cc b/asteroids/Model.cc index b81b833..0fef6e8 100644 --- a/asteroids/Model.cc +++ b/asteroids/Model.cc @@ -287,8 +287,10 @@ int Model::DoLoadLevel (const char* filename) { bool is_player; level_file >> is_player; - if (is_player) + if (is_player) { mPlayerEntityId = entity->mId; + Engine::LogDebug ("Entity with id '%d' is player", entity->mId); + } level_file >> entity->mPhysicState->mPosition[0]; level_file >> entity->mPhysicState->mPosition[1]; @@ -352,6 +354,19 @@ int Model::DoSaveLevel (const char* filename) { 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) { mLastGameState = mGameState; @@ -365,17 +380,7 @@ void Model::SetGameState (const unsigned int &state) { bool Model::OnLevelComplete() { Engine::LogMessage ("Level complete!"); - 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()); - } - - SetGameState(GameStatePaused); + ProceedToNextLevel(); return true; } @@ -444,7 +449,7 @@ void Model::OnKillEntity (const Engine::EntityBase *entity) { if (mAsteroids.size() == 0) { Engine::EventBasePtr level_complete_event (new Engine::EventBase()); level_complete_event->mEventType = EventLevelComplete; - TriggerEvent (level_complete_event); + QueueEvent (level_complete_event); } } } diff --git a/asteroids/Model.h b/asteroids/Model.h index ac93587..77d1b9a 100644 --- a/asteroids/Model.h +++ b/asteroids/Model.h @@ -10,16 +10,22 @@ class Model : public Engine::ModelBase { public: virtual ~Model() {}; virtual void Process(); - int DoLoadLevel (const char* filename); - int DoSaveLevel (const char* filename); + virtual void SetGameState (const unsigned int &state); + float GetWorldWidth (); + float GetWorldHeight (); + + /* Event handler */ bool OnLevelComplete(); bool OnGameOver(); /** \brief Resets values from a previous game */ void OnNewGame (); 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; }; unsigned int GetPoints () { return mPoints; }; std::string GetPlayerName() { return mPlayerName; }; @@ -28,9 +34,7 @@ class Model : public Engine::ModelBase { mPlayerName = name; }; - float GetWorldWidth (); - float GetWorldHeight (); - + /* Highscore */ struct HighscoreEntry { HighscoreEntry(): name ("unknown"), points (0) { }; HighscoreEntry (const char *e_name, const unsigned int e_points): @@ -40,7 +44,6 @@ class Model : public Engine::ModelBase { unsigned int points; }; - /* Highscore */ void LoadHighscoreList (); void SaveHighscoreList (); unsigned int AddHighscoreEntry(const std::string &name, const unsigned int points); diff --git a/asteroids/ShipEntity.h b/asteroids/ShipEntity.h index 3b1ad3e..0ed1f31 100644 --- a/asteroids/ShipEntity.h +++ b/asteroids/ShipEntity.h @@ -11,7 +11,7 @@ struct ShipEntityPhysicState : public Engine::EntityPhysicState { ShipEntityPhysicState () { mType = GameEntityTypeShip; mBaseType = Engine::EntityBaseTypeActor; - + mAcceleration = 10.; mMaxSpeed = 10.; mRotationSpeed = 180.; @@ -37,6 +37,7 @@ struct ShipEntity: public Engine::EntityBase { mType = GameEntityTypeShip; mBaseType = Engine::EntityBaseTypeActor; + mAlive = true; mState = Idle; mAttackTimer = 0.; } diff --git a/asteroids/View.cc b/asteroids/View.cc index 3feaea0..d095169 100644 --- a/asteroids/View.cc +++ b/asteroids/View.cc @@ -523,17 +523,22 @@ void View::DrawUiGamePaused() { if (Engine::GUI::Button (1, "Resume Game", screen_right * 0.5 - 100, 200, button_width, button_height)) { 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); } - 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"); } } diff --git a/asteroids/View.h b/asteroids/View.h index 12f1a40..3949df2 100644 --- a/asteroids/View.h +++ b/asteroids/View.h @@ -76,8 +76,11 @@ class View : public Engine::ViewBase { return mViewStateStack.top(); } 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(); - Engine::LogDebug ("Popped ViewState top is now:%s", GetStringViewState(mViewStateStack.top())); } // \todo [high] add Resource Manager! diff --git a/engine/EngineEnums.h b/engine/EngineEnums.h index 76cb548..aadad03 100644 --- a/engine/EngineEnums.h +++ b/engine/EngineEnums.h @@ -21,7 +21,8 @@ BEGIN_ENUM(EngineStatus) DECL_ENUM_ELEMENT(EngineStatusRunning), DECL_ENUM_ELEMENT(EngineStatusStopping), DECL_ENUM_ELEMENT(EngineStatusStopped), - DECL_ENUM_ELEMENT(EngineStatusDestroying) + DECL_ENUM_ELEMENT(EngineStatusDestroying), + DECL_ENUM_LAST(EngineStatus) } END_ENUM(EngineStatus) @@ -30,7 +31,8 @@ BEGIN_ENUM(LogLevel) DECL_ENUM_ELEMENT(LogLevelDebug), DECL_ENUM_ELEMENT(LogLevelWarning), DECL_ENUM_ELEMENT(LogLevelMessage), - DECL_ENUM_ELEMENT(LogLevelError) + DECL_ENUM_ELEMENT(LogLevelError), + DECL_ENUM_LAST(LogLevel) } END_ENUM(LogLevel) @@ -38,7 +40,8 @@ BEGIN_ENUM(FontJustification) { DECL_ENUM_ELEMENT(FontJustificationRight), DECL_ENUM_ELEMENT(FontJustificationCenter), - DECL_ENUM_ELEMENT(FontJustificationLeft) + DECL_ENUM_ELEMENT(FontJustificationLeft), + DECL_ENUM_LAST(FontJustification) } END_ENUM(FontJustification) diff --git a/engine/EnumToString.h b/engine/EnumToString.h index 1a4f74c..a13e8db 100644 --- a/engine/EnumToString.h +++ b/engine/EnumToString.h @@ -15,21 +15,24 @@ * */ +#undef DECL_ENUM_LAST #undef DECL_ENUM_ELEMENT #undef BEGIN_ENUM #undef END_ENUM #ifndef GENERATE_ENUM_STRINGS + #define DECL_ENUM_LAST( ENUM_NAME ) ENUM_NAME ## Last #define DECL_ENUM_ELEMENT( element ) element #define BEGIN_ENUM( ENUM_NAME ) typedef enum tag##ENUM_NAME #define END_ENUM( ENUM_NAME ) ENUM_NAME; \ const char* GetString##ENUM_NAME(enum tag##ENUM_NAME index); \ const char* GetString##ENUM_NAME(unsigned int index); #else + #define DECL_ENUM_LAST( ENUM_NAME ) #ENUM_NAME #define DECL_ENUM_ELEMENT( element ) #element #define BEGIN_ENUM( ENUM_NAME ) const char* gs_##ENUM_NAME [] = #define END_ENUM( ENUM_NAME ) ; \ const char* GetString##ENUM_NAME(enum \ - tag##ENUM_NAME index){ return gs_##ENUM_NAME [index]; } \ - const char* GetString##ENUM_NAME(unsigned int 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){ if (index < 0 || index > ENUM_NAME ## Last) return "Unknown Enum"; return gs_##ENUM_NAME [index]; } #endif diff --git a/engine/EventBaseGlobal.h b/engine/EventBaseGlobal.h index d5becb5..c981e24 100644 --- a/engine/EventBaseGlobal.h +++ b/engine/EventBaseGlobal.h @@ -9,7 +9,12 @@ namespace Engine { bool RegisterListener (Module *listener_module, const int event_type); /** \brief Calls all event listeners to handle the events */ 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); } diff --git a/engine/Logging.cc b/engine/Logging.cc index 98e2da5..67b4014 100644 --- a/engine/Logging.cc +++ b/engine/Logging.cc @@ -80,8 +80,10 @@ void Logging::Log (LogLevel level, const char *str, ...) { mLogFileOut << "Error occured: Aborting!" << std::endl; mLogFileOut.flush(); mLogFileOut.close(); - exit (-1); } + + // we abort if there was an error + assert (level != LogLevelError); } void Logging::SetLogPrintLevel (LogLevel print_level) { diff --git a/engine/ModelBase.cc b/engine/ModelBase.cc index 4368fff..e637654 100644 --- a/engine/ModelBase.cc +++ b/engine/ModelBase.cc @@ -58,21 +58,28 @@ void ModelBase::Process () { entity_iter++; } while (entity_iter != mEntities.end()); + /* // Update the timers for (TimerIter timer_iter = mTimers.begin(); timer_iter != mTimers.end(); timer_iter++) { timer_iter->second.Update(mDeltaSec); timer_iter++; } + */ // simulate the world mPhysics->Simulate (mDeltaSec, this); - // remove killed entities - unsigned int i; - for (i = 0; i < mKilledEntities.size(); i++) - UnregisterEntity (mKilledEntities[i]); + assert (mKilledEntities.size() <= mEntities.size()); - 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) { @@ -94,10 +101,10 @@ EntityBase* ModelBase::CreateEntity (int type) { void ModelBase::RegisterEntity (EntityBase* entity) { 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 ()) { - LogError ("Replacing Entity with id '%d'", id); + LogError ("Replacing Entity with id '%u' and type '%u'", id, entity->mType); } if (entity->mPhysicState) @@ -109,14 +116,18 @@ void ModelBase::RegisterEntity (EntityBase* entity) { void ModelBase::KillEntity (const unsigned int id) { std::map::iterator iter = mEntities.find (id); + LogDebug ("Killing entity with id '%u'", id); + 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; } else { EntityBase *entity = iter->second; + LogDebug ("Entity pointer = 0x%u", entity); // call the event handler OnKillEntity (entity); + LogDebug ("Entity pointer (after kill) = 0x%u", entity); if (entity->mPhysicState) { entity->mPhysicState->mAlive = false; @@ -130,6 +141,7 @@ void ModelBase::UnregisterEntity (const unsigned int id) { std::map::iterator iter = mEntities.find (id); 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); return; } else { @@ -180,6 +192,9 @@ void ModelBase::ClearEntities () { } mEntityIdCounter = 0; + + // we alsohave to clear the vector of killed entities! + mKilledEntities.clear(); } unsigned int ModelBase::GetPlayerEntityId () { @@ -291,6 +306,7 @@ EntityPhysicState * GetEntityPhysicState (unsigned int id) { return NULL; } +/* void StartTimer(const std::string &id, float sec) { if (!ModelInstance) { LogError ("Couldn't execute GetEntity(): Model not initialized!"); @@ -306,6 +322,7 @@ bool CheckTimer(const std::string &id) { return ModelInstance->CheckTimer(id); } +*/ } diff --git a/engine/ModelBase.h b/engine/ModelBase.h index cdfff0b..4ca6dff 100644 --- a/engine/ModelBase.h +++ b/engine/ModelBase.h @@ -3,7 +3,7 @@ #include "Engine.h" #include "EntityBase.h" -#include "Timer.h" +// #include "Timer.h" namespace Engine { @@ -80,6 +80,7 @@ class ModelBase : public Module { }; unsigned int GetGameState () { return mGameState; }; + /* void StartTimer(const std::string &id, float msec) { TimerIter cur_timer = mTimers.find(id); if (cur_timer != mTimers.end()) { @@ -102,6 +103,7 @@ class ModelBase : public Module { return cur_timer->second.Query(); } + */ protected: /** \brief Initializes the system */ @@ -128,8 +130,10 @@ class ModelBase : public Module { /** \brief contains all Engine::Entities that ceased to exist */ std::vector mKilledEntities; + /* std::map mTimers; typedef std::map::iterator TimerIter; + */ unsigned int mEntityIdCounter; unsigned int mPlayerEntityId; diff --git a/engine/ModelBaseGlobal.h b/engine/ModelBaseGlobal.h index c4fc78a..3e2ca0a 100644 --- a/engine/ModelBaseGlobal.h +++ b/engine/ModelBaseGlobal.h @@ -9,11 +9,11 @@ unsigned int GetPlayerEntityId (); /** \brief Returns the duration of the frame in seconds */ float GetFrameDuration (); -/** \brief Starts a timer with the given id that expires after sec seconds */ -void StartTimer(const std::string &id, float sec); - -/** \brief Checks whether a timer expired */ -bool CheckTimer(const std::string &id); +// /** \brief Starts a timer with the given id that expires after sec seconds */ +// void StartTimer(const std::string &id, float sec); +// +// /** \brief Checks whether a timer expired */ +// bool CheckTimer(const std::string &id); }