previous functionality of the view restored with a few new benefits ("non-linear" menus)

main
Martin Felis (berta) 2010-11-28 00:20:58 +01:00
parent 3340471c61
commit f583cf39a8
11 changed files with 125 additions and 38 deletions

View File

@ -13,6 +13,7 @@ BEGIN_ENUM(Event)
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_ELEMENT(EventPlayerDied),
DECL_ENUM_LAST (Event) DECL_ENUM_LAST (Event)
} }
END_ENUM(Event) END_ENUM(Event)

View File

@ -60,7 +60,6 @@ int Model::OnInit (int argc, char* argv[]) {
mNewestHighscoreEntryIndex = 99999; mNewestHighscoreEntryIndex = 99999;
// initialize event handlers and register them // initialize event handlers and register them
Engine::RegisterListener (this, EventLevelComplete);
Engine::RegisterListener (this, EventGameOver); Engine::RegisterListener (this, EventGameOver);
Engine::RegisterListener (this, EventShipExplode); Engine::RegisterListener (this, EventShipExplode);
@ -82,9 +81,6 @@ bool Model::OnReceiveEvent (const Engine::EventBasePtr &event) {
case EventAccelerateStop: case EventAccelerateStop:
Engine::HaltSoundLoop("./data/sounds/thrust.wav"); Engine::HaltSoundLoop("./data/sounds/thrust.wav");
break; break;
case EventLevelComplete:
return OnLevelComplete();
break;
case EventShipExplode: case EventShipExplode:
OnShipExplode(); OnShipExplode();
break; break;
@ -354,6 +350,15 @@ int Model::DoSaveLevel (const char* filename) {
return 0; return 0;
} }
void Model::ReloadLevel () {
Engine::LogDebug ("Reloading level %d", mCurrentLevelIndex + 1);
if (mCurrentLevelIndex < 0 || mCurrentLevelIndex >= mLevelList.size())
Engine::LogError ("Invalid level index: %u", mCurrentLevelIndex);
DoLoadLevel(mLevelList[mCurrentLevelIndex].c_str());
}
void Model::ProceedToNextLevel () { void Model::ProceedToNextLevel () {
Engine::LogDebug ("Proceeding to next level %d", mCurrentLevelIndex + 1); Engine::LogDebug ("Proceeding to next level %d", mCurrentLevelIndex + 1);
mCurrentLevelIndex++; mCurrentLevelIndex++;
@ -377,24 +382,13 @@ void Model::SetGameState (const unsigned int &state) {
mGameState = state; mGameState = state;
} }
bool Model::OnLevelComplete() {
Engine::LogMessage ("Level complete!");
ProceedToNextLevel();
return true;
}
bool Model::OnGameOver() { bool Model::OnGameOver() {
ClearEntities();
Engine::LogMessage ("Points = %d lowest = %d", mPoints, mHighscoreList.back().points ); Engine::LogMessage ("Points = %d lowest = %d", mPoints, mHighscoreList.back().points );
if (mPoints > mHighscoreList.back().points) { if (mPoints > mHighscoreList.back().points) {
Engine::LogMessage ("New Highscore!"); Engine::LogMessage ("New Highscore!");
AddHighscoreEntry (mPlayerName, mPoints); AddHighscoreEntry (mPlayerName, mPoints);
} }
SetGameState(GameStatePaused);
return false; return false;
}; };
@ -403,7 +397,7 @@ void Model::OnNewGame() {
ClearEntities(); ClearEntities();
mNewestHighscoreEntryIndex = 99999; mNewestHighscoreEntryIndex = 99999;
mPlayerLives = 1; mPlayerLives = 2;
mCurrentLevelIndex = 0; mCurrentLevelIndex = 0;
mPoints = 0; mPoints = 0;
@ -414,9 +408,13 @@ void Model::OnShipExplode () {
mPlayerLives --; mPlayerLives --;
if (mPlayerLives == 0) { if (mPlayerLives == 0) {
Engine::EventBasePtr gameover_event (new Engine::EventBase()); Engine::EventBasePtr gameover_event (new Engine::EventBase());
gameover_event->mEventType = EventGameOver; gameover_event->mEventType = EventGameOver;
QueueEvent (gameover_event); QueueEvent (gameover_event);
} else {
Engine::EventBasePtr playerdied_event (new Engine::EventBase());
playerdied_event->mEventType = EventPlayerDied;
QueueEvent (playerdied_event);
} }
} }
@ -436,7 +434,9 @@ void Model::OnKillEntity (const Engine::EntityBase *entity) {
unsigned int i; unsigned int i;
const AsteroidEntity *asteroid = static_cast<const AsteroidEntity*>(entity); const AsteroidEntity *asteroid = static_cast<const AsteroidEntity*>(entity);
mPoints += 150 + asteroid->mSubAsteroidsCount * 75;
if (GetPlayerEntityId() != Engine::NullEntityId)
mPoints += 150 + asteroid->mSubAsteroidsCount * 75;
for (i = 0; i < mAsteroids.size(); i++) { for (i = 0; i < mAsteroids.size(); i++) {
if (mAsteroids.at(i) == entity->mId) { if (mAsteroids.at(i) == entity->mId) {

View File

@ -15,7 +15,6 @@ class Model : public Engine::ModelBase {
float GetWorldHeight (); float GetWorldHeight ();
/* Event handler */ /* Event handler */
bool OnLevelComplete();
bool OnGameOver(); bool OnGameOver();
/** \brief Resets values from a previous game */ /** \brief Resets values from a previous game */
void OnNewGame (); void OnNewGame ();
@ -25,6 +24,7 @@ class Model : public Engine::ModelBase {
int DoLoadLevel (const char* filename); int DoLoadLevel (const char* filename);
int DoSaveLevel (const char* filename); int DoSaveLevel (const char* filename);
void ReloadLevel();
void ProceedToNextLevel (); void ProceedToNextLevel ();
int GetPlayerLives () { return mPlayerLives; }; int GetPlayerLives () { return mPlayerLives; };
unsigned int GetPoints () { return mPoints; }; unsigned int GetPoints () { return mPoints; };

View File

@ -71,7 +71,9 @@ int View::OnInit (int argc, char* argv[]) {
Engine::RegisterListener (this, EventAccelerateStart); Engine::RegisterListener (this, EventAccelerateStart);
Engine::RegisterListener (this, EventAccelerateStop); Engine::RegisterListener (this, EventAccelerateStop);
Engine::RegisterListener (this, EventShipExplode); Engine::RegisterListener (this, EventShipExplode);
Engine::RegisterListener (this, EventPlayerDied);
Engine::RegisterListener (this, EventGameOver); Engine::RegisterListener (this, EventGameOver);
Engine::RegisterListener (this, EventLevelComplete);
PushViewState (ViewStateMainMenu); PushViewState (ViewStateMainMenu);
@ -96,19 +98,32 @@ bool View::OnReceiveEvent (const Engine::EventBasePtr &event) {
return true; return true;
break; break;
case EventLevelComplete:
PushViewState(ViewStateLevelComplete);
GetModel()->SetPlayerEntityId(Engine::NullEntityId);
break;
case EventGameOver: case EventGameOver:
mFadeTimerSecValue = 2.;
PopViewState(); PopViewState();
PushViewState(ViewStateGameOver); PushViewState(ViewStateGameOver);
GetModel()->SetGameState(GameStatePaused);
GetModel()->SetPlayerEntityId(Engine::NullEntityId);
break;
case EventPlayerDied:
mFadeTimerSecValue = 2.;
PushViewState(ViewStatePlayerDied);
GetModel()->SetPlayerEntityId(Engine::NullEntityId);
break; break;
case EventShipExplode: { case EventShipExplode: {
Engine::LogDebug ("Received Ship Explode Event: %d", event->mEventType); // This event is fired when the ship explodes. Note: this event is not
// sufficient for EventPlayerDied!
Engine::LogDebug ("Received PlayerDied Event: %d", event->mEventType);
PopViewState();
PushViewState(ViewStatePlayerDied);
GetModel()->SetGameState(GameStatePaused);
// insert sprits that contains parts of the ship // insert sprits that contains parts of the ship
Engine::EntityBase *ship_entity = Engine::GetEntity (event->mEventUnsignedInt); Engine::EntityBase *ship_entity = Engine::GetEntity (event->mEventUnsignedInt);
vector3d position = ship_entity->mPhysicState->mPosition; vector3d position = ship_entity->mPhysicState->mPosition;
@ -206,6 +221,8 @@ void View::DrawStars() {
void View::Draw() { void View::Draw() {
PreDraw(); PreDraw();
mFadeTimerSecValue -= GetModel()->GetFrameDuration();
// Actual Drawing // Actual Drawing
UpdateCamera (); UpdateCamera ();
@ -215,12 +232,11 @@ void View::Draw() {
/* /*
if (mDrawAxis) if (mDrawAxis)
DrawAxis (); DrawAxis ();
*/ */
DrawWorld (); DrawWorld ();
DrawUi (); DrawUi ();
// mOverlayManager.Draw();
// Perform post-Draw actions // Perform post-Draw actions
PostDraw(); PostDraw();
@ -499,9 +515,15 @@ void View::DrawUiGameOver() {
screen_bottom * 0.5 + 32); screen_bottom * 0.5 + 32);
} }
if (mFadeTimerSecValue > 0.)
return;
if (Engine::GUI::Button (2, "Continue...", if (Engine::GUI::Button (2, "Continue...",
(screen_right - button_width) * 0.5, (screen_right - button_width) * 0.5,
screen_bottom * 0.5 + 80, button_width, button_height)) { screen_bottom * 0.5 + 80, button_width, button_height)) {
// We do not want the background to show the remaining bits of the game
GetModel()->SetGameState(GameStatePaused);
PopViewState(); PopViewState();
PushViewState(ViewStateShowHighscore); PushViewState(ViewStateShowHighscore);
} }
@ -514,6 +536,7 @@ void View::DrawUiLevelComplete() {
if(Engine::GUI::Button (1, "Next level ...", (screen_right - button_width) * 0.5, screen_bottom * 0.5 + 60, button_width, button_height)) { if(Engine::GUI::Button (1, "Next level ...", (screen_right - button_width) * 0.5, screen_bottom * 0.5 + 60, button_width, button_height)) {
PopViewState(); PopViewState();
GetModel()->ProceedToNextLevel();
} }
} }
@ -531,8 +554,7 @@ void View::DrawUiGamePaused() {
} }
if (Engine::GUI::Button (3, "Abort Game", screen_right * 0.5 - 100, 300, button_width, button_height)) { if (Engine::GUI::Button (3, "Abort Game", screen_right * 0.5 - 100, 300, button_width, button_height)) {
while (mViewStateStack.size()) ResetViewState();
PopViewState();
PushViewState(ViewStateMainMenu); PushViewState(ViewStateMainMenu);
GetModel()->SetGameState(GameStatePaused); GetModel()->SetGameState(GameStatePaused);
@ -547,8 +569,13 @@ void View::DrawUiPlayerDied() {
DrawPageTitle ("You died!"); DrawPageTitle ("You died!");
SelectFont ("console.ttf size=23"); SelectFont ("console.ttf size=23");
if (Engine::GUI::Button (1, "Continue", screen_right * 0.5 - 100, 200, button_width, button_height)) { if (mFadeTimerSecValue > 0.)
return;
if (Engine::GUI::Button (1, "Continue", screen_right * 0.5 - 100, 380, button_width, button_height)) {
PopViewState(); PopViewState();
GetModel()->ReloadLevel();
GetModel()->SetGameState(GameStateRunning);
} }
} }
@ -593,6 +620,7 @@ void View::DrawUiHighscore() {
DrawPageTitle ("Highscores"); DrawPageTitle ("Highscores");
SelectFont ("console.ttf size=23"); SelectFont ("console.ttf size=23");
unsigned int entry_length = 32; unsigned int entry_length = 32;
float char_width, height; float char_width, height;
DrawGLStringMeasure ("M", &char_width, &height); DrawGLStringMeasure ("M", &char_width, &height);

View File

@ -20,6 +20,12 @@ struct BackgroundStar {
}; };
/** \brief Performs the actual drawing based on Camera and Model /** \brief Performs the actual drawing based on Camera and Model
*
* This View also takes care of the drawn user interface. There are different
* view states that are drawn by the member functions with signatures
* DrawUi{ViewStateName}(). Different view states can be pushed onto and
* popped from the mViewStateStack which allows non-linear arrangement
* of different ViewStates in menus.
*/ */
class View : public Engine::ViewBase { class View : public Engine::ViewBase {
public: public:
@ -59,28 +65,39 @@ class View : public Engine::ViewBase {
void DrawRocket (RocketEntity *asteroid); void DrawRocket (RocketEntity *asteroid);
void DrawShipPart (Engine::EntityBase *entity); void DrawShipPart (Engine::EntityBase *entity);
// boost::shared_ptr<MenuOverlay> mMenuOverlay;
// boost::shared_ptr<Engine::SimpleConsoleOverlay> mConsoleOverlay;
std::vector<BackgroundStar> mBackgroundStars; std::vector<BackgroundStar> mBackgroundStars;
std::vector<unsigned int> mShipPartsEntityIds; std::vector<unsigned int> mShipPartsEntityIds;
/** \brief The ViewState stack that is used for non-linear menus */
std::stack<ViewState> mViewStateStack; std::stack<ViewState> mViewStateStack;
/** \brief Pushes the given state onto mViewStateStack */
void PushViewState (const ViewState state) { void PushViewState (const ViewState state) {
Engine::LogDebug ("Pushing ViewState %s", GetStringViewState(state)); Engine::LogDebug ("Pushing ViewState %s", GetStringViewState(state));
mViewStateStack.push(state); mViewStateStack.push(state);
} }
/** \brief Returns the current ViewState */
ViewState GetViewState () { ViewState GetViewState () {
return mViewStateStack.top(); return mViewStateStack.top();
} }
/** \brief Removes the top element of the current ViewState stack */
void PopViewState () { void PopViewState () {
// Warning: you must not query for an invalid enum with // Warning: you must not query for an invalid enum with
// GetStringENUM_NAME! // GetStringENUM_NAME!
Engine::LogDebug("Popping ViewState: %s remainging: %u", GetStringViewState(mViewStateStack.top()), mViewStateStack.size()); std::string popped_name = GetStringViewState(mViewStateStack.top());
mViewStateStack.pop(); mViewStateStack.pop();
std::string current_name ("None");
if (mViewStateStack.size() > 0)
current_name = GetStringViewState(mViewStateStack.top());
Engine::LogDebug("Popped ViewState: %s current %s remaining: %u", popped_name.c_str(), current_name.c_str(), mViewStateStack.size());
}
/** \brief Removes all elements of the ViewState stack */
void ResetViewState() {
Engine::LogDebug ("Resetting ViewState stack");
while (mViewStateStack.size())
mViewStateStack.pop();
} }
// \todo [high] add Resource Manager! // \todo [high] add Resource Manager!
@ -98,6 +115,9 @@ class View : public Engine::ViewBase {
int button_width; int button_width;
int button_height; int button_height;
/// \brief can be used to perform some fading, etc.
float mFadeTimerSecValue;
virtual bool OnReceiveEvent (const Engine::EventBasePtr &event); virtual bool OnReceiveEvent (const Engine::EventBasePtr &event);
}; };

View File

@ -46,6 +46,10 @@ int main (int argc, char* argv[]) {
Engine::RunCommand ("exec asteroids.rc"); Engine::RunCommand ("exec asteroids.rc");
Engine::LogMessage("Warning: muting sound!");
Engine::SetEffectsVolume(0.);
Engine::SetMusicVolume(0.);
engine.MainLoop (); engine.MainLoop ();
SDL_WM_SetIcon(NULL,NULL); SDL_WM_SetIcon(NULL,NULL);

View File

@ -15,6 +15,7 @@
#include <queue> #include <queue>
#include <stack> #include <stack>
#include <bitset> #include <bitset>
#include <limits>
#include "Module.h" #include "Module.h"
#include "EngineEnums.h" #include "EngineEnums.h"

View File

@ -163,6 +163,9 @@ void ModelBase::UnregisterEntity (const unsigned int id) {
} }
EntityBase* ModelBase::GetEntity (const unsigned int id) { EntityBase* ModelBase::GetEntity (const unsigned int id) {
if (id == NullEntityId)
return NULL;
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 ()) {
@ -173,6 +176,9 @@ EntityBase* ModelBase::GetEntity (const unsigned int id) {
} }
unsigned int ModelBase::CreateEntityId () { unsigned int ModelBase::CreateEntityId () {
if (mEntityIdCounter == NullEntityId - 1)
LogError ("Could not create valid entity id, reached maximum value of %u", mEntityIdCounter);
return ++mEntityIdCounter; return ++mEntityIdCounter;
} }
@ -201,6 +207,10 @@ unsigned int ModelBase::GetPlayerEntityId () {
return mPlayerEntityId; return mPlayerEntityId;
} }
void ModelBase::SetPlayerEntityId(unsigned int entity_id) {
mPlayerEntityId = entity_id;
}
/** /**
* \param collision_time The time when the collision occured relative to the start of the simulation frame * \param collision_time The time when the collision occured relative to the start of the simulation frame
*/ */
@ -249,12 +259,20 @@ void ModelBase::SendEntityCollisionEvent (const unsigned int reference_entity_id
*/ */
unsigned int GetPlayerEntityId () { unsigned int GetPlayerEntityId () {
if (!ModelInstance) { if (!ModelInstance) {
LogError ("Couldn't create Entity: Model not initialized!"); LogError ("Couldn't get Player id: Model not initialized!");
} }
return ModelInstance->GetPlayerEntityId (); return ModelInstance->GetPlayerEntityId ();
} }
void SetPlayerEntityId(unsigned int entity_id) {
if (!ModelInstance) {
LogError ("Couldn't set Player id: Model not initialized!");
}
ModelInstance->SetPlayerEntityId (entity_id);
}
float GetFrameDuration () { float GetFrameDuration () {
if (!ModelInstance) { if (!ModelInstance) {
LogError ("Couldn't create Entity: Model not initialized!"); LogError ("Couldn't create Entity: Model not initialized!");

View File

@ -13,6 +13,8 @@ class Events;
class EntityFactoryBase; class EntityFactoryBase;
class OverlayManager; class OverlayManager;
const unsigned int NullEntityId = std::numeric_limits<unsigned int>::max() - 1;
struct EntityBase; struct EntityBase;
/** \brief Represents the current state of the Engine /** \brief Represents the current state of the Engine
@ -69,6 +71,11 @@ class ModelBase : public Module {
/** Returns the id of the entity the player is currently controlling */ /** Returns the id of the entity the player is currently controlling */
unsigned int GetPlayerEntityId (); unsigned int GetPlayerEntityId ();
/** \brief Assigns the player to an Entity. All controls will be redirected 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 */ /** Notifies the gamelogic of a collision event */
void SendEntityCollisionEvent (const unsigned int reference_entity_id, void SendEntityCollisionEvent (const unsigned int reference_entity_id,

View File

@ -5,6 +5,11 @@ namespace Engine {
/** \brief Adds the function callback as command for the given name*/ /** \brief Adds the function callback as command for the given name*/
unsigned int GetPlayerEntityId (); unsigned int GetPlayerEntityId ();
/** \brief Assigns the player to an Entity. All controls will be redirected 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);
/** \brief Returns the duration of the frame in seconds */ /** \brief Returns the duration of the frame in seconds */
float GetFrameDuration (); float GetFrameDuration ();

View File

@ -72,6 +72,8 @@
* todos within the code have a look at the \ref todo. * todos within the code have a look at the \ref todo.
* *
* \todo [high] Create a simple racing or asteroids game * \todo [high] Create a simple racing or asteroids game
* \todo [high] Enable saving of music and effects volume
* \todo [med] Use shared_ptr instead of raw pointers for the Entities
* \todo [med] Clear all references of EntityVisualState and EntityGameState * \todo [med] Clear all references of EntityVisualState and EntityGameState
* \todo [med] Clarify functionalities of CreateEntity, KillEntity, RegisterEntity, UnregisterEntity (which frees memory, which does only change the state of the Model?) * \todo [med] Clarify functionalities of CreateEntity, KillEntity, RegisterEntity, UnregisterEntity (which frees memory, which does only change the state of the Model?)
* \todo [med] Add basic networking * \todo [med] Add basic networking
@ -86,7 +88,8 @@
* Engine::Module::Init() * Engine::Module::Init()
* *
* Done: * Done:
* \todo [high] (11-09-2010) Since introduction of the IMGUI pressing 'space' in the menu crashes the game * \todo [high] (28-11-2010) Allow transitions when player dies
* \todo [high] (11-09-2010) Since introduction of the IMGUI pressing 'space' in the menu crashes the game
* - [high] In Physics remove dependancy on the Model to pass on collision * - [high] In Physics remove dependancy on the Model to pass on collision
* events * events
* - [high] Fix Physics bug when two actors collide actively (i.e. velocity * - [high] Fix Physics bug when two actors collide actively (i.e. velocity