#ifndef _MODELBASE_H #define _MODELBASE_H #include "Engine.h" #include "EntityBase.h" namespace Engine { class Module; class PhysicsBase; class Events; class EntityFactoryBase; class OverlayManager; const unsigned int NullEntityId = std::numeric_limits::max() - 1; struct EntityBase; struct Timer { Timer() : mRunning(false), mCurrentValue(0.) {} Timer (float sec_value) : mRunning(true), mCurrentValue (sec_value) {} Timer (const Timer& timer) : mRunning (timer.mRunning), mCurrentValue (timer.mCurrentValue) {} Timer& operator= (const Timer& timer) { if (this != &timer) { mRunning = timer.mRunning; mCurrentValue = timer.mCurrentValue; } return *this; } void Set (float sec_value) { mCurrentValue = sec_value; } float Get () { return mCurrentValue; } bool Query() { if (mCurrentValue <= 0.) return true; return false; } void Start() { mRunning = true; } void Pause() { mRunning = false; } bool Update(float sec_value) { if (mRunning) mCurrentValue -= sec_value; return Query(); } bool mRunning; float mCurrentValue; }; /** \brief Represents the current state of the Engine * * Represents the State of the Engine and is unaware of anything except itself. * It manages all Entities, Physics, etc. * * It has the following subsystems: * - Events * - Physics * - Variables * * \note * To create an Entity one must call Engine::CreateEntity() which will * allocate the Entity and performs all the required registrations by calling * Model::RegisterEntity(). */ class ModelBase : public Module { public: /** Performs simulation, gamelogic, etc */ virtual void Process (); /** Updates the timer */ void UpdateTimer () { static float last_frame = 0; float current_frame = static_cast (SDL_GetTicks ()) * 1.0e-3; mDurationApplicationStart = current_frame; mDeltaSec = current_frame - last_frame; last_frame = current_frame; UpdateTimers (mDeltaSec); } float GetFrameDuration () { return mDeltaSec; } float GetDurationApplicationStart () { return mDurationApplicationStart; } /** Adds the given Entity to the Model */ void RegisterEntity (EntityBase *entity); /** Removes the Entity with the given id */ void UnregisterEntity (const unsigned int id); /** Marks an Engine::Entity as killed so that it gets removed after the * simulation */ void KillEntity (const unsigned int id); /** Creates an Entity of the given type * * This calls the CreateEntity() function on the Model::mEntityFactory to * create the proper Entity and registers it to the required submodules * (so far only Model::mPhysics). */ EntityBase* CreateEntity (int type); /** Returns the Entity with the given id */ EntityBase* GetEntity (const unsigned int id); /** Returns the Entity at the given world coordinates */ EntityBase* GetEntityAt (const vector3d &pos); EntityBaseIter GetEntityIterBegin () { return mEntities.begin(); } EntityBaseIter GetEntityIterEnd() { return mEntities.end(); } /** Returns a unused id for an Entity */ unsigned int CreateEntityId (); /** Removes all Entities */ void ClearEntities (); /** Returns the id of the entity the player is currently controlling */ unsigned int GetPlayerEntityId (); /** \brief Assigns the player to an Entity. All controls will be redirected * \brief to that player * * This can be used to disable the controls of of the player by assinging * the special entity id of NullEntityId */ void SetPlayerEntityId(unsigned int entity_id); /** Notifies the gamelogic of a collision event */ void SendEntityCollisionEvent (const unsigned int reference_entity_id, const unsigned int incidence_entity_id, float collision_time, vector3d point, vector3d normal); virtual void SetGameState (const unsigned int &state) { mLastGameState = mGameState; mGameState = state; }; unsigned int GetGameState () { return mGameState; }; void StartTimer(const std::string &id, float sec) { TimerIter cur_timer = mTimers.find(id); if (cur_timer != mTimers.end()) { cur_timer->second.Set(sec); cur_timer->second.Start(); return; } mTimers[id] = Timer(sec); assert (mTimers.size() > 0); } bool CheckTimer(const std::string &id) { TimerIter cur_timer = mTimers.find(id); if (cur_timer == mTimers.end()) { return true; } return cur_timer->second.Query(); } float GetTimer (const std::string &id) { TimerIter cur_timer = mTimers.find(id); if (cur_timer == mTimers.end()) { return 0.; } return cur_timer->second.Get(); } void PauseTimers () { for (TimerIter iter = mTimers.begin(); iter != mTimers.end(); iter++) { iter->second.Pause(); } } void ResumeTimers () { for (TimerIter iter = mTimers.begin(); iter != mTimers.end(); iter++) { iter->second.Start(); } } void UpdateTimers (float sec) { TimerIter iter = mTimers.begin(); while (iter != mTimers.end()) { bool timer_running = iter->second.Update(sec); if (timer_running) { LogDebug ("Erasing expired timer %s", iter->first.c_str()); mTimers.erase(iter++); } else ++iter; } } protected: /** \brief Initializes the system */ virtual int OnInit (int argc, char* argv[]); /** \brief Destroys the system (must be called!) */ virtual void OnDestroy (); /** \brief Gets called when an entity of the given type is being created */ virtual void OnCreateEntity (const int type, const unsigned int id) {}; /** \brief Gets called when an entity is marked to be killed */ virtual void OnKillEntity (const EntityBase *entity) {}; PhysicsBase *mPhysics; Events *mEvents; /** \brief Creates Entities */ EntityFactoryBase *mEntityFactory; /** \brief contains all Engine::Entities */ std::map mEntities; typedef std::map::iterator EntityIter; /** \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; unsigned int mGameState; unsigned int mLastGameState; float mDeltaSec; float mDurationApplicationStart; friend class ViewBase; friend class OverlayManager; friend class Engine; friend class Controller; }; /** \brief Creates an Entity of the given type and registers at the required modules * * * It allocates the memory needed to represent that specific type of Entity. * At also performs the required registrations at the various Modules. * * All Entities that are created with this function get also destroyed in * Model::Destroy () by calling DestroyEntity () for this Entity. * * \note All Entities must be created with this function if you intend to keep * the different Modules in sync! */ EntityBase * CreateEntity (int type); /** \brief Frees the Memory required by the Entity and unregisters it * * This function also frees the memory the Entity is using in its * different representitions such as EntityVisualState and EntityPhysicState. * * It also unregisters the Entity from the different Modules where it was * registered by CreateEntity. */ void DestroyEntity (unsigned int id); /** \brief Tells the model that the entity is no more existant in the game * world */ void KillEntity (unsigned int id); /** \brief Returns the Entity with the given id, NULL otherwise */ EntityBase * GetEntity (unsigned int id); /** \brief Returns the physical state of the Entity with the given id, NULL otherwise */ EntityPhysicState * GetEntityPhysicState (unsigned int id); } #endif // _MODEL_H