Search Unity

persistent data between game sessions

Discussion in 'Scripting' started by Deleted User, May 16, 2018.

  1. Deleted User

    Deleted User

    Guest

    playerprefs can save score.

    i need in main menu scene score texts shows overal gathered scores of all sessions.
    but i need ui text score in gameplay scenes only runs between 0 and max scores that user gets.

    i have already implemented the main menu and saving via playerprefs , but still i cannot in other scenes have score texts between 0 and max scores which is affordable.

    i hope it is clear to you what i meant.

    P.S : this is an updated from earlier post. :)
     
    Last edited by a moderator: May 16, 2018
  2. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    You begin by saying

    ...but then, the code you show never uses PlayerPrefs at all.

    You were quite right: PlayerPrefs can save the score. Try using it, and if you run into troubles, post your attempt and any error messages you got and we'll see if we can help.
     
    Deleted User likes this.
  3. Deleted User

    Deleted User

    Guest

    please read my updated post just above...
     
  4. Ian094

    Ian094

    Joined:
    Jun 20, 2013
    Posts:
    1,548
    Not very clear to me.

    Maybe you're looking to clamp the score from 0 to a max value using Mathf.Clamp?
     
    JoeStrout likes this.
  5. Deleted User

    Deleted User

    Guest

    i try to reset score int to 0 each time user start a new game.
    but it does not work.
     
  6. Ian094

    Ian094

    Joined:
    Jun 20, 2013
    Posts:
    1,548
    How are you resetting / reading the score?

    Either delete the PlayerPrefs key every time the user starts a new game or set the PlayerPref key value to 0.
    Code (CSharp):
    1. //Delete the score value, assuming it's key is "Highscore"
    2. PlayerPrefs.DeleteKey("Highscore");
    3.  
    4. //Alternatively, just set it to 0
    5. PlayerPrefs.SetInt("Highscore", 0);
    Here's a good tutorial about using PlayerPrefs for high scores:

    https://unity3d.com/learn/tutorials/topics/scripting/high-score-playerprefs
     
    JoeStrout and Deleted User like this.
  7. Deleted User

    Deleted User

    Guest

    i could not handle it when it comes to 2 variables as score and highscore.
    my game was correct until i wanted to reset in every game variable score and pass its current amount to highscore after each time game is played . but i lost all connections. here are classes : how can i save total score in main menu scene, and i show score in game play scene . score should be reset each time . it means it start from 0.

    here user get 1 score each time :

    Code (CSharp):
    1. GameObject.FindObjectOfType<GameController> ().score++;
    2.  
    3.             GameController gcs = GameObject.FindObjectOfType<GameController> ();
    4.             PlayerPrefs.SetInt ("TotalScores", gcs.score);
    5.             gcs.scoretext.text = gcs.score.ToString();
    now here i want to see total amount of scores of all sessions :

    Code (CSharp):
    1. public class MainmenuLevelSelectionScores : MonoBehaviour
    2. {
    3.  
    4.     void Start ()
    5.     {
    6.         ScoreManager.instance.scoreText = GetComponent<Text>();
    7.  
    8.         ScoreManager.instance.scoreText.text = PlayerPrefs.GetInt ("TotalScores").ToString();
    9.     }
    10.  
    11. }

    it shows total scores . can someone give me ideas how when i go back to game play scene and gather some more scores there , after coming back to here , to see them added here too?
     
    Last edited by a moderator: May 16, 2018
  8. Deleted User

    Deleted User

    Guest

    i have this question please:

    there is score and highscore int in gamecontroller.

    there is a text in main menu and a text in game play scene.

    what i need is to show total scores in main menu scene .

    in gameplay scene i need each time to begin from 0 . i use playerprefs;

    now each time i go to gameplay scene , score starts from 0 but when i return back to main menu scene , the new score will be overwritten on last score.

    instead i need new amount to be added to that in main menu .thanks.
     
  9. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    all you need is something like:
    Code (csharp):
    1. void GotPoints(int val) { // don't even need 'val' if you can only ever get 1.
    2.    gameScore += val;
    3.    highScore += val;
    4.  }
    Normally when I think of high score, I think : if score > highscore, highscore = score; However, your wording makes it sound like maybe you mean accumulated score ... which is what my post tries to answer above.
     
    Deleted User likes this.
  10. Deleted User

    Deleted User

    Guest

    Still not working.
    I have playerpprefs.setint total score .
    In main menu this int will be got via playerpprefs.getint .
    But where my score is saved i need to say to add it to highscore , not the highest score ever gathered . I need to sum amount of all times of user scores .
     
  11. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    That is what the posted code does, and also what I explained in my last post, too. :)
     
    Deleted User likes this.
  12. winterfluxstudio

    winterfluxstudio

    Joined:
    May 4, 2018
    Posts:
    61

    Are you talking about persisting data between scenes (DontDestroyOnLoad) or persisting data between actual sessions (users players, gets XP to 1,000, closes game. Comes back 1 hour later and you want to set their XP back to 1000) (?)

    if its the latter, its something like this:


    Code (CSharp):
    1. using UnityEngine;
    2. using System;
    3. using System.Runtime.Serialization.Formatters.Binary;
    4. using System.IO;
    5. public class CalendarData : MonoBehaviour {
    6.     public int GameYear;
    7.     public int GameMonth;
    8.     public int GameDay;
    9.     private void Start()
    10.     {
    11.         // if CalendarData.dat exists - load it.
    12.         if (File.Exists(Application.persistentDataPath + "/CalendarData.dat") == true)
    13.         {
    14.             Load();
    15.         }
    16.    
    17.     }
    18.     // Load Data
    19.     public void Load()
    20.     {
    21.         if(File.Exists(Application.persistentDataPath + "/CalendarData.dat"))
    22.         {
    23.             // create new binary formatter
    24.             BinaryFormatter CalendarDataBF = new BinaryFormatter();
    25.             // open file
    26.             FileStream CalendarDataFS = File.Open(Application.persistentDataPath + "/CalendarData.dat", FileMode.Open);
    27.             // deserialize data
    28.             CalendarDataContainer calendarData = (CalendarDataContainer)CalendarDataBF.Deserialize(CalendarDataFS);
    29.             // close file
    30.             CalendarDataFS.Close();
    31.             // data to load
    32.             GameYear = calendarData.GameYear;
    33.             GameMonth = calendarData.GameMonth;
    34.             GameDay = calendarData.GameDay;
    35.         }
    36.     }
    37.     // Save Data
    38.     public void Save()
    39.     {
    40.         // create new binary formatter
    41.         BinaryFormatter CalendarDataBF = new BinaryFormatter();
    42.         // create new filestream
    43.         FileStream CalendarDataFS = File.Create(Application.persistentDataPath + "/CalendarData.dat");
    44.         // data to save
    45.         CalendarDataContainer calendarData = new CalendarDataContainer();
    46.         calendarData.GameYear = GameYear;
    47.         calendarData.GameMonth = GameMonth;
    48.         calendarData.GameDay = GameDay;
    49.         // serialize data
    50.         CalendarDataBF.Serialize(CalendarDataFS, calendarData);
    51.         // close file
    52.         CalendarDataFS.Close();
    53.     }
    54. }
    55. // serializable data container class
    56. [Serializable]
    57. class CalendarDataContainer
    58. {
    59.     public int GameYear;
    60.     public int GameMonth;
    61.     public int GameDay;
    62. }
    This tutorial will show you what you need to know in order to persist data between sessions.

    https://unity3d.com/learn/tutorials/topics/scripting/persistence-saving-and-loading-data

    Application.persistentDataPath is a path on the users machine (works on everything like android/ios, pc, mac etc, but not the web player)

    it stores a .dat file which can be saved to and loaded from. You use a serializable class to make a data container (which contains the data you want to save/load)

    if you make the Load() and Save() functions public, you can call them from other scripts when you want to save the data.


    Code (CSharp):
    1. public GameObject CalendarDataGO;
    2. private CalendarData calendarData;
    3.  
    4. private void Start()
    5. {
    6.     calendarData = CalendarData.GetComponent<CalendarData>();
    7. }
    8.  
    9. private void SaveExample()
    10. {
    11.     calendarData.Save();
    12. }
     
    Last edited: May 17, 2018
    Deleted User likes this.
  13. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Goodness gracious! Don't do all that. The OP is having a hard enough time using PlayerPrefs; let's not introduce him to file I/O (which certainly works, but is a lot more complicated than PlayerPrefs for something like saving a score).
     
    Deleted User likes this.
  14. jhocking

    jhocking

    Joined:
    Nov 21, 2009
    Posts:
    814
    Yeah winterflux while everything you said is technically correct, it's more likely to confuse the OP than to help. Also your post kinda implies that PlayerPrefs can only persist data between scenes and not sessions, which is incorrect. The main purpose of PlayerPrefs is to persist small amounts of data between sessions, like high scores or settings
     
    JoeStrout likes this.
  15. Deleted User

    Deleted User

    Guest

    Guys please dont make it too much complex . i have already a variable int score which is saved to key "totalscore" with playerprefs.setint.

    now i added a new variable in my gameplay script too as public static int highscore.

    and then highscore += score ;
    but , i dont know how before leaving game scene add that new amount of score to highscore.
    so that in menu scene my ui text reads it amount from highscore variable .
    can you give me idea how :

    add score int to another int variable at the end of game. accumulation


    thanks Guys ! :)
     
    Last edited by a moderator: May 17, 2018
  16. winterfluxstudio

    winterfluxstudio

    Joined:
    May 4, 2018
    Posts:
    61
    True, but I was unsure what OP wanted (so I tried to provide a Copy/Paste script with comments).

    I didn't mean to suggest PlayerPrefs can not be used to do that, so thanks for pointing it out. That's a good distinction to make and useful for anyone reading who is new to Unity and reads this thread.

    Although, I will say they should only be used to store the players preferences (so the HighScore is not a player preference). I mean, in a single player game, serializing data might be over-the-top so I guess it's down to personal preference.
     
  17. jhocking

    jhocking

    Joined:
    Nov 21, 2009
    Posts:
    814
    I apologize if this is too simple and doesn't address your question, but I'm having trouble understanding what you're asking. Can't you just put this code into whatever script is storing the score:

    Code (CSharp):
    1. void OnDestroy() {
    2.     int totalscore = PlayerPrefs.GetInt("totalscore");
    3.     totalscore += score;
    4.     PlayerPrefs.SetInt("totalscore", totalscore);
    5. }
     
    Deleted User likes this.
  18. winterfluxstudio

    winterfluxstudio

    Joined:
    May 4, 2018
    Posts:
    61
    are you trying to write the score to a UI text box?

    something like this


    Code (CSharp):
    1. // need this or it will not work
    2. using UnityEngine.UI
    3.  
    4. // This is the UI component attached to the cavas and used to display the score
    5. public Text Score;
    6.  
    7. // this is the players score
    8. public int PlayerScore;
    9.  
    10. void Update()
    11. {
    12.     PlayerScore += 1;
    13.     UpdateScore();
    14. }
    15.  
    16. void UpdateScore()
    17. {
    18.     // set the Score UI to display the PlayerScore
    19.     Score.text = "" + PlayerScore;
    20. }
    https://unity3d.com/learn/tutorials/topics/scripting/high-score-playerprefs

    That might help (ironically rated more difficult than the persistent data tutorial I linked)
     
    Last edited: May 17, 2018
  19. winterfluxstudio

    winterfluxstudio

    Joined:
    May 4, 2018
    Posts:
    61
    Ok, I think I get it.

    1) OP wants to display the total combined score of all sessions on the main menu
    2) OP wants to display the "current score" in the game play screens, where they can only go to a maximum number

    To update a UI text element you need to reference the UI element in your Menu script

    Create a public reference to the UI text of the Menu. Drag the Text element from the hierarchy to the empty slot in the inspector for the object this script is attached to.

    Code (CSharp):
    1. public Text TotalScore;
    You will need to reference the UI stuff for it to work.

    Code (CSharp):
    1. using UnityEngine.UI
    You then need to set the text component of the Text UI with the score stored in player prefs. (this is just an example)

    Code (CSharp):
    1. public int totalScore;
    2.  
    3. void Start()
    4. {
    5.    
    6.     TotalScore.text = "" + totalScore;
    7. }
    During GamePlay scenes, you will need something like a max score


    Code (CSharp):
    1. public int MaxScore;
    2.  
    3. public Text PlayerScore;
    4. public int playerScore;
    5.  
    6.  
    7. void ExampleMethod()
    8. {
    9.     // if the player score is less than max score,
    10.     // continue increasing player score and
    11.     // update UI score displayed to user
    12.     if (playerScore < MaxScore)
    13.     {
    14.         playerScore += 1;
    15.         PlayerScore.text = "" + playerScore;
    16.     }
    17.     else
    18.     {
    19.         QuitScene();
    20.     }
    21. }
    22.  
    23. void QuitScene()
    24. {
    25.  
    26. }
    27.  
     
    Deleted User likes this.
  20. Deleted User

    Deleted User

    Guest

    @winterfluxstudio ,that is exactly what i need.
    i have already in script of gameplay defined those int and text ui :
    Code (CSharp):
    1.     public int score;
    2.     public int highscore;
    3.     public Text scoretext;
    4.  
    5.  
    and then in menu scene i referenced ui highscore text to :
    Code (CSharp):
    1.         ScoreManager.instance.scoreText.text = PlayerPrefs.GetInt ("TotalScores" , 0).ToString();
    2.  
    now it will read from key "TotalScores" .

    i dont know if() statement which you said about how will add its amount to highscore and save it .
    can you explain more there? only here i need some ideas. the other parts are done.
     
  21. winterfluxstudio

    winterfluxstudio

    Joined:
    May 4, 2018
    Posts:
    61
    Well, you mention having a maximum score so I assume you have some kind of setup where the player reaches a certain score, or has a certain time limit.

    You have a couple of scenarios

    1) use an if statement to check for the player reaching a certain score, then do something
    example. GameScene 1 - When the player reaches 10,000 points, load GameScene 2

    2) set a "maximum achievable score" when using a time based system.
    example. User has 2 minutes to get their highest score. The maximum achievable score is 5,000

    Let's say you have GameScene 1 and the player starts with 0 points. You want to show a "Level Complete" screen and let them load GameScene2 when they reach a certain amount of points.


    Code (CSharp):
    1. // reference the Menu UI Screen
    2. // Canvas -> UI -> Panel
    3. public GameObject LevelCompleteScreen;
    4.  
    5. // reference players current score
    6. public int currentScore;
    7.  
    8. // reference max score
    9. public int maximumScore;
    10.  
    11. void Update()
    12. {
    13.     // check if the players score has reached the maximum
    14.     // allowed score, if so, freeze time and show the screen
    15.     if(currentScore == maximumScore)
    16.     {
    17.         // freeze time (optional)
    18.         Time.timeScale = 0.0f;
    19.  
    20.         // show level complete screen which has the
    21.         // "load level 2" button
    22.         LevelCompleteScreen.SetActive(true);
    23.     }
    24.  
    25. }
     
  22. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    This thread is a bit confused. :)

    He's asking for a score and an accumulated score.

    If you play 1 game and score 4 pts, your score + acc score is 4.
    You play another game and score 5 pts, your score is 5 and acc score is 9.


    Based on my best knowledge & understanding of the OP's question. I believe at least 2+ posts have tried to show an answer for this..
     
  23. winterfluxstudio

    winterfluxstudio

    Joined:
    May 4, 2018
    Posts:
    61
    OP is also asking how to display that score via a UI text element at the main menu, and during each game scene.

    It's been unclear exactly how they want to handle the situation; ie - using DoNotDestroyOnload to persist the data between scenes, or using the playerprefs to load it every time a scene is switched.
     
  24. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    Indeed, sometimes his posts are hard to follow.
    I was pretty sure I had helped him solve the issue of displaying the text, earlier (perhaps a different thread).
    Sometimes he repeats his entire goal(s), even when one is solved. Though it's possible he changed his mind about the earlier working solution.. :)
     
  25. Deleted User

    Deleted User

    Guest

    now i have created an IO external file in order to save the data.

    but i dont understand how to pass score and highscore to that . and then receive new score .
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System;
    4. using System.IO;
    5. using System.Runtime.Serialization.Formatters.Binary;
    6.  
    7. public static class SaveLoadData
    8. {
    9.  
    10.     public static void Save() {
    11.  
    12.         //Creates a new file
    13.         BinaryFormatter binaryFormatter = new BinaryFormatter();
    14.         FileStream fileStream = File.Create(Application.persistentDataPath + "/playerInfo.dat");
    15.  
    16.         //Creates a new class 'PlayerData'
    17.         PlayerData playerData = new PlayerData();
    18.         //Sets the value 'score' of 'playerData' to the current total Score
    19.         playerData.score = ScoreManager.totalScore;
    20.  
    21.         //Copies 'playerData' to the file that was created
    22.         binaryFormatter.Serialize(fileStream, playerData);
    23.         //Ends the file editing.
    24.         fileStream.Close();
    25.  
    26.     }
    27.  
    28.     public static void Load() {
    29.         //Checks if the file exists
    30.         if (File.Exists(Application.persistentDataPath + "/playerInfo.dat")) {
    31.             //Opens the file
    32.             BinaryFormatter binaryFormatter = new BinaryFormatter();
    33.             FileStream fileStream = File.Open(Application.persistentDataPath + "/playerInfo.dat", FileMode.Open);
    34.             //Copies the contents of the file into a new 'PlayerData'
    35.             PlayerData playerData = (PlayerData)binaryFormatter.Deserialize(fileStream);
    36.             //Closes the file stream
    37.             fileStream.Close();
    38.  
    39.             //Recovers the value of 'playerData'
    40.             ScoreManager.totalScore = playerData.score;
    41.         }
    42.     }
    43.  
    44.     //This is "PlayerData", a child class
    45.     [Serializable]
    46.     class PlayerData
    47.     {
    48.         public int score; //This value will remember the score
    49.     }
    50. }
    51.  
     
  26. Deleted User

    Deleted User

    Guest

    i did like this and now each time i come back to menu scene , highscore is score * 2 .
    instead i need sum of scores = highscore. what is your idea ? whats wrong?

    save load class

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System;
    4. using System.IO;
    5. using System.Runtime.Serialization.Formatters.Binary;
    6.  
    7. public static class SaveLoadData
    8. {
    9.     public static void Save()
    10.     {
    11.         BinaryFormatter binaryFormatter = new BinaryFormatter();
    12.         FileStream fileStream = File.Create(Application.persistentDataPath + "/playerInfo.dat");
    13.         PlayerData playerData = new PlayerData();
    14.  
    15.         playerData.score = PlayerInput.instance.highscore;
    16.  
    17.         binaryFormatter.Serialize(fileStream, playerData);
    18.         fileStream.Close();
    19.     }
    20.  
    21.     public static void Load()
    22.     {
    23.         if (File.Exists(Application.persistentDataPath + "/playerInfo.dat"))
    24.         {
    25.             BinaryFormatter binaryFormatter = new BinaryFormatter();
    26.             FileStream fileStream = File.Open(Application.persistentDataPath + "/playerInfo.dat", FileMode.Open);
    27.             PlayerData playerData = (PlayerData)binaryFormatter.Deserialize(fileStream);
    28.             fileStream.Close();
    29.  
    30.             PlayerInput.instance.highscore = playerData.score;
    31.         }
    32.     }
    33.  
    34.     [Serializable]
    35.     class PlayerData
    36.     {
    37.         public int score;
    38.     }
    39. }
    40.  
    code where i leave game scene :
    Code (CSharp):
    1.     public void GoToMainmenuScene()
    2.     {
    3.         Time.timeScale = 1.0f;
    4.         SceneManager.LoadScene (1);
    5.  
    6.         PlayerInput playeri = GameObject.FindObjectOfType<PlayerInput> ();
    7.  
    8.         int overalscore = PlayerPrefs.GetInt("TotalScores");
    9.         overalscore = overalscore + playeri.score;
    10.         PlayerPrefs.SetInt("TotalScores", overalscore);
    11.  
    12.         Debug.Log (overalscore);
    13.         Debug.Log (playeri.score);
    14.  
    15.     }
    menu scene text reference . here i show highscore in the menu scene :
    Code (CSharp):
    1.     void Start ()
    2.     {
    3.         ScoreManager.instance.scoreText = GetComponent<Text>();
    4.  
    5.         ScoreManager.instance.scoreText.text = PlayerPrefs.GetInt ("TotalScores", 0).ToString();
    6.  
    7.    
    8.     }
     
  27. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    There is really no need to save it to both places, but I suppose you can?
    It looks as though you're looking up the total score, then adding to that the regular score, and then saving it. That would account for it looking like * 2.

    As I was trying to say before, every time you gain a point while playing, increase the current game's score, but also increase the accumulated score (by one). Just read this line to yourself a couple of times! :)

    From there, it doesn't matter if you save to the filesystem or player prefs, because it will be the right number.
     
    Deleted User likes this.
  28. Deleted User

    Deleted User

    Guest

    hi , here score increase by 1
    Code (CSharp):
    1. public void OnItemClicked(GameObject Item)
    2.     {
    3.         if (Item.GetComponent<InteractableObj> ().CanBeUsed)
    4.         {
    5.             Item.GetComponent<Animator> ().SetBool ("returning", true);
    6.             Item.GetComponent<Animator> ().SetBool ("Smashing", false);
    7.             Item.GetComponent<InteractableObj> ().isUsed = false;
    8.             Item.GetComponent<InteractableObj> ().ShowBar (false);
    9.             Item.GetComponent<InteractableObj> ().CanBeUsed = false;
    10.  
    11.             score++;
    12.             PlayerPrefs.SetInt ("TotalScores", score);
    13.             scoretext.text = score.ToString();
    14.         }
    15.     }
    i really cannot understand which variable mean you by increase the accumulated score (by one).

    would you please point to that out?
     
  29. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    I used these terms "game score" and "accumulated score". Game score would be playing once. Accumulated would be all of the scores combined.

    When the game starts, the score is 0, but the accumulated score is whatever the player has earned together through any previous session(s). So, while they're increasing from 0, moving upward, the accumulated score just needs to increase by 1 point every time the current game's score does.
    I'm not sure how this is confusing, so I don't know what to explain.

    Take a moment to just think about what I'm saying, without even thinking about code at all - maybe that is the part that is confusing you.
     
    Deleted User likes this.
  30. Deleted User

    Deleted User

    Guest

    just in the sake of making it clear for you i send a very sample project. i hope you take a look at that and help me to understand my missunderstanding. i would appreaciate for your patients.

    https://ufile.io/wromi
     
  31. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    Ya, all I got was some warning about ad blocker. Anyways, I'm not sure what else to say.

    I have tried to explain it simply and clearly, and I am sorry you do not know what I mean. I think when you do get it, you will think "hey, that was easy". However, between now n then, I'm not sure what else to say.

    Start of the level:
    Code (csharp):
    1. int overallScore = 0;
    2. int currentScore = 0;
    3. void Start() {
    4.    overallScore = PlayerPrefs.GetInt("TotalScore");
    5.   }
    6. void OnPointEarned() {
    7.    currentScore++;
    8.    overallScore++;
    9.    PlayerPrefs.SetInt("TotalScore", overallScore);
    10.    PlayerPrefs.Save();
    11. }
    That's my last try for now. :)
     
    Deleted User likes this.
  32. Deleted User

    Deleted User

    Guest

    thanks. i try thinking even more about all answers . i take some time to do it alone. ya , lets see! hmmmm...^^
     
  33. Deleted User

    Deleted User

    Guest

    finally its almost working but just one question .
    the following class will save and load game score and highscore well. Though in menu scene i have 1 text as highscore.

    and in game scene i have only 1 text as score. this class is attached in each scene to an empty gameobject.
    the problem is as soon as menu scene runs , because in inspector score text is empty , there will be errors in console. and vice versa in game scene.
    what would be a soulution for that?
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5.  
    6. public class PlayerInput : MonoBehaviour
    7. {
    8.     public int currentScore = 0;
    9.     public Text CurrentScore;
    10.     public int overallScore = 0;
    11.     public Text OverallScore;
    12.  
    13.     public void OnItemClicked(GameObject Item)
    14.     {
    15.         if (Item.GetComponent<InteractableObj> ().CanBeUsed)
    16.         {
    17.             Item.GetComponent<Animator> ().SetBool ("returning", true);
    18.             Item.GetComponent<Animator> ().SetBool ("Smashing", false);
    19.             Item.GetComponent<InteractableObj> ().isUsed = false;
    20.             Item.GetComponent<InteractableObj> ().ShowBar (false);
    21.             Item.GetComponent<InteractableObj> ().CanBeUsed = false;
    22.  
    23.             currentScore++;
    24.             overallScore++;
    25.             PlayerPrefs.SetInt("TotalScore", overallScore);
    26.             PlayerPrefs.Save();
    27.         }
    28.     }
    29.          
    30.     void Start()
    31.     {
    32.         overallScore = PlayerPrefs.GetInt("TotalScore");
    33.         OverallScore.text = overallScore.ToString ();
    34.  
    35.     }
    36.  
    37.     void Update()
    38.     {
    39.         CurrentScore.text = currentScore.ToString ();
    40.  
    41.     }
    42. }
     
  34. winterfluxstudio

    winterfluxstudio

    Joined:
    May 4, 2018
    Posts:
    61
    ok, this might be a little complex compared to what you originally wanted to do, but I will try to explain how it works in theory.

    Let's say you have a Main Menu screen (the first scene a user sees when starting your game). Within this scene, you have two empty GameObjects, each with a script attached that saves/loads data

    CalendarData [empty GameObject] has CalendarData.cs attached to it.
    GameScore [empty GameObject] has GameScore.cs attached to it.

    so you use DoNotDestroyOnLoad to persist these scripts into the next scene (user starts level 1 and CalendarData.cs and GameScore.cs exist in the scene, because they have DoNotDestroyOnLoad.

    Level 1 has UI elements (a current score text box) that take information from one of the scripts. But what if YOU start at Level 1, instead of loading through the game menu (Main Menu -> Level 1)

    Well, it doesn't exist. and you get errors (as you pointed out).

    To resolve this error, you can use a pseudo-singleton design pattern. This can be simplified to "only 1 of this object can exist".

    so, what you do is make a prefab of the empty GameObjects with the attached scripts. Then, you can drop these into any scene you want and continue developing.

    Because the user has to come back through the main menu to load Level 1, when the next level is loaded (level 1) the CalendarData.cs and GameScore.cs look for "copys" of themselves in Level 1 and, if they exist, they get destroyed. Therefore maintaining the "there can be only one" pseudo-singleton.

    if you want to go this route, I really recommend taking your time to get familiar the concepts provided in

    https://unity3d.com/learn/tutorials/topics/scripting/persistence-saving-and-loading-data

    this will teach you everything you need to move forward with development.
     
    Deleted User likes this.
  35. Deleted User

    Deleted User

    Guest

    nice !
    thanks ! let's see! :)

    p.s : if you need to unlock your game levels with in game coins , how you do it?
    do you use for each game level something like : playerprefs ? or?
     
  36. winterfluxstudio

    winterfluxstudio

    Joined:
    May 4, 2018
    Posts:
    61

    Something I want to preface is there are usually multiple ways to achieve the same goal. A lot of time it comes down to personal choice or level of knowledge.

    so we have a game with 10 levels. Level 1 is "open" and the rest are locked and need to be bought.

    I would have two Menu screens:

    1) Main Menu which has the "new game" "select level" buttons etc
    2) Level Select Menu which has the level buttons "level 1" "level 2"

    Buttons have a "interactable" boolean. I would have the interactable bool turned off for all levels but the start level.

    Level 1 button (interactable)
    Level 2 button (not interactable)
    Level 3 button (not interactable)
    etc

    so, we have the menus and the appropriate buttons. The player can only load Level 1. But what about when they earn coins in-game and want to unlock a new level?

    Well, each button that is not interactable, could have a "buy" button next to it. When the user clicks this button they purchase/unlock the level.


    Level 1
    Level 2 [ Buy ]
    Level 3 [ Buy ]
    Level 4 [ Buy ]
    etc

    This would require a LevelManager.cs or some way to save/load "which levels are available to the player, how many coins the player has, and how many coins each level requires.



    Code (CSharp):
    1. // reference player
    2. public GameObject PlayerGO;
    3.  
    4. // reference coins script
    5. private PlayerCoins playerCoins;
    6.  
    7. // reference Button
    8. public Button BuyLevel2;
    9.  
    10. void Start()
    11. {
    12.     playerCoins = PlayerGO.GetComponent<PlayerCoins>();
    13.  
    14.     // reference button component
    15.     Button buyLevel2 = BuyLevel2.GetComponent<Button>();
    16.     // do something when button is clicked
    17.     buyLevel2.OnClick.AddListener(PurchaseLevel2);
    18. }
    19.  
    20. void PurchaseLevel2()
    21. {
    22.     if (playerCoins.AvailableCoins > 50)
    23.     {
    24.         // if player has enough coins, unlock level 2
    25.     }
    26.  
    27. }
    Also, you should never use playerprefs to store data/information you dont want the player to have access to (or they could just unlock all levels by changing the playerprefs file)
     
    Deleted User likes this.
  37. Deleted User

    Deleted User

    Guest

    that is a VERY awsome answer i needed to learn . wunderbar!!!! :)
    i will try to learn it ! :)
    thanks.
     
  38. Deleted User

    Deleted User

    Guest

    i would like to create a new thread for this concept .
     
  39. winterfluxstudio

    winterfluxstudio

    Joined:
    May 4, 2018
    Posts:
    61
    To be honest there is not much more I can say without just literally giving you copy/paste scripts. I sometimes write down processes on paper and try to map it out logically, that always helped me learn new concepts.

    it's fairly simple in terms of implementation.

    GameManager.cs

    Code (CSharp):
    1. public int TotalCoins;
    2.  
    3. void Start()
    4. {
    5.     TotalCoins = 0;
    6. }
    MainMenuManager.cs


    Code (CSharp):
    1. // reference GameManager GameObject
    2. public GameObject GameManagerGO;
    3.  
    4. // reference GameManager script
    5. private GameManager gameManager;
    6.  
    7. // reference Main Menu screen panel
    8. public GameObject MainMenuScreenGO;
    9.  
    10. // reference Level Select screen panel
    11. public GameObject LevelSelectScreenGO;
    12.  
    13. // reference Main Menu screen Buttons
    14. public Button NewGameButton;
    15. public Button LevelSelectButton;
    16.  
    17. // Level Select Buttons
    18. public Button Level1;
    19.  
    20. // reference Level 2 button, Buy level 2 button, and a bool
    21. // to keep track of if its already been purchased
    22. public Button Level2;
    23. public Button Level2Buy;
    24. public bool PlayerPurchasedLvl2;
    25.  
    26. void Start()
    27. {
    28.     gameManager = GameManager.GetComponent<GameManager>();
    29.  
    30.     // reference Level Select button component
    31.     Button levelSelectButton = LevelSelectButton.GetComponent<Button>():
    32.     // do something when button is clicked
    33.     levelSelectButton.OnClick.AddListener(OpenLevelSelectMenu);
    34.  
    35.     // get the Level 2 buy button component
    36.     button level2Buy = Level2Buy.GetComponent<Button>();
    37.     // unlock lvl 2 for player
    38.     level2Buy.OnClick.AddListener(PurchaseLvl2);
    39. }
    40.  
    41. private void OpenLevelSelectMenu()
    42. {
    43.     // switch from Main Menu to Level Select
    44.     MainMenuScreenGO.SetActive(false);
    45.     LevelSelectScreenGO.SetActive(true);
    46. }
    47.  
    48. private void PurchaseLvl2()
    49. {
    50.     if(gameManager.TotalCoins > 50)
    51.     {
    52.         // player bought lvl 2
    53.         PlayerPurchasedLvl2 = true;
    54.         // unlock lvl 2 - enable lvl 2 button in menu
    55.         Level2.interactable = true;
    56.     }
    57. }
     
  40. Deleted User

    Deleted User

    Guest

    i still cannot see where data will be safe and permanently get saved ?
    for this purpose is needed a binary formatter save load file ?
    i have already this class in my project. but i dont know how to connect things to that :
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System;
    4. using System.IO;
    5. using System.Runtime.Serialization.Formatters.Binary;
    6.  
    7. public static class SaveLoadData
    8. {
    9.     public static void Save()
    10.     {
    11.         BinaryFormatter binaryFormatter = new BinaryFormatter();
    12.         FileStream fileStream = File.Create(Application.persistentDataPath + "/playerInfo.dat");
    13.         PlayerData playerData = new PlayerData();
    14.  
    15.         playerData.score = PlayerInput.instance.highscore;
    16.         binaryFormatter.Serialize(fileStream, playerData);
    17.         fileStream.Close();
    18.     }
    19.  
    20.     public static void Load()
    21.     {
    22.         if (File.Exists(Application.persistentDataPath + "/playerInfo.dat"))
    23.         {
    24.             BinaryFormatter binaryFormatter = new BinaryFormatter();
    25.             FileStream fileStream = File.Open(Application.persistentDataPath + "/playerInfo.dat", FileMode.Open);
    26.             PlayerData playerData = (PlayerData)binaryFormatter.Deserialize(fileStream);
    27.             fileStream.Close();
    28.  
    29.             PlayerInput.instance.highscore = playerData.score;
    30.         }
    31.     }
    32.  
    33.     [Serializable]
    34.     class PlayerData
    35.     {
    36.         public static int score;
    37.     }
    38. }
    39.  
     
  41. winterfluxstudio

    winterfluxstudio

    Joined:
    May 4, 2018
    Posts:
    61
    Basically, Yes. If you want to have a player do the following

    1) Play your game, unlock level 2, 3 and 4, stop playing
    2) come back, load the game, level 1, 2, 3 and 4 are available.

    otherwise, it would reset to the default values (only level 1 is unlocked) every time they quit the game.
     
    Deleted User likes this.
  42. Deleted User

    Deleted User

    Guest

    all the things good ! can you reply in the other thread when i had more questions about level unlock ?! ^^
     
  43. winterfluxstudio

    winterfluxstudio

    Joined:
    May 4, 2018
    Posts:
    61
    yeah ive already replied there about the error (its onClick not OnClick. Made a typo when i posted it)
     
    Deleted User likes this.