Pubnub null reference exception in unity - c#

I am trying to get my leaderboard working in unity using pubnub. I tried to follow and alter this tutorial but when I run it in unity, nothing shows up:
In my code, the only thing that's different from the tutorial is the publish key and subscribe key, where I set to my own one.
this is the screenshot of the keys:
this is the screenshot of the storage and playback setting:
this is the screenshot of the pubnub function setting, it says "it's automatically set to on when a module is running":
this is the screenshot of the only module in the app:
this is my code, nothing is print to the console when I tried to set usernames and scores(see comment below):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using PubNubAPI;
using UnityEngine.UI;
using SimpleJSON;
public class MyClass
{
public string username;
public string score;
public string refresh;
}
public class leaderboard : MonoBehaviour
{
public static PubNub pubnub;
public Text Line1;
public Text Line2;
public Text Line3;
public Text Line4;
public Text Line5;
public Text Score1;
public Text Score2;
public Text Score3;
public Text Score4;
public Text Score5;
public Button SubmitButton;
public InputField FieldUsername;
public InputField FieldScore;
//public static leaderboard instance;
//public Object[] tiles = {}
// Use this for initialization
void Start()
{
Button btn = SubmitButton.GetComponent<Button>();
btn.onClick.AddListener(TaskOnClick);
// Use this for initialization
PNConfiguration pnConfiguration = new PNConfiguration();
pnConfiguration.PublishKey = "pub-c-450b-redacted";
pnConfiguration.SubscribeKey = "sub-c-03aa-redacted";
pnConfiguration.LogVerbosity = PNLogVerbosity.BODY;
pnConfiguration.UUID = Random.Range(0f, 999999f).ToString();
pubnub = new PubNub(pnConfiguration);
Debug.Log(pnConfiguration.UUID);
MyClass fireRefreshObject = new MyClass();
fireRefreshObject.refresh = "new user refresh";
string firerefreshobject = JsonUtility.ToJson(fireRefreshObject);
pubnub.Fire() // This will trigger the leaderboard to refresh so it will display for a new user.
.Channel("submit_score")
.Message(firerefreshobject)
.Async((result, status) =>
{
if (status.Error)
{
Debug.Log(status.Error);
Debug.Log(status.ErrorData.Info);
}
else
{
Debug.Log(string.Format("Fire Timetoken: {0}", result.Timetoken));
}
});
pubnub.SubscribeCallback += (sender, e) =>
{
SubscribeEventEventArgs mea = e as SubscribeEventEventArgs;
if (mea.Status != null)
{
}
if (mea.MessageResult != null)
{
Dictionary<string, object> msg = mea.MessageResult.Payload as Dictionary<string, object>;
string[] strArr = msg["username"] as string[];
string[] strScores = msg["score"] as string[];
int usernamevar = 1;
//setting usernames, nothing is printed to the console
foreach (string username in strArr)
{
string usernameobject = "Line" + usernamevar;
GameObject.Find(usernameobject).GetComponent<Text>().text = usernamevar.ToString() + ". " + username.ToString();
usernamevar++;
Debug.Log(username);
}
//setting scores, nothing is printed to the console
int scorevar = 1;
foreach (string score in strScores)
{
string scoreobject = "Score" + scorevar;
GameObject.Find(scoreobject).GetComponent<Text>().text = "Score: " + score.ToString();
scorevar++;
Debug.Log(score);
}
}
if (mea.PresenceEventResult != null)
{
Debug.Log("In Example, SusbcribeCallback in presence" + mea.PresenceEventResult.Channel + mea.PresenceEventResult.Occupancy + mea.PresenceEventResult.Event);
}
};
pubnub.Subscribe()
.Channels(new List<string>() {
"leaderboard_scores"
})
.WithPresence()
.Execute();
//TaskOnClick();
}
public void TaskOnClick()
{
var usernametext = FieldUsername.text;// this would be set somewhere else in the code
var scoretext = FieldScore.text;
MyClass myObject = new MyClass();
myObject.username = FieldUsername.text;
myObject.score = FieldScore.text;
string json = JsonUtility.ToJson(myObject);
pubnub.Publish()
.Channel("submit_score")
.Message(json)
.Async((result, status) =>
{
if (!status.Error)
{
Debug.Log(string.Format("Publish Timetoken: {0}", result.Timetoken));
}
else
{
Debug.Log(status.Error);
Debug.Log(status.ErrorData.Info);
}
});
//Output this to console when the Button is clicked
Debug.Log("You have clicked the button!");
}
}
If there are any other things you would need to know, please let me know.
Sorry for my English. Thanks in advance.

