5SD033 High Score Screen and Issues

This week will focus on one of the harder (to me) things to implement about our game: The High Score Screen. The screen itself was just another state to implement, but actually creating a list of scores and names that updated accordingly and displayed appropriately even after alterations was a challenge. It is not yet complete, requiring help by other coders to finish.

BlogHigh
The current version of the high score screen, sans input

First on the agenda was deciding what format to use to save the scores to. The first suggestion me and fellow coder Adrian decided to go with was a .txt file, with input and output regulated by Regular Expressions http://www.cplusplus.com/reference/regex/ and streamed by the standard library inputstream class. However, while reading from such a file worked well enough, via using codes from http://regexr.com/ , writing to the file did not produce desired results. Changes did not write to file as it should, with syntax breaking and the format of the document becoming unreadable by the expressions we had written. After several attempts to alter the Regular Expressions used, this attempt was scrapped in favor of the current method, that of using json (also known as JavaScript Object Notation) files. More information on json can be found here http://www.json.org/

Now that we had a new format, we needed to load our base high score information from said file. As luck would have it , jsons are loaded the same way a text file would be, via ifstream:


scoreFile.open("../assets/Score.json"); //scoreFile is an ifstream instance
nlohmann::json scorejson;
if (scoreFile.is_open())
{
while (!scoreFile.eof())
{
try
{
scoreFile >> scorejson;
}
catch (std::exception& e)
{
printf("Exception: %sn", e.what());
}
}
scoreFile.close();
}

After this was done, we needed a way to set up and display the SF::Text instances required to show off each entry in the scores. At first, a for loop was set up to go through every instance of an array of structs, each holding two Text instances linked to an achieved score and the name attached to it. At every iteration, a position, color and font had to be set, as there is no default font in SFML 2.0 . A string also had to be set for each Text, and updated when there was a new entry in the high score .

However, doing things that way meant each element in the array then had to be updated and the final entry removed when a new score was achieved. The array was changed to a vector instead, and the vector function insert used to update the list automatically.


//Here the code goes through the file, loads each instance of names and scores, sets up a new Text file for each and adds them to the scorePos struct. The numbers array is filled with the numbers displayed next to each position of scores, 1-10.

if (scoreFont.loadFromFile("../assets/arial.ttf"))
{
auto it = scorejson["scores"].begin();
for (int i=0; i < std::min(10, static_cast(scorejson["scores"].size())); i++)
{
try
{
std::string name = (*it)["name"].get();
std::string score = (*it)["score"].get();
sf::Text naming;
sf::Text scoring;
naming.setString(name);
scoring.setString(score);
scorePosition scorePos;
scorePos = { naming,scoring };
scores.push_back(scorePos);
numbers[i].setString(std::to_string(i + 1));
}


//Goes through the score entries, updating a position counter. When an entered score is higher than the one in the iterator, set a font and position for a new text, a bool that lets players enter a score to true during the game update, and save the current position.

auto iter = scorejson["scores"].begin();
int position = 0;
while (iter !=scorejson["scores"].end())
{
if (calculatedScore > std::stoi((*iter)["score"].get()))
{
youGotScore.setFont(scoreFont);
youGotScore.setColor(sf::Color(0, 0, 0));
youGotScore.setPosition(138, 150);
enteringScore = true;
positioncounter = position;

(*iter)["score"] = nlohmann::json::number_integer_t(calculatedScore);
break;
}
position++;
iter++;

After that, we arrive at the point where the code needs alteration. Right now, what is supposed to happen is that the player gets to enter a string of characters as their name, and that gets saved to the appropriate position. This does happen, but the characters are not displayed properly, possibly because of an issue with the font or how unicode is handled.


if (enteringScore)
{
if (keyEvent.key.code == sf::Keyboard::BackSpace)
{
nameEntry.erase(nameEntry.getSize() - 1);
youGotScore.setString(nameEntry);
}
else if (keyEvent.key.code == sf::Keyboard::Return)
{
youGotScore.setString(nameEntry);

scorePosition scorePos;
sf::Text naming;
sf::Text scoring;
naming.setColor(sf::Color(0, 0, 0));
naming.setFont(scoreFont);
naming.setPosition(numbers[positioncounter].getPosition());
naming.setString(nameEntry);
scoring.setString(std::to_string(calculatedScore));
scorePos = {naming,scoring };
scores.insert(scores.begin() + positioncounter,scorePos);
nlohmann::json scoreJson;
scoreJson["scores"].array();
for (int i = 0; i < 10; i++)
{
scoreJson["scores"][i]["name"] = scores[i].name.getString();
scoreJson["scores"][i]["score"] = scores[i].score.getString();
}
std::ofstream scoreFile;
scoreFile.open("../assets/Score.json");
scoreFile.clear();
scoreFile << scoreJson.dump();
scoreFile.close();

enteringScore = false;
} else if (nameEntry.getSize()<=18)
{
nameEntry += static_cast(keyEvent.text.unicode);
youGotScore.setString(nameEntry);
}

And that does it for this week. The code still needs changing, perhaps a great deal to ensure the score currently on display updates properly (as it is now, the code does not update the displayed text in the correct position, as the strings are cut off after the 9th entry).

About Karl Malm

2015 Programming