来自:http://www.codeproject.com/Articles/30775/TetroGL-An-OpenGL-Game-Tutorial-in-C-for-Win32-pla
目录:
1、The High-Scores State
2、简单使用
1、The High-Scores State
This state is responsible to display the high-scores which are saved from previous games. The information is saved in a file for persistency ("HighScores.txt"). The file is not protected, so anybody can edit this file and change the high-scores. This is of course not very nice but describing ways to protect this data is outside the scope of the article. As usual, I'll first show the class declaration before going into some details:
// Specialization of the CGameState class for
// the high scores state. This displays the high
// scores (player name+score). When a new high
// score is available after a game, it lets the
// player enters his name.
class CHighScoreState : public CGameState
{
public:
~CHighScoreState();
// Sets a new score: if this score should be
// part of the high scores, the user will need
// to enter his name.
void SetNewHighScore(ULONG ulNewHighScore)
{ m_ulNewHighScore = ulNewHighScore; }
// Implementation of specific events
void OnKeyDown(WPARAM wKey);
void OnChar(WPARAM wChar);
void Draw();
void EnterState();
static CHighScoreState* GetInstance(CStateManager* pManager);
protected:
CHighScoreState(CStateManager* pManager);
private:
// Saves the current high scores
void SaveScores();
// Adds a new score in the high-score table and
// insert it at the correct location.
void AddNewScore(const std::string& strName, ULONG ulScore);
// High-score data: score and player name.
struct HighScoreData
{
std::string strPlayer;
ULONG ulScore;
// We have to sort in decreasing order, so the <
// operator returns the opposite.
bool operator< (const HighScoreData& other)
{
if (this->ulScore > other.ulScore)
return true;
return false;
}
};
// The new high-score, if any.
ULONG m_ulNewHighScore;
// Mode in which the user has to enter his name.
bool m_bEnterName;
// Char array containing the name currently being entered.
char m_pCurrentName[26];
// The index of the next char to be entered.
int m_iNameIndex;
CGameFont* m_pFont;
typedef std::vector<HighScoreData> THighScoreTable;
// The high-score table.
THighScoreTable m_vecHighScores;
// The background and title images.
TImagePtr m_pBackgroundImg;
TImagePtr m_pTitleImg;
// The image of the entries background
TImagePtr m_pEntriesBckgndImg;
// The 'Enter name' image and the background.
TImagePtr m_pEnterNameImg;
TImagePtr m_pEnterNameBackImg;
};
The class overrides the
EnterState
function, it is used to read the high-scores from the file and check if a new high-score should be added in the table:
void CHighScoreState::EnterState()
{
// Clear the high-score table
m_vecHighScores.clear();
ifstream inputFile("HighScores.txt");
if (inputFile.fail())
{
if (m_ulNewHighScore)
m_bEnterName = true;
return;
}
// Read all entries from the file
while (!inputFile.eof())
{
HighScoreData newScore;
inputFile >> newScore.strPlayer >> newScore.ulScore;
m_vecHighScores.push_back(newScore);
}
// Sort the table
sort(m_vecHighScores.begin(), m_vecHighScores.end());
// Check if we have a new high-score that should be
// added in the table. If yes, m_bEnterName is set
// to true.
ULONG lastScore = 0;
if (m_vecHighScores.size())
lastScore = m_vecHighScores[m_vecHighScores.size()-1].ulScore;
if (m_ulNewHighScore && m_ulNewHighScore>lastScore)
m_bEnterName = true;
}
When reading the file, we sort the high-scores using the
std::sort
function. For that purpose, we should provide an
operator<
for our structure. The
std::sort
function sorts the elements in ascending order, that's the reason our operator returns the opposite of what is excepted (so that all elements are ordered in the opposite order). When characters are inserted by the user, the
OnChar
function is called. If the
m_bEnterName
flag is true, characters will be added to the
m_pCurrentName
array, until the user presses enter. In that case, the
AddNewScore
function is called:
void CHighScoreState::AddNewScore(const std::string& strName, ULONG ulScore)
{
// Create a new high-score and push it into the table
HighScoreData newData;
newData.strPlayer = strName;
newData.ulScore = ulScore;
m_vecHighScores.push_back(newData);
// Sort the table
sort(m_vecHighScores.begin(), m_vecHighScores.end());
// If too much elements, remove the last one.
while (m_vecHighScores.size() > 10)
m_vecHighScores.pop_back();
SaveScores();
}
The
SaveScores
is called at the end to save the new high scores in the file:
void CHighScoreState::SaveScores()
{
// Create the file
ofstream outputFile("HighScores.txt");
if (outputFile.fail())
return;
// Write all the entries in the file.
THighScoreTable::iterator iter = m_vecHighScores.begin();
for (iter; iter != m_vecHighScores.end(); iter++)
{
outputFile << iter->strPlayer << " " << iter->ulScore;
}
}
In normal mode (when the name is not entered), the user can exit the high-score state and return to the main menu by pressing enter or escape.
//原文 end
2、简单使用
void CMenuState::SelectionChosen()
{
switch (m_iCurrentSelection)
{
//...
case 2:
ChangeState(CHighScoreState::GetInstance(m_pStateManager));
break;
//...
}
}
void CPlayState::OnKeyDown(WPARAM wKey)
{
switch (wKey)
{
//...
case VK_RETURN:
if (m_bGameOver)
{
CHighScoreState* pHighScores =
CHighScoreState::GetInstance(m_pStateManager);
pHighScores->SetNewHighScore(m_ulCurrentScore);
ChangeState(pHighScores);
}
}
}