Related

Syncing Text using PUN in Unity

I'm making a simple Word Builder type of game (where one player enters a word, and the other player enters a word starting with the last letter of the first player's word), and I can't get the Text to show up on both the screens.
I'm able to get the text to show up if I hard code it, like:
[PunRPC]
public void DisplayWord ()
{
MainWord.text = "Word";
}
But I can't get it to display the word a player just entered to both screens, I thought this code would word:
[PunRPC]
public void DisplayWord ()
{
MainWord.text = UsedString;
//UsedString is the word the (one of the) players just entered.
}
Any help would be greatly appreciated, thank you so much!
Here's the full code for entering a word:
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine;
using Photon.Pun;
public class DictionaryScript : MonoBehaviourPunCallbacks
{
List<string> DictA = new List<string> () {
"a",
"aa",
"aaa",
"aah",
"aahed",
"aahing",
"aahs",
"aal",
"aalii",
"aaliis",
"aals",
"aam",
"aani",
"aardvark",
"aardvarks",
"aardwolf",
"aardwolves",
"aargh",
"aaron",
"aaronic",
"aaronical",
"aaronite",
"aaronitic",
"aarrgh",
"aarrghh",
"aaru",
"aas",
"aasvogel",
"aasvogels"};
public List<string> DictAUsed = new List<string>() { };
public string UsedString;
public string NewString;
public InputField inputField;
public Text AddedWord;
public Text MainWord;
public Text TurnText;
public Text ConnectedText;
public Button StartButton;
public Canvas OverlayCanvas;
// Start is called before the first frame update
public void Awake()
{
if (PhotonNetwork.IsMasterClient)
{
StartButton.enabled = true;
OverlayCanvas.enabled = true;
}
else
{
StartButton.enabled = false;
OverlayCanvas.enabled = true;
}
}
void Start()
{
if (PhotonNetwork.InRoom)
{
ConnectedText.text = "Connected!";
}
}
public void StartGame ()
{
photonView.RPC("CanvasDisplay", RpcTarget.All);
}
public void MyWord (string newWord)
{
string newString = newWord.ToLower();
print(newString);
if (DictA.Contains(newString) && newString[0] == MainWord.text[0] && !DictAUsed.Contains(newString))
{
UsedString = newString;
Debug.Log(UsedString);
photonView.RPC("OnInput", RpcTarget.All);
}
else
{
print("This word does not exist!");
AddedWord.text = newString + " is not a valid word!";
}
inputField.text = "";
}
[PunRPC]
public void OnInput ()
{
DictAUsed.Add(UsedString);
AddedWord.text = "The word was: " + UsedString;
photonView.RPC("DisplayWord", RpcTarget.All);
}
[PunRPC]
public void DisplayWord ()
{
MainWord.text = UsedString;
//UsedString is the word the (one of the) players just entered.
}
[PunRPC]
public void CanvasDisplay()
{
//string Alphabet = "abcdefghijklmnopqrstuvwxyz";
string Alphabet = "aaaaaaaaaaaaaaaaaaaaaaaaaa";
MainWord.text = Alphabet[Random.Range(0, 25)].ToString();
StartButton.enabled = false;
OverlayCanvas.enabled = false;
}
}
I only have words starting with 'aa' for now, I'll add all the words once I can get it working.
UsedString is not synchronized in your network => Each player might have a different value for UsedWorld at the moment the RPC get called.
Why not pass on the UsedWord as argument to OnInput and DisplayWord?
Also why is DisplayWord even called via RPC at all? Since OnInput is alreay synchronized to ALL you could simply call the method right away
...
photonView.RPC(nameof(OnInput), RpcTarget.All, UsedWord);
...
[PunRPC]
public void OnInput (string usedString)
{
DictAUsed.Add(usedString);
AddedWord.text = "The word was: " + usedString;
// since this shall happen on any client as well
// why even call it via RPC?
// OnInput is called on ALL anyway so just do it right away
DisplayWord(usedString);
}
public void DisplayWord (string usedString)
{
MainWord.text = usedString;
}

