- Home /
The question is answered, right answer was accepted
how to transfer score and time to a highscore table
so i have objects that you need to match correctly(dragging a card to the correct dropzone), once matched, i have a counter that adds the total of correct and incorrect card matches, plus there is a timer that tracks how long it takes you to match all the objects(matching mean dropping the card in the correct dropzone).
once all the items match, the timer stops, so the ingame scoreboard will show the Total correct, incorrect matches, plus the total time it took to complete.
now i want to take that data and put it on a highscore table, that shows the following: Rank(this captures 1st, 2nd, 3d, etc), Name, Incorrect matches, and Time. the rank will be based on the incorrect matches (the lower the incorrect number the higher you are on the highscore table). The next would be the time, so if two people had 0 incorrect, the one with the lower time would be higher.
can someone help me figure this out, i was trying to use playerprefs, but didnt work.
the script for time and the correct/incorrect match is below: ```
public class Timer : ScoreTextScript
{
public Text timerText;
private float startTime;
private bool timerisActive = true;
public GameObject HighScore; //HighScore table for game scores
// Start is called before the first frame update
void Start()
{
startTime = Time.time;
}
// Update is called once per frame
void Update()
{if (timerisActive == true)
{
float t = Time.time - startTime;
string minutes = ((int)t / 60).ToString();
string seconds = (t % 60).ToString("f2");
timerText.text = minutes + ":" + seconds;
}
if (correctAmount>= 100)
{
timerisActive = false;
HighScore.gameObject.SetActive(true);
```
public class ScoreTextScript : MonoBehaviour
{
Text text;
public static int correctAmount;
public static int wrongAmount;
// Start is called before the first frame update
void Start()
{
text = GetComponent<Text>();
}
// Update is called once per frame
void Update()
{
if(gameObject.tag == "Correct")
{
text.text = correctAmount.ToString();
}
}
if(gameObject.tag == "Wrong")
{
text.text = wrongAmount.ToString();
}
}
}
this is the ingame scoreboard that captures the player data. i want the data from this to transfer to the Highscore table that is triggered at the end of the game.
You may want to start by putting code in code tags so people can actually read the code. Like so:
public class Timer : ScoreTextScript
{
public Text timerText;
private float startTime;
private bool timerisActive = true;
public GameObject HighScore;
//HighScore table for game scores // Start is called before the first frame update
void Start()
{
startTime = Time.time;
}
// Update is called once per frame
void Update()
{
if (timerisActive == true)
{
float t = Time.time - startTime;
string $$anonymous$$utes = ((int)t / 60).ToString();
string seconds = (t % 60).ToString("f2");
timerText.text = $$anonymous$$utes + ":" + seconds;
}
if (correctAmount>= 100)
{ timerisActive = false;
HighScore.gameObject.SetActive(true);
Basically your gonna need a way to save Multiple
players data. This isn't too bad, gimme some time though. The second sorting by Time
if Incorrect
has multiple equal values might be a bit trickier. Actually turns out a second sort is easy. HighScoresList = HighScoresList.OrderBy(o => o.Incorrect).ThenBy(p => p.Time).ToList();
if you had a List
called HighScoresList
this would first sort by Incorrect
and then by Time
.
no problem, take your time, i really appreciate your help.
Answer by HellsHand · Apr 25, 2021 at 02:35 AM
Ok, this is what I came up with:
using System.Linq;
using System;
using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;
public class HighScoreBoard : MonoBehaviour //Placed on the ScoreBoard Panel
{
HighScoreBoardSerializer board = new HighScoreBoardSerializer();
public SaveHighScores highScores; //Drag in EventSystem into inspector
Transform scores;
public void StartGame() //Called when starting a new game, loads saved data if available, otherwise creates the following
{
scores = transform.GetChild(1); //Set the second child, Scores Empty Object, to scores
board = highScores.LoadGameData();
if(board.HighScoreList.Count == 0) //New Game, an example of how to add scores to the High Score List
{
board.HighScoreList.Add(new HighScore {
Name = "Player01", Time = 0.0f, Incorrect = 0, dateTime = DateTime.Now.ToString() });
board.HighScoreList.Add(new HighScore {
Name = "Player02", Time = 0.0f, Incorrect = 0, dateTime = DateTime.Now.ToString() });
board.HighScoreList.Add(new HighScore {
Name = "Player03", Time = 0.0f, Incorrect = 0, dateTime = DateTime.Now.ToString() });
board.HighScoreList.Add(new HighScore {
Name = "Player04", Time = 0.0f, Incorrect = 0, dateTime = DateTime.Now.ToString() });
board.HighScoreList.Add(new HighScore {
Name = "Player05", Time = 0.0f, Incorrect = 0, dateTime = DateTime.Now.ToString() });
board.HighScoreList.Add(new HighScore {
Name = "Player06", Time = 0.0f, Incorrect = 0, dateTime = DateTime.Now.ToString() });
board.HighScoreList.Add(new HighScore {
Name = "Player07", Time = 0.0f, Incorrect = 0, dateTime = DateTime.Now.ToString() });
board.HighScoreList.Add(new HighScore {
Name = "Player08", Time = 0.0f, Incorrect = 0, dateTime = DateTime.Now.ToString() });
board.HighScoreList.Add(new HighScore {
Name = "Player09", Time = 0.0f, Incorrect = 0, dateTime = DateTime.Now.ToString() });
board.HighScoreList.Add(new HighScore {
Name = "Player10", Time = 0.0f, Incorrect = 0, dateTime = DateTime.Now.ToString() });
}
}
public void SaveGame() //Called on completion of a game
{
highScores.SaveGameData(board);
}
public void DisplayScoreBoard() //Does what it says
{
board.HighScoreList = board.HighScoreList.OrderBy
(
i => i.Incorrect //First sort by Incorrect guesses
).ThenBy
(
t => t.Time //Second, sort by Time elapsed
).ThenBy
(
p => p.dateTime //Finally, sort by Date and Time completed
).ToList();
gameObject.SetActive(true);
int count = 0;
foreach (HighScore score in board.HighScoreList)
{
scores.GetChild(count).GetComponent<Text>().text =
(count + 1) + ": " + score.Name + " - " + score.Time + " - " + score.Incorrect + " - " + score.dateTime;
count++;
if(count > 9)
{
break; //Only display the top 10 scores
}
}
}
public void CloseScoreBoard() //Close Button on the ScoreBoard
{
gameObject.SetActive(false);
}
}
[Serializable]
public class HighScoreBoardSerializer
{
public List<HighScore> HighScoreList = new List<HighScore>();
}
[Serializable]
public class HighScore
{
public string Name;
public float Time;
public int Incorrect;
public string dateTime; //Added as a third check in case more than 1 player shares Incorrect and Time
}
A separate script for saving the data to file:
using UnityEngine;
using System.IO;
public class SaveHighScores : MonoBehaviour //Placed on the EventSystem
{
string GetSaveLocationPath() //Create a Path variable so we don't need to keep getting the path
{
string folder = Application.persistentDataPath;
string file = "Save.json";
string fullPath = Path.Combine(folder, file);
return fullPath;
}
public void SaveGameData(HighScoreBoardSerializer board)
{
string json = JsonUtility.ToJson(board); //Format data to json
string fullPath = GetSaveLocationPath();
if(File.Exists(fullPath))
{
Debug.Log("File Deleted");
File.Delete(fullPath); //Delete the file instead of adding to it
}
File.WriteAllText(fullPath, json);
}
public HighScoreBoardSerializer LoadGameData()
{
string fullPath = GetSaveLocationPath();
if(File.Exists(fullPath))
{
string jsonString = File.ReadAllText(fullPath);
Debug.Log("Game Loaded");
return JsonUtility.FromJson<HighScoreBoardSerializer>(jsonString);
}
else
{
Debug.Log("New Game");
return new HighScoreBoardSerializer();
}
}
}
and an example of the layout, this you will need to tweak to your needs but it shows how the Hierarchy was set up:
I'm sure there are more elegant ways of doing it but this works, feel free to ask about anything you may not understand.
One thing that will need to be done I forgot about, dateTime
is turned into a string so it can be serialized but would need to be turned back into an actual DateTime
in order to sort it correctly. It's not super important and may never be needed so I'll give you some time to try and understand how to do that. =)
You will also need to add a public
method to the HighScoreBoard
to access board
to add scores. You may also wanna convert the json data to binary so that someone can't go in and alter the scores. This guy has a really good tutorial on how to go about doing that(https://www.youtube.com/watch?v=Eb1M111xyTo), it's a bit long but very helpful. He explains what I've shown you and goes further into how to convert it into binary.
you are awesome, thank you very much for all your help, i will take what you put and try to play around with it, if i have any questions or cant get it to work, i will let you now. but again i truly appreciate all you have done.
you are a good person. :)
ok so i tried playing around with it, and i cant get what you got on your screen, i added the highscoreboard script to the scoreboard and added the save script to the eventsystem, but when i run the game i still dont get anything being added to the scoreboard, am i doing something wrong. i know i still need to add a public method to add the score once completed, but shouldnt i see something before that on the board?
Answer by Smurfj3 · Apr 24, 2021 at 01:22 AM
Alright so I don't know what you tried exactly in Playerprefs however you can also simply serialize it and save it yourself. Maybe make a class like so:
[System.Serializable]
public class HighScore
{
public string Name;
public float Time;
public int Incorrect;
}
Then after each game create a new instance of that object, fill out the properties add it to the List serialize it and save it on the harddrive. Then whenever people open the highscore board, you deserialize the list of HighScores and order them the way you like.
im not following, so i add the HighScore script to the scoreboard, then i would use time script to call up the Highscore class to add the data?
You keep a list of type HighScore somewhere. Then when a game ends you create a new instance of HighScore:
HighScore myscore = new HighScore();
myscore.name = "somename";
myscore.InCorrect = 3; //incorrect placements
myscore.Time = 25; //time it took to complete
HighScoreBoard.MyHighScoreList.Add(myscore);
//then serialize MyHighScoreList
To elaborate on that, if you then want to populate a highscore board all you got to do in your HighScoreBoard class is write a method that does something like:
List<HighScore> highscore = MyHighScoreList.OrderBy(o => o.InCorrect).ToList();
foreach(HighScore score in MyHighScoreList)
{
//Create UI element and fillout the details
txt_name = score.name;
txt_time = score.Time;
txt_incorrect = score.InCorrect;
}
Answer by HellsHand · Apr 27, 2021 at 11:26 PM
Sorry, got stuck working on my car. I'm not sure why it would give you errors. If I copy and paste the scripts from here everything works fine. The Serialized
classes should be able to remain outside of the main class. What errors does it give you?
Here we will go on from here for now.
Im going to do what you said and create a new project to easily test and see whats going on, once i complete it i will post all the errors so we can clearly see waht the issues are. give me like 15 $$anonymous$$.
ok so after i did a new project, it seems like its working, just a couple of questions.
1) the close button doesnt seem to be working correctly, if you look at the pic, the close button is added to the panel but is behind it, when i move it on the hierarchy it becomes visible, but the data is then added to the close button and not to the player text objects.
2) second question, i hit start, then show display button, then save, how do i check that the data is actually saved and will be visible to the user and not deleted?
3)if i take these scripts now and move them to my main project, how do i connect it to my timer so it captures the data once the timer stops? right now when the user goes to that scene, the timer automatically starts, and when the player matches all 100 objects correctly the timer stops, so i have a timer script, a scoretext script (counts the correct/incorrect matches), and other scripts for the dragging and dropzone.
Follow this Question
Related Questions
Calculating player distance meter? C# Unity2D 1 Answer
Gradually scale platform? 4 Answers
Ideas for Animating while Paused? 9 Answers
Why are my bullets shooting at an unpredictable rate? 3 Answers
timer that can be reset 1 Answer