Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice
  3. Dismiss Notice

Question Issues with save/load files

Discussion in 'Scripting' started by Aggelas, May 23, 2024.

  1. Aggelas

    Aggelas

    Joined:
    Mar 20, 2021
    Posts:
    2
    First issue - Saving
    I have private variables from another script I want to save to a .txt file but comes up with this "NullReferenceException: Object reference not set to an instance of an object."
    This is what I'm trying to save... (tested each data as I added it.)
    Code (CSharp):
    1.         contents =
    2.             "Player Name" + loadGame.splitSaveMark + playerDetails.playerName + "\n" +
    3.             "Player Position.X" + loadGame.splitSaveMark + playerPosition.x + "\n" +
    4.             "Player Position.Y" + loadGame.splitSaveMark + playerPosition.y + "\n" +
    5.             "Level Name" + loadGame.splitSaveMark + levelName + "\n" +
    6.             repairShip.SaveBools() + resourceCollection.SaveResources() +
    7.             questVariables.SaveVariables() + timeToRepair.SaveQuestTimes() +
    8.             "Conversation Point" + loadGame.splitSaveMark + questConversation.conversationPoint + "\n" +
    9.             "Active Quest Name" + loadGame.splitSaveMark + questConversation.questName
    10.             + "Player Health" + loadGame.splitSaveMark
    11.             + "\n" + playerHealth.SaveData()
    12.              ;
    13.         PlayerPrefs.SetString(saveNo, text.text);
    14.         SaveFileCreate();
    "playerHealth.SaveData()" is where the issue is...
    Code (CSharp):
    1.     public string SaveData()
    2.     {
    3.         Debug.Log("HealthSaveData: Start");
    4.  
    5.         GameObject lSBase = GameObject.Find("Canvas").transform.GetChild(15).gameObject;
    6.         LoadGame loadGame = lSBase.transform.GetChild(1).GetComponent<LoadGame>();
    7.  
    8.         string saveData = "Player Health"+ loadGame.splitSaveMark + health +
    9.             "Max Health" + loadGame.splitSaveMark + maxHealth;
    10.  
    11.         Debug.Log("HealthSaveData: End");
    12.  
    13.         return saveData;
    14.     }
    health is public, max health is private. Health script is attached to player character.
    Code (CSharp):
    1.     public float health = 100;
    2.     private float maxHealth;
    maxHealth is set in awake
    Code (CSharp):
    1.     void Awake()
    2.     {
    3.         maxHealth = health;
    4.         SetHealth();
    5.         GetVariables();
    6.     }
    upload_2024-5-23_15-29-29.png
    Second issue - load - player position
    I have been trying to move my player to a designated XY coordinates.
    (X:90.63384 Y:-0.1123914) stays at (X:-24.71 Y:-0.1150008)
    Tried two ways
    Code (CSharp):
    1.         //Player Position
    2.  
    3.         playerMovement = GameObject.FindGameObjectWithTag("Player").GetComponent<PlayerMovement>();
    4.         //X Position
    5.         subs = saveGame.savedInfo[xPosLoad].Split(':');
    6.         string numberString = subs[subs.Length - 1];
    7.         float ppX = float.Parse(numberString);
    8.         //Y Position
    9.         subs = saveGame.savedInfo[yPosLoad].Split(':');
    10.         numberString = subs[subs.Length - 1];
    11.         float ppY = float.Parse(numberString);
    12.  
    13.         //Move Player
    14.         //player.transform.position = new Vector3(ppX, ppY, 0);
    15.         playerMovement.transform.position = new Vector3(ppX, ppY, 0);
    16.         Debug.Log("Player X: " + player.transform.position.x + " Player Y: " + player.transform.position.y);
    17.  
    18.         //test for player position
    19.         subs = saveGame.savedInfo[xPosLoad].Split(':');
    20.         numberString = subs[subs.Length - 1];
    21.         ppX = float.Parse(numberString);
    22.  
    23.         subs = saveGame.savedInfo[yPosLoad].Split(':');
    24.         numberString = subs[subs.Length - 1];
    25.         ppY = float.Parse(numberString);
    26.         player.transform.position = new Vector3(ppX, ppY, 0);
    Early attempted at https://github.com/Aggelas/StrandedOnPlanetX/blob/main/LoadGame.cs

    Addendum: I have issues with my ability to wrap my brain around concepts and have to work around the ones I have trouble with. I have watched numerous videos on JSON, couldn't get it. This seems to be were my head is at. Maybe in six months/a year that will change (has happened before in reverse) but until then...
    Any variable declared in this code is a local variable.
     
    Last edited: Jun 12, 2024 at 6:52 AM
  2. TeaJunkie

    TeaJunkie

    Joined:
    Nov 23, 2016
    Posts:
    24
    straight away i would create a public variable instead of using GameObject.Find().

    Code (CSharp):
    1. GameObject lSBase = GameObject.Find("Canvas").transform.GetChild(15).gameObject;
    should be changed to public GameObject ISBase as a variable and then in the inspector drag the gameobject onto it.

    That much information i would recommend using JSON to save and load using the JSON Utilities. Youtube as plenty of tutorials on how to do it.
     
  3. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    6,922
    This is not a save file, it's a text dump. You will find it tremendously challenging to read it back in if you ever change the format of that file. There are established file formats like json.

    The error is in line 127. Set a breakpoint and debug it, you can see all the values of each variable as your code executes.
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    39,357
    Oh my goodness, DO NOT do this crazy Ninja stuff, ever!

    That one line of code contains SO much that can go wrong:

    - GameObject.Find() <---- a disaster function - AVOID!
    - A magic number (what is 15? What if it changes? How would you know?)
    - way too many dots... dots... dots...

    Remember the first rule of GameObject.Find():

    Do not use GameObject.Find();

    More information: https://starmanta.gitbooks.io/unitytipsredux/content/first-question.html

    More information: https://forum.unity.com/threads/why-cant-i-find-the-other-objects.1360192/#post-8581066



    If you have more than one or two dots (.) in a single statement, you're just being mean to yourself.

    Putting lots of code on one line DOES NOT make it any faster. That's not how compiled code works.

    The longer your lines of code are, the harder they will be for you to understand them.

    How to break down hairy lines of code:

    http://plbm.com/?p=248

    Break it up, practice social distancing in your code, one thing per line please.

    "Programming is hard enough without making it harder for ourselves." - angrypenguin on Unity3D forums

    "Combining a bunch of stuff into one line always feels satisfying, but it's always a PITA to debug." - StarManta on the Unity3D forums




    As for the NullReference, you never need to make a post for that.

    The answer is always the same... ALWAYS!

    How to fix a NullReferenceException error

    https://forum.unity.com/threads/how-to-fix-a-nullreferenceexception-error.1230297/

    Three steps to success:
    - Identify what is null <-- any other action taken before this step is WASTED TIME
    - Identify why it is null
    - Fix that



    Finally...

    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

    And another excellent set of notes and considerations by karliss_coldwild:

    https://forum.unity.com/threads/saving-levels-in-an-in-game-level-editor.1525156/#post-9518140

    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. Save data needs to be all entirely plain C# data with no Unity objects in it.

    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, so you end up with a defective "dead" Unity 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