Is there a way to save data from an array into a text file

I am making a quiz with both unity and c#. At the end there is a survey with toggle questions and an in input field and I am using arrays to save the data from the survey. Is there any way I can take the whatever I store in my array and put it in a text file so I can open it later?
Here is my code for the survey:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class UIScript07 : MonoBehaviour
{
public GameObject[] questionGroupArr;
public QAClass07[] qaArr;
public GameObject AnwerPanel;
void Start()
{
qaArr = new QAClass07[questionGroupArr.Length];
}
void Update()
{
}
public void SubmitAnswer()
{
for (int i = 0; i < qaArr.Length; i++)
{
qaArr[i] = ReadQuestionAndAnswer(questionGroupArr[i]);
}
}
QAClass07 ReadQuestionAndAnswer(GameObject questionGroup)
{
QAClass07 result = new QAClass07();
GameObject q = questionGroup.transform.Find("Question").gameObject;
GameObject a = questionGroup.transform.Find("Answer").gameObject;
result.Question = q.GetComponent<Text>().text;
if (a.GetComponent<InputField>() != null)
{
result.Answer = a.transform.Find("Text").GetComponent<Text>().text;
}
else if (a.GetComponent<InputField>()== null)
{
string s = "";
int counter = 0;
for (int i = 0; i < a.transform.childCount; i++)
{
if (a.transform.GetChild(i).GetComponent<Toggle>().isOn)
{
if (counter != 0)
{
s = s + ",";
}
s = s + a.transform.GetChild(i).Find("Label").GetComponent<Text>().text;
counter++;
}
if (i == a.transform.childCount - 1)
{
s = s + ".";
}
}
result.Answer = s;
}
return result;
}
[System.Serializable]
public class QAClass07
{
public string Question = "";
public string Answer = "";
}
}
You can save your array data as json object and save it as text file.
If you want your custom classes to save to json too, you should add **[System.Serializable] which you added already. Then for saving any serialized object you can create a serialized class that you can add every variable. Here is sample workflow.
[Serializable]
public class SaveObject
{
public GameObject[] questionGroup;
public string playerName;
public QAClass07[] qaArr;
public GameObject AnswerPanel;
}
[System.Serializable]
public class QAClass07
{
public string Question = "";
public string Answer = "";
}
public void Save()
{
var saveObject = new SaveObject()
{
AnswerPanel = GetAnswerPanel(),
playerName = GetPlayerName(),
qaArr = GetqaArr,
questionGroup = GetquestionGroup
};
string saveText = JsonUtility.ToJson(saveObject);
File.WriteAllText(Application.persistentDataPath + "/SAVES/save.txt", saveText);
}
public void LoadQ()
{
if (File.Exists(Application.persistentDataPath + "/SAVES/save.txt"))
{
isLoading = true;
string saveText = File.ReadAllText(Application.persistentDataPath + "/SAVES/save.txt");
var saveObject = JsonUtility.FromJson<SaveObject>(saveText);
// You can load back all objects from saveObject in same way. Load and Get methods are random. You get the point
LoadAnswerPanel(saveObject.AnswerPanel);
}
}
The reason there is a class named SaveObject is collecting all data in one class and save to json and load it back from json easily.

Need help understanding why data is being removed from all my lists

