Apologies I am a newbie, ill try to explain as best as I can. Im creating a game for a university assignment. My game is a maths game that asks the user maths questions, they get a point for answering correctly and lose a life for answering incorrectly. I have created the game over multiple forms namely: Main Menu, Game (actual game), Rules and Leaderboard. My question focuses on the game and leaderboard forms. The two inputs the user give are their 'usernames' as a string input and the amount of points they get once they finish a round of answering questions as a interger input.
I am attempting to display the 'Username' and 'Score' on a listbox (leaderboard) permanetly so that if multiple players play, they can compare scores when opening the leaderboard at any time (leaderboard does not need to keep its data if the program is stopped and started again, only the data it acquires while its running). At the moment, once a player has finished their round, the leaderboard pops up and displays the information correctly, but when the player goes back to main menu and reopens the leaderboard or plays another round, the leaderboard is empty again, as if the array had cleaned itself.
I managed to succesfully keep the data in the listbox when I use one form only for the inputs, array and listbox, the issue comes in when trying to do it over two different forms, in my case, the inputs (name and score) are inputted on the game form, then are transferred over to the leaderboard form and stored in an array. The array is then displayed to the listbox output for the leaderboard.
Example of what I would like: Player 1 plays 1 round and gets a score of 7. This is outputted to the listbox leaderboard as follows:
Username: Player 1 | Score: 7
Player 2 proceeds to play 1 round and gets a score of 9. Then the listbox leaderboard is as follows:
Username: Player 2 | Score: 9
Username: Player 1 | Score: 7
etc. At the moment, the usernames and scores are displayed on the leaderboard the first time the player views it which is right after their round. Then when the player closes the leaderboard it gets deleted/refreshed off the leaderboard so that the leaderboard is empty which is not what I want.
Things to note:
Hope that was clear enough. Any help would be greatly appreciated :)
My code sofar is as follows: Leaderboard code:
namespace Educational_Boardgame_Group_Assignment
{ public partial class Leaderboard : Form { //Variables string userName; int userScore;
public Leaderboard()
{
InitializeComponent();
}
public Leaderboard(string nameValue, int numValue)
{
InitializeComponent();
this.nameValue = nameValue;
this.scoreValue = numValue;
}
public string nameValue { get; set; }
public int scoreValue { get; set; }
//Back to main menu method
private void btnMainMenu_Click(object sender, EventArgs e)
{
//Closes Leaderboard Form
this.Close();
}
//Loads users name and score from the game they played
private void Leaderboard_Load(object sender, EventArgs e)
{
//Variables
string[] Username = new string[20];
int[] Score = new int[20];
int index = 0;
//Input
userName = nameValue;
userScore = scoreValue;
//Process | Displays user's name and score from the array within it is stored.
if (index < Username.Length && index < Score.Length)
{
Username[index] = userName;
Score[index] = userScore;
lstHighScoreOutput.Items.Add("Username: " + Username[index] + " Score: " + Score[index]);
}
}
}
}
Game Code (Acquiring Username):
//Variable
bool boolTryAgain = false;
//Process | Dialog Pop-Up Box for username entry by user in order to save their highscore
do
{
//Variable
userName = UserPopUpBox.GetUserInput("Enter your name below:", "Username Entry");
//Process
if (userName == "")
{
DialogResult dialogResult = MessageBox.Show("You did not enter anything. Try again?", "Error", MessageBoxButtons.YesNo);
if (dialogResult == DialogResult.Yes)
{
boolTryAgain = true; //will reopen the dialog for user to input text again
}
else if (dialogResult == DialogResult.No)
{
//exit/cancel
MessageBox.Show("Your highscore will not be saved.");
boolTryAgain = false;
}//end if
}
else
{
if (userName == "cancel")
{
MessageBox.Show("Your highscore will not be saved.");
}
else
{
MessageBox.Show("Your username is: '" + userName + "'");
}
}
} while (boolTryAgain == true);
Game Code (Acquiring User Score):
//Process | Determines whether user input is correct. Displays specific output based on user input.
int userEntered = Convert.ToInt32(txtAnswer.Text);
if (userEntered == total)
{
lblStatus.Text = "Correct!";
lblStatus.ForeColor = Color.Lime;
score += 1;
lblScore.Text = "Score: " + score;
SetUpGame();
}
else
{
lblStatus.Text = "Incorrect!";
lblStatus.ForeColor = Color.Red;
lives -= 1;
lblLives.Text = "Lives: " + lives;
SetUpGame();
}
Game Code (Sending data to the leaderboard form):
//Process | If user answers incorrectly 3 times, game ends and output displayed.
if (lives == 0)
{
this.Close();
MessageBox.Show("You have run out of lives! \nYour final score is: " + score);
//Shows user score on leaderboard
Leaderboard frm3 = new Leaderboard(userName, score);
frm3.ShowDialog();
}
Welcome to managing state in an application!
A couple things to point out first (some you already know):
Leaderboard
has nameValue
and scoreValue
as public properties so that they are accessible outside of the Leaderboard
class and are available to the rest of the class (like it's methods etc).string[] Username
and int[] Score
are scoped to the Leaderboard_Load
method. That is, these variable exist during the method's execution and no where else. You can't access these variables in btnMainMenu_Click
, for example.Username
and Scrore
, but is then loaded into lstHighScoreOutput
. Once that method finishes, Username
and Scrore
are removed from memory. So the only place where your data is actually present once the UI is loaded, is in the UI component of lstHighScoreOutput
.Leaderboard
closes, it disposes (clears out of memory) all of it's referenced components, including lstHighScoreOutput
. So at that point, the data is removed from memory, which is why when you open the UI again, you don't see previous values.So what you want is the data to exist and be managed outside of the Leaderboard
UI, because this is state for your game. Ok so you don't need it to persist between runs, that's fine. But you want it to be available no matter how many times you run the game portion and show the leaderboard.
A simple place to put this is in your main/calling window (probably your main menu in this case). So you store the data there, update it
OR
A more 'correct' way of storing leaderboard data is in it's own class, one that holds both score and user arrays. Then you're not passing 2 arrays around the place, you just pass the leaderboard instance.
public class LeaderboardData
{
public string[] UserNames { get; set; }
public int[] UserScores { get; set; }
}
You can even take this further with the Singleton Pattern. This is a special design pattern which lets your class only ever have once instance. With a singleton LeaderboardData, you don't even need to pass references to the class. It will hold onto and look after it's own data for the lifetime of your running game. This is the approach I would take.