Search Unity

Bug Values don't change in my game data using DatePersistence

Discussion in 'Scripting' started by michael200101, Mar 18, 2023.

  1. michael200101

    michael200101

    Joined:
    Jun 30, 2022
    Posts:
    4
    Hey i have got a problem. I was following along a tutorial on Youtube on creating saves for a game.

    The code doesnt throw any errors but even though i followed him step by step The values dont change for me

    Here are the scripts i use:

    The Testscriptmoney is on an empty game object. I created it as a placeholder

    And the DataPersistenceManager is on another empty game Object.

    The Debug info that a game is loaded with 0 money comes up but when exiting it still is 0.

    The value 0 i set in my GameData script just wont change
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. [System.Serializable]
    6.  
    7. public class GameData
    8. {
    9.     public int money;
    10.  
    11.  
    12.     //Hier wird beim Spielstand erstellen auf 0 gesetzt
    13.     public GameData()
    14.     {
    15.         this.money= 0;
    16.     }
    17. }
    18.  
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using System.Linq;
    5.  
    6. public class DataPersistenceManager : MonoBehaviour
    7. {
    8.  
    9.     private GameData gameData;
    10.  
    11.     private List<IDataPersistence> dataPersistenceObjects;
    12.    public static DataPersistenceManager instance { get; private set; }
    13.  
    14.     private void Awake()
    15.     {
    16.         if (instance != null)
    17.         {
    18.             Debug.LogError("Found more than one");
    19.         }
    20.         instance = this;
    21.     }
    22.  
    23.     public void Start()
    24.     {
    25.         this.dataPersistenceObjects = FindAllDataPersistenceObjects();
    26.         LoadGame();
    27.     }
    28.     private void FixedUpdate()
    29.     {
    30.         Debug.Log(gameData.money);
    31.     }
    32.  
    33.     public void NewGame()
    34.     {
    35.         this.gameData = new GameData();
    36.     }
    37.  
    38.     public void LoadGame()
    39.     {
    40.         //TODO - Load any saved data from a file using the data handler
    41.         //if no data can be loaded, initialize to a new game
    42.         if(this.gameData == null)
    43.         {
    44.             Debug.Log("No data was found. Initializing data to defaults");
    45.             NewGame();
    46.         }
    47.  
    48.         // push the Loaded data to all other scripts that need it
    49.         foreach (IDataPersistence dataPersistenceObj in dataPersistenceObjects)
    50.         {
    51.             dataPersistenceObj.LoadData(gameData);
    52.         }
    53.  
    54.         Debug.Log("Loaded money =" + gameData.money);
    55.     }
    56.     public void SaveGame()
    57.     {
    58.         // pass the data to ither scripts so they can update it
    59.         foreach (IDataPersistence dataPersistenceObj in dataPersistenceObjects)
    60.         {
    61.             dataPersistenceObj.SaveData(ref gameData);
    62.         }
    63.         Debug.Log("Saved money =" + gameData.money);
    64.         //TODO - save that data to a file using the data handler
    65.     }
    66.  
    67.     private void OnApplicationQuit()
    68.     {
    69.         SaveGame();
    70.     }
    71.  
    72.     private List<IDataPersistence> FindAllDataPersistenceObjects()
    73.     {
    74.         IEnumerable<IDataPersistence> dataPersistenceObjects = FindObjectsOfType<MonoBehaviour>().OfType<IDataPersistence>();
    75.         return new List<IDataPersistence>(dataPersistenceObjects);
    76.     }
    77.  
    78.  
    79. }
    80.  
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public interface IDataPersistence
    6. {
    7.     void LoadData(GameData data);
    8.     void SaveData(ref GameData data);
    9. }
    10.  
    11. [code=CSharp]using System.Collections;
    12. using System.Collections.Generic;
    13. using UnityEngine;
    14.  
    15. public class TestScriptMoney : MonoBehaviour, IDataPersistence
    16. {
    17.     private int Money = 165;
    18.     public void LoadData(GameData data)
    19.     {
    20.         this.Money = data.money;
    21.     }
    22.     public void SaveData(ref GameData data)
    23.     {
    24.         data.money = this.Money;
    25.     }
    26. }
    27.  
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class TestScriptMoney : MonoBehaviour, IDataPersistence
    6. {
    7.     private int Money = 165;
    8.     public void LoadData(GameData data)
    9.     {
    10.         this.Money = data.money;
    11.     }
    12.     public void SaveData(ref GameData data)
    13.     {
    14.         data.money = this.Money;
    15.     }
    16. }
    17.  
     
    Last edited: Mar 18, 2023
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,752
    It appears that you forgot to do this part:

    Otherwise I see nowhere above that would save a game, just code to prepare some data for saving.

    If that's not the answer, then it is ...

    Time to start debugging! Here is how you can begin your exciting new debugging adventures:

    You must find a way to get the information you need in order to reason about what the problem is.

    Once you understand what the problem is, you may begin to reason about a solution to the problem.

    What is often happening in these cases is one of the following:

    - the code you think is executing is not actually executing at all
    - the code is executing far EARLIER or LATER than you think
    - the code is executing far LESS OFTEN than you think
    - the code is executing far MORE OFTEN than you think
    - the code is executing on another GameObject than you think it is
    - you're getting an error or warning and you haven't noticed it in the console window

    To help gain more insight into your problem, I recommend liberally sprinkling
    Debug.Log()
    statements through your code to display information in realtime.

    Doing this should help you answer these types of questions:

    - is this code even running? which parts are running? how often does it run? what order does it run in?
    - what are the values of the variables involved? Are they initialized? Are the values reasonable?
    - are you meeting ALL the requirements to receive callbacks such as triggers / colliders (review the documentation)

    Knowing this information will help you reason about the behavior you are seeing.

    You can also supply a second argument to Debug.Log() and when you click the message, it will highlight the object in scene, such as
    Debug.Log("Problem!",this);


    If your problem would benefit from in-scene or in-game visualization, Debug.DrawRay() or Debug.DrawLine() can help you visualize things like rays (used in raycasting) or distances.

    You can also call Debug.Break() to pause the Editor when certain interesting pieces of code run, and then study the scene manually, looking for all the parts, where they are, what scripts are on them, etc.

    You can also call GameObject.CreatePrimitive() to emplace debug-marker-ish objects in the scene at runtime.

    You could also just display various important quantities in UI Text elements to watch them change as you play the game.

    If you are running a mobile device you can also view the console output. Google for how on your particular mobile target, such as this answer or iOS: https://forum.unity.com/threads/how-to-capturing-device-logs-on-ios.529920/ or this answer for Android: https://forum.unity.com/threads/how-to-capturing-device-logs-on-android.528680/

    If you are working in VR, it might be useful to make your on onscreen log output, or integrate one from the asset store, so you can see what is happening as you operate your software.

    Another useful approach is to temporarily strip out everything besides what is necessary to prove your issue. This can simplify and isolate compounding effects of other items in your scene or prefab.

    Here's an example of putting in a laser-focused Debug.Log() and how that can save you a TON of time wallowing around speculating what might be going wrong:

    https://forum.unity.com/threads/coroutine-missing-hint-and-error.1103197/#post-7100494

    When in doubt, print it out!(tm)

    Note: the
    print()
    function is an alias for Debug.Log() provided by the MonoBehaviour class.
     
    Last edited: Mar 18, 2023
    michael200101 likes this.
  3. michael200101

    michael200101

    Joined:
    Jun 30, 2022
    Posts:
    4
    First of all big thanks to that answer!
    I am currently only wanting to print out a debug with the amount of money that would be saved that you can find in the SaveGame Method in the DataPersistenceManager script.

    I am going to sprinkle debugs everywhere now.

    Currently it says "Money Saved = 0" instead of the amount that i actually have.

    I know it doesnt save anything currently but that debug should give me a number already i think.
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,752
    That may be, but follow it through and you'll know why or if it should or does.

    ALSO... here's some more scribblings on the subject:

    Load/Save steps:

    https://forum.unity.com/threads/save-system-questions.930366/#post-6087384

    An excellent discussion of loading/saving in Unity3D by Xarbrough:

    https://forum.unity.com/threads/save-system.1232301/#post-7872586

    Loading/Saving ScriptableObjects by a proxy identifier such as name:

    https://forum.unity.com/threads/use...lds-in-editor-and-build.1327059/#post-8394573

    When loading, you can never re-create a MonoBehaviour or ScriptableObject instance directly from JSON. The reason is they are hybrid C# and native engine objects, and when the JSON package calls
    new
    to make one, it cannot make the native engine portion of the object.

    Instead you must first create the MonoBehaviour using AddComponent<T>() on a GameObject instance, or use ScriptableObject.CreateInstance<T>() to make your SO, then use the appropriate JSON "populate object" call to fill in its public fields.

    If you want to use PlayerPrefs to save your game, it's always better to use a JSON-based wrapper such as this one I forked from a fellow named Brett M Johnson on github:

    https://gist.github.com/kurtdekker/7db0500da01c3eb2a7ac8040198ce7f6

    Do not use the binary formatter/serializer: it is insecure, it cannot be made secure, and it makes debugging very difficult, plus it actually will NOT prevent people from modifying your save data on their computers.

    https://docs.microsoft.com/en-us/dotnet/standard/serialization/binaryformatter-security-guide
     
    michael200101 likes this.
  5. michael200101

    michael200101

    Joined:
    Jun 30, 2022
    Posts:
    4
    OK now i have a file set up to save stuff.
    I am now trying to save my money and the playerposition

    The playerposition works fine
    it gets saved correctly and when loading the game it puts me where i was. but somehow my money is still at zero. so i think there is a problem with my money storing script.

    Can anyone spot an error in the script?
    The Method GainMoney gets called when an enemy dies.
    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using System.Diagnostics;
    5. using UnityEngine;
    6. using UnityEngine.UI;
    7. using Debug = UnityEngine.Debug;
    8.  
    9. public class GameStats : MonoBehaviour, IDataPersistence
    10. {
    11.    
    12.     private int experience= 0;
    13.     private int level;
    14.     private int Money= 0;
    15.    
    16.    
    17.     GameObject[] enemies;
    18.     public Text enemyCountText;
    19.  
    20.    
    21.  
    22.  
    23.  
    24.     void Update()
    25.     {
    26.         enemies = GameObject.FindGameObjectsWithTag("Enemy");
    27.         try
    28.         {
    29.             enemyCountText.text = "Enemies:" + enemies.Length.ToString();
    30.         }
    31.        
    32.  
    33.         catch (NullReferenceException)
    34.         {
    35.            
    36.         }
    37.        
    38.     }
    39.     public int GainMoney(int income)
    40.     {
    41.         this.Money =Money+ income;
    42.        
    43.         Debug.Log(Money);
    44.         return Money;
    45.        
    46.        
    47.        
    48.     }
    49.     public void LoadData(GameData data)
    50.     {
    51.         this.Money = data.money;
    52.     }
    53.     public void SaveData(ref GameData data)
    54.     {
    55.         Debug.Log("It has been saved:"+data.money);
    56.         data.money = this.Money;
    57.        
    58.        
    59.     }
    60.  
    61.  
    62.     public float GainExperience(int xp)
    63.     {
    64.         this.experience = experience + xp;
    65.         //Debug.Log("Experience: "+ experience);
    66.         Level();
    67.  
    68.         return experience;
    69.     }
    70.  
    71.     public int Level()
    72.     {
    73.         if (experience >= 100)
    74.         {
    75.             level++;
    76.             this.experience = experience - 100;
    77.             //Debug.Log("Level:"+level);
    78.             return level;
    79.         }
    80.         else
    81.         {
    82.        
    83.             return level;
    84.         }
    85.        
    86.     }
    87.  
    88.  
    89.  
    90. }
    91.  
    And this is the player movement script where i get the position from that is saved
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class PlayerMovement : MonoBehaviour, IDataPersistence
    6. {
    7.    
    8.     public float speed = 10.0f;
    9.     public Animator animator;
    10.     private Vector2 direction;
    11.  
    12.    
    13.     void FixedUpdate()
    14.     {  
    15.         TakeInput();
    16.         Move();
    17.     }
    18.  
    19.     public void LoadData(GameData data)
    20.     {
    21.         this.transform.position = data.playerPosition;
    22.     }
    23.     public void SaveData(ref GameData data)
    24.     {
    25.         data.playerPosition = this.transform.position;
    26.  
    27.  
    28.     }
    29.  
    30.  
    31.  
    32.  
    33.  
    34.     private void Move()
    35.     {
    36.        
    37.         transform.Translate(direction * speed * Time.deltaTime);
    38.         if(direction.x != 0 || direction.y != 0)
    39.         {
    40.             animator.SetLayerWeight(1, 1);
    41.             SetAnimatorMovement(direction);
    42.         }
    43.         else
    44.         {
    45.             animator.SetLayerWeight(1, 0);
    46.             SetAnimatorMovement(direction);
    47.         }
    48.        
    49.     }
    50.     private void TakeInput()
    51.     {
    52.         direction = Vector2.zero;
    53.         if (Input.GetKey(KeyCode.W))
    54.         {
    55.             direction += Vector2.up;
    56.            
    57.         }
    58.         if (Input.GetKey(KeyCode.S))
    59.         {
    60.             direction += Vector2.down;
    61.            
    62.         }
    63.         if (Input.GetKey(KeyCode.A))
    64.         {
    65.             direction += Vector2.left;
    66.            
    67.         }
    68.         if (Input.GetKey(KeyCode.D))
    69.         {
    70.             direction += Vector2.right;
    71.            
    72.         }
    73.     }
    74.  
    75.     private void SetAnimatorMovement(Vector2 direction)
    76.     {
    77.  
    78.        
    79.         animator.SetFloat("xDir", direction.x);
    80.         animator.SetFloat("yDir", direction.y);
    81.        
    82.     }
    83.    
    84. }
     
  6. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,752
    That is not at all how debugging works!

    I already posted how to debug above for you and nothing has changed since yesterday.

    Time to start debugging! Here is how you can begin your exciting new debugging adventures:

    You must find a way to get the information you need in order to reason about what the problem is.

    Once you understand what the problem is, you may begin to reason about a solution to the problem.

    What is often happening in these cases is one of the following:

    - the code you think is executing is not actually executing at all
    - the code is executing far EARLIER or LATER than you think
    - the code is executing far LESS OFTEN than you think
    - the code is executing far MORE OFTEN than you think
    - the code is executing on another GameObject than you think it is
    - you're getting an error or warning and you haven't noticed it in the console window

    To help gain more insight into your problem, I recommend liberally sprinkling
    Debug.Log()
    statements through your code to display information in realtime.

    Doing this should help you answer these types of questions:

    - is this code even running? which parts are running? how often does it run? what order does it run in?
    - what are the values of the variables involved? Are they initialized? Are the values reasonable?
    - are you meeting ALL the requirements to receive callbacks such as triggers / colliders (review the documentation)

    Knowing this information will help you reason about the behavior you are seeing.

    You can also supply a second argument to Debug.Log() and when you click the message, it will highlight the object in scene, such as
    Debug.Log("Problem!",this);


    If your problem would benefit from in-scene or in-game visualization, Debug.DrawRay() or Debug.DrawLine() can help you visualize things like rays (used in raycasting) or distances.

    You can also call Debug.Break() to pause the Editor when certain interesting pieces of code run, and then study the scene manually, looking for all the parts, where they are, what scripts are on them, etc.

    You can also call GameObject.CreatePrimitive() to emplace debug-marker-ish objects in the scene at runtime.

    You could also just display various important quantities in UI Text elements to watch them change as you play the game.

    If you are running a mobile device you can also view the console output. Google for how on your particular mobile target, such as this answer or iOS: https://forum.unity.com/threads/how-to-capturing-device-logs-on-ios.529920/ or this answer for Android: https://forum.unity.com/threads/how-to-capturing-device-logs-on-android.528680/

    If you are working in VR, it might be useful to make your on onscreen log output, or integrate one from the asset store, so you can see what is happening as you operate your software.

    Another useful approach is to temporarily strip out everything besides what is necessary to prove your issue. This can simplify and isolate compounding effects of other items in your scene or prefab.

    Here's an example of putting in a laser-focused Debug.Log() and how that can save you a TON of time wallowing around speculating what might be going wrong:

    https://forum.unity.com/threads/coroutine-missing-hint-and-error.1103197/#post-7100494

    When in doubt, print it out!(tm)

    Note: the
    print()
    function is an alias for Debug.Log() provided by the MonoBehaviour class.