started to work on the highscore
parent
a9ffd12b43
commit
38096a4502
|
@ -26,6 +26,7 @@ BEGIN_ENUM(GameState)
|
|||
DECL_ENUM_ELEMENT(GameStatePaused),
|
||||
DECL_ENUM_ELEMENT(GameStatePlayerDied),
|
||||
DECL_ENUM_ELEMENT(GameStateLevelComplete),
|
||||
DECL_ENUM_ELEMENT(GameStateShowHighscore),
|
||||
DECL_ENUM_ELEMENT(GameStateGameOver)
|
||||
}
|
||||
END_ENUM(GameState)
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
#ifndef ASTEROIDSEVENTS_H
|
||||
#define ASTEROIDSEVENTS_H
|
||||
|
||||
#include "EnumToString.h"
|
||||
|
||||
namespace asteroids {
|
||||
|
@ -7,9 +10,12 @@ BEGIN_ENUM(Event)
|
|||
DECL_ENUM_ELEMENT(EventAccelerateStart),
|
||||
DECL_ENUM_ELEMENT(EventAccelerateStop),
|
||||
DECL_ENUM_ELEMENT(EventLevelComplete),
|
||||
DECL_ENUM_ELEMENT(EventGameOver),
|
||||
DECL_ENUM_ELEMENT(EventShipExplode)
|
||||
}
|
||||
END_ENUM(Event)
|
||||
|
||||
}
|
||||
|
||||
#endif /* ASTEROIDSEVENTS_H */
|
||||
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
#ifndef MENUOVERLAY
|
||||
#define MENUOVERLAY
|
||||
|
||||
namespace Engine {
|
||||
class OverlayBase;
|
||||
}
|
||||
|
||||
#include "OverlayBase.h"
|
||||
#include "Sprite.h"
|
||||
|
||||
namespace asteroids {
|
||||
|
||||
class Model;
|
||||
class View;
|
||||
|
||||
class MenuOverlay : public Engine::OverlayBase {
|
||||
public:
|
||||
MenuOverlay () {
|
||||
};
|
||||
virtual void Init ();
|
||||
virtual ~MenuOverlay() {};
|
||||
|
||||
virtual bool OnKeyDown (const SDL_keysym &keysym);
|
||||
virtual void Draw ();
|
||||
|
||||
void DrawGameOverScreen ();
|
||||
void DrawGameMenu();
|
||||
void DrawGameLevelComplete ();
|
||||
void DrawGamePaused ();
|
||||
void DrawGameRunning ();
|
||||
void DrawPlayerDied ();
|
||||
|
||||
void SetModel (Model *model) { mModel = model; };
|
||||
void SetView (View *view) { mView = view; };
|
||||
|
||||
private:
|
||||
Model *mModel;
|
||||
View *mView;
|
||||
Engine::Sprite mShipSprite;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* MENUOVERLAY */
|
|
@ -23,6 +23,8 @@ static Model* ModelInstance = NULL;
|
|||
int Model::OnInit (int argc, char* argv[]) {
|
||||
int result = Engine::ModelBase::OnInit (argc, argv);
|
||||
|
||||
Engine::LogMessage ("Model Initialization!");
|
||||
|
||||
ModelInstance = this;
|
||||
|
||||
mGameState = GameStateMainMenu;
|
||||
|
@ -30,14 +32,38 @@ int Model::OnInit (int argc, char* argv[]) {
|
|||
|
||||
/// \TODO use <optional> or similar for initialization of mCurrentLevelIndex
|
||||
mCurrentLevelIndex = 99999;
|
||||
mNewestHighscoreEntryIndex = 99999;
|
||||
|
||||
if (InitLevelList() == 0)
|
||||
Engine::LogError ("No levels found!");
|
||||
|
||||
// First we reset the highscore list
|
||||
mHighscoreList.clear();
|
||||
// then we try to load values from the file
|
||||
LoadHighscoreList();
|
||||
|
||||
// if we have less than the usual number of entries we add default values
|
||||
if (mHighscoreList.size() < 10) {
|
||||
AddHighscoreEntry ("Imperator", 1000000);
|
||||
AddHighscoreEntry ("Darth Vader", 800000);
|
||||
AddHighscoreEntry ("Luke Skywalker", 600000);
|
||||
AddHighscoreEntry ("Han Solo", 400000);
|
||||
AddHighscoreEntry ("Princess Leia", 200000);
|
||||
AddHighscoreEntry ("C3PO", 100000);
|
||||
AddHighscoreEntry ("R2-D2", 50000);
|
||||
AddHighscoreEntry ("Chewy", 10000);
|
||||
AddHighscoreEntry ("Mr. Ewok", 5000);
|
||||
AddHighscoreEntry ("Jabba the Hutt", 1000);
|
||||
}
|
||||
|
||||
// initialize event handlers and register them
|
||||
mLevelCompleteEventHandler = new LevelCompleteEventHandler (this);
|
||||
Engine::RegisterListener (mLevelCompleteEventHandler, EventLevelComplete);
|
||||
|
||||
Engine::LogMessage ("Model Initialization!");
|
||||
mGameOverEventHandler = new GameOverEventHandler (this);
|
||||
Engine::RegisterListener (mGameOverEventHandler, EventGameOver);
|
||||
|
||||
mPlayerName = "Player";
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -55,18 +81,19 @@ void Model::Process () {
|
|||
Engine::LogDebug ("Switching from %s->%s", GetStringGameState(mLastGameState), GetStringGameState(mGameState));
|
||||
|
||||
if (mLastGameState == GameStateMainMenu && mGameState == GameStateRunning) {
|
||||
mPlayerLives = 3;
|
||||
mCurrentLevelIndex = 0;
|
||||
mPoints = 0;
|
||||
DoLoadLevel (mLevelList[mCurrentLevelIndex].c_str());
|
||||
OnNewGame();
|
||||
}
|
||||
else if (mLastGameState == GameStateRunning && mGameState == GameStatePlayerDied) {
|
||||
mPlayerLives --;
|
||||
|
||||
ClearEntities();
|
||||
|
||||
if (mPlayerLives == 0)
|
||||
mGameState = GameStateGameOver;
|
||||
if (mPlayerLives == 0) {
|
||||
Engine::EventBasePtr gameover_event (new Engine::EventBase());
|
||||
gameover_event->mEventType = EventGameOver;
|
||||
QueueEvent (gameover_event);
|
||||
//mGameState = GameStateGameOver;
|
||||
}
|
||||
}
|
||||
else if (mLastGameState == GameStateLevelComplete && mGameState == GameStateRunning) {
|
||||
mCurrentLevelIndex++;
|
||||
|
@ -82,14 +109,11 @@ void Model::Process () {
|
|||
ClearEntities();
|
||||
|
||||
// ... and we have to set the last game state to the current gamestate
|
||||
// otherwise we end up in an infinit loop of performing the switching
|
||||
// otherwise we end up in an infinite loop of performing the switching
|
||||
// action.
|
||||
mLastGameState = mGameState;
|
||||
}
|
||||
|
||||
void DoLoadLevel (unsigned int level_index) {
|
||||
}
|
||||
|
||||
unsigned int Model::InitLevelList () {
|
||||
const char* level_dir_name = "./data/levels/";
|
||||
Engine::LogDebug ("Searching for levels in %s", level_dir_name);
|
||||
|
@ -123,6 +147,97 @@ unsigned int Model::InitLevelList () {
|
|||
return mLevelList.size();
|
||||
}
|
||||
|
||||
void Model::LoadHighscoreList () {
|
||||
Engine::LogDebug ("Loading highscore file");
|
||||
boost::filesystem::path highscore_file("./highscore.dat");
|
||||
|
||||
// if the file does not exist, we create it and write standard values into
|
||||
// it.
|
||||
if (!boost::filesystem::exists(highscore_file))
|
||||
return;
|
||||
|
||||
if (!boost::filesystem::is_regular_file(highscore_file)) {
|
||||
Engine::LogError ("Could not load highscore file: %s is not a regular file!", highscore_file.filename().c_str());
|
||||
}
|
||||
|
||||
std::ifstream score_stream (highscore_file.filename().c_str());
|
||||
while (!score_stream.eof()) {
|
||||
std::string name;
|
||||
unsigned int points;
|
||||
|
||||
std::string line;
|
||||
getline (score_stream, line);
|
||||
|
||||
std::string::size_type delimiter = line.find ('\t');
|
||||
if (delimiter == std::string::npos)
|
||||
break;
|
||||
|
||||
name = line.substr(0, delimiter);
|
||||
|
||||
std::istringstream points_stream(line.substr(delimiter + 1, line.size()));
|
||||
points_stream >> points;
|
||||
|
||||
Engine::LogDebug ("Read Highscore Entry Name: %s Points: %d", name.c_str(), points);
|
||||
AddHighscoreEntry (name, points);
|
||||
}
|
||||
}
|
||||
|
||||
void Model::SaveHighscoreList () {
|
||||
std::ofstream highscore_file ("./highscore.dat");
|
||||
|
||||
std::list<HighscoreEntry>::iterator iter = mHighscoreList.begin();
|
||||
|
||||
while (iter != mHighscoreList.end()) {
|
||||
highscore_file << iter->name << "\t" << iter->points << std::endl;
|
||||
iter++;
|
||||
}
|
||||
|
||||
highscore_file.close();
|
||||
}
|
||||
|
||||
bool highscore_cmp (Model::HighscoreEntry a, Model::HighscoreEntry b) {
|
||||
return a.points > b.points;
|
||||
}
|
||||
|
||||
/** \brief Addes an entry to the highscore list and takes care that the list stays valid
|
||||
*
|
||||
* \TODO Re-think usage of mNewestHighscoreEntryIndex variable in this function
|
||||
*/
|
||||
unsigned int Model::AddHighscoreEntry(const std::string &name, const unsigned int points) {
|
||||
HighscoreEntry entry;
|
||||
entry.name = name;
|
||||
entry.points = points;
|
||||
|
||||
unsigned int counter = 0;
|
||||
std::list<HighscoreEntry>::iterator iter = mHighscoreList.begin();
|
||||
while (iter != mHighscoreList.end()) {
|
||||
if (points >= iter->points) {
|
||||
mHighscoreList.insert (iter, entry);
|
||||
mNewestHighscoreEntryIndex = counter;
|
||||
break;
|
||||
}
|
||||
iter++;
|
||||
counter ++;
|
||||
}
|
||||
|
||||
if (mHighscoreList.size() < 10) {
|
||||
mHighscoreList.push_back(entry);
|
||||
mNewestHighscoreEntryIndex = mHighscoreList.size();
|
||||
return mHighscoreList.size();
|
||||
}
|
||||
|
||||
while (mHighscoreList.size() > 10) {
|
||||
mHighscoreList.pop_back();
|
||||
}
|
||||
|
||||
if (counter < 10)
|
||||
return counter;
|
||||
|
||||
mNewestHighscoreEntryIndex = 99999;
|
||||
|
||||
return 99999;
|
||||
}
|
||||
|
||||
int Model::DoLoadLevel (const char* filename) {
|
||||
Engine::LogMessage ("Loading level from %s", filename);
|
||||
std::fstream level_file (filename, std::ios::in);
|
||||
|
@ -235,6 +350,27 @@ bool Model::OnLevelComplete() {
|
|||
} else {
|
||||
SetGameState (GameStateLevelComplete);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Model::OnGameOver() {
|
||||
Engine::LogMessage ("Points = %d lowest = %d", mPoints,mHighscoreList.back().points );
|
||||
if (mPoints > mHighscoreList.back().points) {
|
||||
Engine::LogMessage ("New Highscore!");
|
||||
AddHighscoreEntry (mPlayerName, mPoints);
|
||||
}
|
||||
SetGameState(GameStateGameOver);
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
void Model::OnNewGame() {
|
||||
mNewestHighscoreEntryIndex = 99999;
|
||||
mPlayerLives = 1;
|
||||
mCurrentLevelIndex = 0;
|
||||
mPoints = 0;
|
||||
DoLoadLevel (mLevelList[mCurrentLevelIndex].c_str());
|
||||
}
|
||||
|
||||
void Model::OnCreateEntity (const int type, const unsigned int id) {
|
||||
|
@ -265,7 +401,6 @@ void Model::OnKillEntity (const Engine::EntityBase *entity) {
|
|||
Engine::EventBasePtr level_complete_event (new Engine::EventBase());
|
||||
level_complete_event->mEventType = EventLevelComplete;
|
||||
TriggerEvent (level_complete_event);
|
||||
// SetGameState (GameStateLevelComplete);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,13 +13,35 @@ class Model : public Engine::ModelBase {
|
|||
int DoLoadLevel (const char* filename);
|
||||
int DoSaveLevel (const char* filename);
|
||||
bool OnLevelComplete();
|
||||
bool OnGameOver();
|
||||
/** \brief Resets values from a previous game */
|
||||
void OnNewGame ();
|
||||
|
||||
int GetPlayerLives () { return mPlayerLives; };
|
||||
unsigned int GetPoints () { return mPoints; };
|
||||
std::string GetPlayerName() { return mPlayerName; };
|
||||
void SetPlayerName(const std::string &name) { mPlayerName = name; };
|
||||
|
||||
float GetWorldWidth ();
|
||||
float GetWorldHeight ();
|
||||
|
||||
struct HighscoreEntry {
|
||||
HighscoreEntry(): name ("unknown"), points (0) { };
|
||||
HighscoreEntry (const char *e_name, const unsigned int e_points):
|
||||
name (e_name), points (e_points) { };
|
||||
|
||||
std::string name;
|
||||
unsigned int points;
|
||||
};
|
||||
|
||||
/* Highscore */
|
||||
void LoadHighscoreList ();
|
||||
void SaveHighscoreList ();
|
||||
unsigned int AddHighscoreEntry(const std::string &name, const unsigned int points);
|
||||
bool HighscoreCmp (HighscoreEntry a, HighscoreEntry b);
|
||||
std::list<HighscoreEntry> mHighscoreList;
|
||||
unsigned int mNewestHighscoreEntryIndex;
|
||||
|
||||
protected:
|
||||
/** \brief Initializes the system */
|
||||
virtual int OnInit (int argc, char* argv[]);
|
||||
|
@ -27,7 +49,9 @@ class Model : public Engine::ModelBase {
|
|||
Engine::ModelBase::OnDestroy();
|
||||
mAsteroids.clear();
|
||||
mLevelList.clear();
|
||||
SaveHighscoreList();
|
||||
delete mLevelCompleteEventHandler;
|
||||
delete mGameOverEventHandler;
|
||||
};
|
||||
virtual void OnRegisterCommands ();
|
||||
|
||||
|
@ -42,8 +66,9 @@ class Model : public Engine::ModelBase {
|
|||
|
||||
int mPlayerLives;
|
||||
unsigned int mPoints;
|
||||
std::vector<std::string> mLevelList;
|
||||
unsigned int mCurrentLevelIndex;
|
||||
std::string mPlayerName;
|
||||
std::vector<std::string> mLevelList;
|
||||
|
||||
/* event handler class definitions */
|
||||
class LevelCompleteEventHandler : public Engine::EventListenerBase {
|
||||
|
@ -57,8 +82,20 @@ class Model : public Engine::ModelBase {
|
|||
Model *mModel;
|
||||
};
|
||||
|
||||
class GameOverEventHandler : public Engine::EventListenerBase {
|
||||
public:
|
||||
explicit GameOverEventHandler (Model *view) : mModel (view) {};
|
||||
virtual bool HandleEvent (const Engine::EventBasePtr &event) const {
|
||||
return mModel->OnGameOver();
|
||||
}
|
||||
private:
|
||||
GameOverEventHandler() {};
|
||||
Model *mModel;
|
||||
};
|
||||
|
||||
/* event handler member variables */
|
||||
LevelCompleteEventHandler *mLevelCompleteEventHandler;
|
||||
GameOverEventHandler *mGameOverEventHandler;
|
||||
|
||||
friend class View;
|
||||
};
|
||||
|
|
|
@ -37,6 +37,9 @@ bool MainMenuOverlay::OnKeyDown (const SDL_keysym &keysym) {
|
|||
case SDLK_RETURN:
|
||||
GetModel()->SetGameState(GameStateRunning);
|
||||
return true;
|
||||
case SDLK_h:
|
||||
GetModel()->SetGameState(GameStateShowHighscore);
|
||||
return true;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
|
@ -408,4 +411,124 @@ void PlayerDiedOverlay::Draw () {
|
|||
|
||||
};
|
||||
|
||||
/**********************
|
||||
*
|
||||
* Highscore
|
||||
*
|
||||
**********************/
|
||||
|
||||
void HighscoreOverlay::Init () {
|
||||
}
|
||||
|
||||
bool HighscoreOverlay::OnKeyDown (const SDL_keysym &keysym) {
|
||||
switch (keysym.sym) {
|
||||
case SDLK_ESCAPE:
|
||||
case SDLK_RETURN:
|
||||
// If we just entered a new entry we simply show the highscore table,
|
||||
// otherwise we switch back to the main menu
|
||||
if (GetModel()->mNewestHighscoreEntryIndex < GetModel()->mHighscoreList.size()) {
|
||||
GetModel()->mNewestHighscoreEntryIndex = GetModel()->mHighscoreList.size();
|
||||
SDL_EnableUNICODE(-1);
|
||||
SDL_EnableKeyRepeat(0,100);
|
||||
|
||||
return true;
|
||||
}
|
||||
GetModel()->SetGameState(GameStateMainMenu);
|
||||
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void HighscoreOverlay::Draw () {
|
||||
glClearColor (0., 0., 0., 1.);
|
||||
|
||||
right = static_cast<float> (Engine::GetWindowWidth());
|
||||
bottom = static_cast<float> (Engine::GetWindowHeight());
|
||||
|
||||
// we switch to orthographic projection and draw the contents of the 2d
|
||||
// overlay on top of the previous drawings
|
||||
glMatrixMode (GL_PROJECTION);
|
||||
glPushMatrix ();
|
||||
glLoadIdentity ();
|
||||
|
||||
// first we have to get the size of the current viewport to set up the
|
||||
// orthographic projection correctly
|
||||
GLint viewport[4];
|
||||
glGetIntegerv(GL_VIEWPORT, viewport);
|
||||
gluOrtho2D (viewport[0], viewport[2], viewport[3], viewport[1]);
|
||||
|
||||
glMatrixMode (GL_MODELVIEW);
|
||||
glPushMatrix ();
|
||||
glLoadIdentity ();
|
||||
|
||||
GetView()->SelectFont("console.ttf");
|
||||
float x = right * 0.5 - 100;
|
||||
float y = bottom * 0.5 - 8 - 128;
|
||||
|
||||
// then we do the drawings
|
||||
Engine::DrawGLString ( x, y, "A s t e r o i d s");
|
||||
y += 30;
|
||||
Engine::DrawGLString ( x, y, "Highscore");
|
||||
|
||||
y += 30;
|
||||
std::list<Model::HighscoreEntry>::iterator highscore_iter = GetModel()->mHighscoreList.begin();
|
||||
|
||||
GetView()->SetFontJustification(Engine::FontJustificationLeft);
|
||||
|
||||
unsigned int entry_length = 32;
|
||||
|
||||
unsigned int i = 0;
|
||||
while (highscore_iter != GetModel()->mHighscoreList.end()) {
|
||||
// compute the number of digits
|
||||
unsigned int digits = 1;
|
||||
unsigned int temp_val = highscore_iter->points;
|
||||
while (temp_val > 0) {
|
||||
temp_val /= 10;
|
||||
digits ++;
|
||||
}
|
||||
|
||||
// output of the name
|
||||
std::ostringstream out_stream;
|
||||
out_stream << highscore_iter->name;
|
||||
|
||||
// add dots to fill the line
|
||||
temp_val = entry_length - out_stream.str().size() - digits;
|
||||
for (temp_val; temp_val > 0; temp_val--) {
|
||||
out_stream << ".";
|
||||
}
|
||||
out_stream << highscore_iter->points;
|
||||
|
||||
// Check whether we have to highlight an entry (such as when entering
|
||||
// the name)
|
||||
if (GetModel()->mNewestHighscoreEntryIndex < GetModel()->mHighscoreList.size()
|
||||
&& GetModel()->mNewestHighscoreEntryIndex == i) {
|
||||
GetView()->SetFontColor (224./255., 200/255., 0.);
|
||||
Engine::DrawGLString ( x, y, out_stream.str().c_str());
|
||||
GetView()->SetFontColor (1., 1., 1.);
|
||||
} else {
|
||||
Engine::DrawGLString ( x, y, out_stream.str().c_str());
|
||||
}
|
||||
|
||||
// go down one line
|
||||
y += 16;
|
||||
|
||||
i++;
|
||||
highscore_iter++;
|
||||
}
|
||||
|
||||
Engine::DrawGLString ( x + 16, y + 16, "Press [Return] to continue.");
|
||||
|
||||
|
||||
glPopMatrix ();
|
||||
|
||||
glMatrixMode (GL_PROJECTION);
|
||||
glPopMatrix ();
|
||||
|
||||
glMatrixMode (GL_MODELVIEW);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -91,6 +91,18 @@ class PlayerDiedOverlay : public Engine::OverlayBase {
|
|||
virtual void Draw ();
|
||||
};
|
||||
|
||||
class HighscoreOverlay : public Engine::OverlayBase {
|
||||
public:
|
||||
HighscoreOverlay () {
|
||||
};
|
||||
virtual ~HighscoreOverlay() {};
|
||||
|
||||
virtual void Init ();
|
||||
|
||||
virtual bool OnKeyDown (const SDL_keysym &keysym);
|
||||
virtual void Draw ();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* USERINTERFACE */
|
||||
|
|
|
@ -36,6 +36,7 @@ int View::OnInit (int argc, char* argv[]) {
|
|||
Engine::OverlayBasePtr level_complete_overlay (new LevelCompleteOverlay);
|
||||
Engine::OverlayBasePtr game_paused_overlay (new GamePausedOverlay);
|
||||
Engine::OverlayBasePtr player_died_overlay (new PlayerDiedOverlay);
|
||||
Engine::OverlayBasePtr highscore_overlay (new HighscoreOverlay);
|
||||
|
||||
mOverlayManager.Register (menu_overlay, GameStateMainMenu);
|
||||
mOverlayManager.Register (game_running_overlay, GameStateRunning);
|
||||
|
@ -43,6 +44,7 @@ int View::OnInit (int argc, char* argv[]) {
|
|||
mOverlayManager.Register (game_over_overlay, GameStateGameOver);
|
||||
mOverlayManager.Register (player_died_overlay, GameStatePlayerDied);
|
||||
mOverlayManager.Register (game_paused_overlay, GameStatePaused);
|
||||
mOverlayManager.Register (highscore_overlay, GameStateShowHighscore);
|
||||
|
||||
mOverlayManager.InitOverlays();
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <queue>
|
||||
#include <bitset>
|
||||
|
|
Loading…
Reference in New Issue