I currently have questions and answers being loaded in from a .json file into unity and then this data is placed inside a unansweredquestions list which then when a new question is generated it removes the current question being displayed. however, it also removes the data main list where the information is loaded in to. The code below is what is used to do this:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using UnityEngine.UI;
public class QuestionHandler : MonoBehaviour
{
[SerializeField] public Text questionText;
[SerializeField] public Text answerAText;
[SerializeField] public Text answerBText;
[SerializeField] public Text answerCText;
[SerializeField]
private QuestionData _QuestionData = new QuestionData();
public static List<Question> unansweredQuestions;
private Question currentQuestion;
private QuestionData questionData;
public void SaveIntoJson()
{
string question = JsonUtility.ToJson(_QuestionData, true);
System.IO.File.WriteAllText(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Desktop) + "/QuestionGameData/QuestionData.json", question);
Debug.Log(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Desktop) + "/QuestionGameData/QuestionData.json");
}
// Start is called before the first frame update
void Start()
{
if(!Directory.Exists(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Desktop) + "/QuestionGameData"))
{
Directory.CreateDirectory(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Desktop) + "/QuestionGameData");
File.Create(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Desktop) + "/QuestionGameData/QuestionData.json");
SaveIntoJson();
}
Load();
Debug.Log(_QuestionData.questions[0].questionName);
//if the unansweredQuestion list has no data or all the questions have been removed it will copy in the data from the _QuestionData list
if (unansweredQuestions == null || unansweredQuestions.Count == 0)
{
Debug.Log("No questions present loading in saved data");
unansweredQuestions = _QuestionData.questions;
}
Debug.Log(unansweredQuestions[0].questionName);
SetCurrentQuestion();
}
// Update is called once per frame
void Update()
{
}
public void SetCurrentQuestion()
{
int randomQuestionIndex = Random.Range(0, unansweredQuestions.Count);
currentQuestion = unansweredQuestions[randomQuestionIndex];
questionText.text = currentQuestion.questionName;
answerAText.text = currentQuestion.answerA;
answerBText.text = currentQuestion.answerB;
answerCText.text = currentQuestion.answerC;
}
public void SetNewCurrentQuestion()
{
if (unansweredQuestions == null || unansweredQuestions.Count <= 0)
{
Debug.Log("No more questions left in the list!");
_QuestionData = questionData;
}
else
{
//removes current question from the list so no question comes up twice
unansweredQuestions.Remove(currentQuestion);
//randomly picks a new question out the remaining questions
int randomQuestionIndex = Random.Range(0, unansweredQuestions.Count);
currentQuestion = unansweredQuestions[randomQuestionIndex];
questionText.text = currentQuestion.questionName;
answerAText.text = currentQuestion.answerA;
answerBText.text = currentQuestion.answerB;
answerCText.text = currentQuestion.answerC;
Debug.Log(_QuestionData.questions.Count);
Debug.Log(unansweredQuestions.Count);
}
}
void Load()
{
string filePath = System.IO.Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Desktop) + "/QuestionGameData/QuestionData.json");
string data = System.IO.File.ReadAllText(filePath);
questionData = JsonUtility.FromJson<QuestionData>(data);
Debug.Log("Got Data!");
//sets the loaded questiondata into the game question list
_QuestionData = questionData;
}
private void OnApplicationQuit()
{
//SaveIntoJson();
}
}
//format of the questions within the game
[System.Serializable]
public class QuestionData
{
public List<Question> questions = new List<Question>();
}
[System.Serializable]
public class Question
{
public string questionName;
public string answerA;
public bool isA;
public string answerB;
public bool isB;
public string answerC;
public bool isC;
}
Shows the main unity screen with the question data down the left side:
Any help understanding this would be great I've tried using debug.log to see what's going on but I cannot work it out.
You are doing
unansweredQuestions = _QuestionData.questions;
So after this line both fields point to the same list reference. => When you later remove the question via
unansweredQuestions.Remove(currentQuestion);
This item is removed from the _QuestionData.questions since it is the same list.
To avoid that you rather should create and work on a copy of the list instead like
unansweredQuestions = new List<Question>(_QuestionData.questions);
Then for the saving you would probably want to only keep the unansweredQuestions except for the first time
public void SaveIntoJson(bool overwriteWithUnanswered = true)
{
if(overwriteWithUnanswered) _QuestionData.questions = unansweredQuestions;
var question = JsonUtility.ToJson(_QuestionData, true);
System.IO.File.WriteAllText(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Desktop) + "/QuestionGameData/QuestionData.json", question);
Debug.Log(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Desktop) + "/QuestionGameData/QuestionData.json");
}
And pass in false only the first time in `Start
if(!Directory.Exists(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Desktop) + "/QuestionGameData"))
{
Directory.CreateDirectory(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Desktop) + "/QuestionGameData");
File.Create(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Desktop) + "/QuestionGameData/QuestionData.json");
SaveIntoJson(false);
}
Two further notes:
In general for filepaths you should always use Path.Combine instead of manually concatenate + "/"
you should store the path once instead of all the time getting it again and again
private readonly string filePath = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Desktop), "QuestionGameData", "QuestionData.json");
and then simply re-use it everywhere like e.g in
public void SaveIntoJson(bool overwriteWithUnanswered = true)
{
if(overwriteWithUnanswered) _QuestionData.questions = unansweredQuestions;
var question = JsonUtility.ToJson(_QuestionData, true);
Debug.Log(filePath);
System.IO.File.WriteAllText(filePath, questions);
}
Because it is a reference copy. Create a new list
//sets the loaded questiondata into the game question list
_QuestionData.questions = new List<Question>(questionData);
List<Question> mainlist = new List<Question>();
List<Question> sublist = new List<Question>();
Question current;
[System.Serializable]
public class Question
{
public string questionName;
public string answerA;
public bool isA;
public string answerB;
public bool isB;
public string answerC;
public bool isC;
public override string ToString()
{
return $"Question {questionName} = Answer {answerA} ";
}
}
public void Load() {
mainlist = new List<Question>() {
new Question(){questionName="Question A",answerA="A" },
new Question(){questionName="Question B",answerA="B" },
new Question(){questionName="Question C",answerA="C" },
new Question(){questionName="Question D",answerA="D" },
};
// sublist = mainlist; if you uncommment these you will get the same behavior you have.
sublist = new List<Question>(mainlist); ///Do these in order to avoid reference problems
}
public void showList(List<Question> sublist)
{
foreach (var item in sublist)
{
Console.WriteLine(item);
}
}
public void showList()
{
showList(mainlist);
showList(sublist);
}
public void SetCurrentQuestion()
{
int randomQuestionIndex = new Random().Next(0, mainlist.Count);
current = mainlist[randomQuestionIndex];
}
public void Remove()
{
sublist.Remove(current);
}
static void Main(string[] args)
{
var p = new Program();
p.Load();
p.SetCurrentQuestion();
p.Remove();
p.showList();
Console.WriteLine("Hello World!");
}
}

UI Not Loading When Using While In Foreach Loop

I am making a program which you can create and load in a flashcard pack using csv files. When a csv file is chosen it opens other UI with the question, answer and image for a flashcard and will keep on looping until all the flashcards in the pack are gone through using a foreach loop.
However the foreach loop would keep on looping without the user pressing the next button. To fix this I did:
while (Continue() == false) { } //this is at the end of the foreach loop
}
}
private bool Continue()
{
if (btn_NextFlashcard_WasClicked) return true;
Application.DoEvents();
Thread.Sleep(250);
Application.DoEvents();
return false;
}
private bool btn_NextFlashcard_WasClicked;
private void btn_NextFlashcard_Click(object sender, EventArgs e)
{
btn_NextFlashcard_WasClicked = true;
}
This fixed the problem of it looping again without the button for the next flashcard being pressed but now it doesn't even open the second UI for me to press the next flashcard button.
How would I fix this? Any help would be greatly appreciated.
Code for foreach loop:
public void ReadFlashcardPack(string file)
{
var records = engine.ReadFile(file);
foreach (var record in records)
{
Console.WriteLine("New foreach loop");
lblQuestion.Text = record.question;
lblAnswer.Text = record.answer;
lblAnswer.Visible = false;
btn_NextFlashcard_WasClicked = false;
//check if there is an image
if (record.image == "FALSE")
{
Image.Hide();
}
else
{
Image.Show();
Image.Image = Properties.Resources.test_image;
}
while (Continue() == false) { }
}
}
The records also come from a class: [DelimitedRecord(",")]
public class FlashcardPack
{
public string question;
public string answer;
public string image;
}
And then a new instance of FileHelpers engine is made private FileHelperEngine<FlashcardPack> engine = new FileHelperEngine<FlashcardPack>(); to read the csv file and every time the foreach loop loops record.question, record.answer and record.image changes depending on what line the loop is on.
One idea that comes to mind is to store the list of records outside of the method, keep track of the next record that should be read, and modify the method to just read the next record.
Then, in your click event, you can just call the method again until all records have been read.
private string filePath = #"f:\private\temp\temp.csv"; // Use your file path here
private List<FlashcardPack> records;
private int nextRecord;
public void ReadNextRecord()
{
if (records == null)
{
records = engine.ReadFile(filePath).ToList();
nextRecord = 0;
}
else if (nextRecord >= records.Count)
{
// Do something when all records have been read
nextRecord = 0;
}
// Get next record and increment our variable
var record = records[nextRecord++];
lblQuestion.Text = record.question;
lblAnswer.Text = record.answer;
lblAnswer.Visible = false;
btn_NextFlashcard_WasClicked = false;
//check if there is an image
if (record.image == "FALSE")
{
Image.Hide();
}
else
{
Image.Show();
Image.Image = Properties.Resources.test_image;
}
}
private void btn_NextFlashcard_Click(object sender, EventArgs e)
{
ReadNextRecord();
}
Here's a working sample that uses the concept above which might help you get your code working, since I can't see your whole project:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private List<Flashcard> flashcards;
private int nextRecord;
// Use a valid path on your system here (the file doesn't need to exist)
private const string FilePath = #"f:\public\temp\temp.csv";
private void LoadFlashcards()
{
flashcards = Engine.ReadFile(FilePath);
nextRecord = 0;
}
public void DisplayNextFlashcard()
{
if (flashcards == null)
{
LoadFlashcards();
}
else if (nextRecord >= flashcards.Count)
{
// Do something when all records have been read
nextRecord = 0;
}
var flashcard = flashcards[nextRecord++];
lblQuestion.Text = flashcard.Question;
lblAnswer.Visible = false;
lblAnswer.Text = flashcard.Answer;
Image.Visible = flashcard.Image;
Image.Image = Properties.Resources.FlashcardImage;
}
private void btn_NextFlashcard_Click(object sender, EventArgs e)
{
DisplayNextFlashcard();
}
}
class Flashcard
{
public string Question { get; set; }
public string Answer { get; set; }
public bool Image { get; set; }
public static Flashcard Parse(string csvLine)
{
if (csvLine == null) throw new ArgumentNullException(nameof(csvLine));
var parts = csvLine.Split(',').Select(item => item.Trim()).ToList();
if (parts.Count != 3) throw new FormatException(
"csvLine does not contain 3 comma-separated items.");
return new Flashcard
{
Question = parts[0],
Answer = parts[1],
Image = !parts[2].Equals("FALSE", StringComparison.OrdinalIgnoreCase)
};
}
}
class Engine
{
public static List<Flashcard> ReadFile(string filePath)
{
if (filePath == null) throw new ArgumentNullException(nameof(filePath));
if (!File.Exists(filePath)) CreateFile(filePath);
return File.ReadAllLines(filePath).Select(Flashcard.Parse).ToList();
}
private static void CreateFile(string filePath)
{
File.CreateText(filePath).Close();
File.WriteAllText(filePath,
"What is more useful when it is broken?, An egg, TRUE\n" +
"What belongs to you but other people use it more?, Your name, FALSE\n" +
"I have three eyes all in a row. When the red one opens " +
"no one can go. What am I?, A traffic light, TRUE");
}
}

Unity - Leaderboard data is delayed when showing up

I'm a beginner to coding. A friend of mine used to help me but now he's busy so I have to do things alone. The game has a function that remember the name the player input before playing the game as well as the score of the player. Right now, my problem is that when I play a game, it doesn't show up in my leaderboard scene. And then when I play another round with a different name, I can see the previous score but not my current one. It's like the data is delayed to appear.
void ReplaceRank(string player, int currentScore) {
string oldName;
int oldScoreNumber;
for (int i = 0; i < 10; i++) {
if (currentScore > scores[i]) {
highscoreShow.enabled = true;
oldScoreNumber = scores[i];
oldName = PlayerPrefs.GetString(oldPlayerName[i]);
PlayerPrefs.SetInt(oldScore[i], currentScore);
PlayerPrefs.SetString(oldPlayerName[i], player);
Debug.Log(currentScore);
if (i <= 9) {
ReplaceRank(oldName, oldScoreNumber);
}
break;
}
}
}
private void GetAllKeys() {
oldScore = new List<string>();
oldPlayerName = new List<string>();
scores = new List<int>();
for (int i = 11; i < 21; i++) {
if (PlayerPrefs.GetString("score" + i + "Name", "") == "") {
PlayerPrefs.SetString("score" + i + "Name", "");
}
oldPlayerName.Add("score" + i + "Name");
oldScore.Add("score" + i);
scores.Add(PlayerPrefs.GetInt("score" + i, 0));
}
}
Even though this seems trivial its not , saving is kinda tricky, they are a few things you can do to make it easier e.g you should save the scores as a list
Saving
add scores to list
convert list of scores to Json
save json string in player prefs
Loading
get json string from player prefs
convert Json to list
updated list in script
wrote this class quickly.. its tested and works but you might have to modify it to suit your needs and improve it
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace ScoreBoard
{
[Serializable]
public class PlayerScore
{
public string Name;
public int Score;
public PlayerScore(string name, int score)
{
Name = name;
Score = score;
}
}
[Serializable]
// we need to store list of scores in a container class so we can change it to json
public class PlayerScoresRankedListContainer
{
public List<PlayerScore> PlayerScoresRanked = new List<PlayerScore>();
}
[Serializable]
public class ScoresRanked : MonoBehaviour
{
public static PlayerScoresRankedListContainer PlayerScoresListContainer =new PlayerScoresRankedListContainer();
public void Awake()
{
//example of usage
//get saved items
if (PlayerPrefs.GetString("PlayerScoresRanked").Length > 0)
{
PlayerScoresListContainer.PlayerScoresRanked = GetSortedListFromPlayerPrefs();
DebugShowScores();
}
else
{
//test the class asving items
AddScoreToRankedList("player1", 1000);
AddScoreToRankedList("player2", 20);
AddScoreToRankedList("player3", 100);
SaveListAsJSONInPlayerPrefs();
}
}
private void AddScoreToRankedList(string player, int currentScore)
{
var score = new PlayerScore(player, currentScore);
if (DoesScoreAlreadyExist(score))
{
//we remove a score if it already exists so we can updated it
//you might not need this maybe you just want to keep adding scores
PlayerScoresListContainer.PlayerScoresRanked.RemoveAll(x => x.Name == score.Name);
PlayerScoresListContainer.PlayerScoresRanked.Add(score);
}
else
{
PlayerScoresListContainer.PlayerScoresRanked.Add(score);
}
}
public void SaveListAsJSONInPlayerPrefs()
{
var jsonlist = JsonUtility.ToJson(PlayerScoresListContainer);
Debug.Log("LOG ITEMS BEING SAVED: "+jsonlist);
PlayerPrefs.SetString("PlayerScoresRanked", jsonlist);
}
public List<PlayerScore> GetSortedListFromPlayerPrefs()
{
var jsonlist = PlayerPrefs.GetString("PlayerScoresRanked");
var ListContainer = JsonUtility.FromJson<PlayerScoresRankedListContainer>(jsonlist);
var listsorted = ListContainer.PlayerScoresRanked.OrderByDescending(x => x.Score).ToList();
return listsorted;
}
public bool DoesScoreAlreadyExist(PlayerScore scoreToChcek)
{
if (PlayerScoresListContainer.PlayerScoresRanked.Exists(x => x.Name == scoreToChcek.Name))
{
return true;
}
else
{
return false;
}
}
public void DebugShowScores()
{
foreach (var playerScore in PlayerScoresListContainer.PlayerScoresRanked)
{
Debug.Log(playerScore.Name + " " + playerScore.Score);
}
}
}
}

Categories

Resources