Save Input Field data during runtime?

This should be super simple , but I am having trouble. I simply want to save the input the user types into an Input Field in a variable , I tried to do that with my code below, which I call on OnEndEdit on the Input Field.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class SaveUserName : MonoBehaviour {

     public InputField field ;
    // Use this for initialization
    void Start () {
       
       
    }

    // Update is called once per frame
    void Update()
    {
     
    }
    public void SaveUsername()
    {
        field.text = field.text.ToString();
        field.text = GameNewSave.PlayerName; // static string variable in another class
    }
}

However , upon calling the variable in another scene to see if it worked , it just comes back as a blank string. So , how can I manage to save whatever the player types into the Input Field while the game is running , and store it in a string variable , so I can use it when I want to call the user’s name?

Okay there’s two things going wrong here. I might be making assumptions as I can’t see the other classes working alongside this one, but what you’re doing on SaveUsername() is:

    public void SaveUsername()
    {
        field.text = field.text.ToString(); // All that's happening here is you're setting text as the exact same text that it already has.
        field.text = GameNewSave.PlayerName; // Here you're setting the text of the InputField as 'PlayerName'.
    }

So in neither of these places are you saving PlayerName, which i’m guessing is the thing you wanted to save. You’re telling the text of the input field to turn into PlayerName, which I’m guessing hasn’t been assigned too yet. So it’ll be blank still.

What you want to do is:

public void SaveUsername()
        {
            GameNewSave.PlayerName = field.text.ToString(); // static string variable in another class
        }

When you want to set the username, just do:

public void LoadUsername()
        {
            if (!string.IsNullOrEmpty(GameNewSave.PlayerName))
            {
                field.text = GameNewSave.PlayerName; // static string variable in another class
            }
            else
            {
                Debug.LogWarning("You're haven't assigned PlayerName yet fella!");
            }
        }

Thanks for the reply , but that was my exact code before I changed to the code you corrected. I think the problem is that unity isn’t saving what the player types after I stop the game.

I can’t send the GameNewSave code over as I’m on mobile , but it’s pretty simple

public static string PlayerName = " ";

The class is big, but that’s the only part concerning playername.

What I’m trying to do is get unity to save what the player types while the game is running into player name , so I can use it in different places during the game.

Aaah, yes nothing is saved when you end the game and restart it. When you go to a new scene, static fields are kept, but not when you stop and restart the game.

To keep it simple you’ll want to use:

Like this:

public void SaveUsername()
        {
            PlayerPrefs.SetString("Username", field.text);
        }

        public void LoadUsername()
        {
            if (PlayerPrefs.HasKey("Username"))
            {
                field.text = PlayerPrefs.GetString("Username");
            }
            else
            {
                Debug.Log("Username not saved yet");
            }
        }

Alright , I got you ! Will test this when I get home , but it looks like it should work. For future reference , should I not make strings static and access them later , and just use playerprefs?

Well static strings have their uses sometimes. When you want something to be saved when you stop the game and start the game, go ahead and use a PlayerPref. When you want something a string to be saved when you go from scene to scene, but disappear when you end the game, use a static :). Though of course you can also use Unity - Scripting API: Object.DontDestroyOnLoad for keeping things between scenes too.

1 Like

Standard disclaimer: PlayerPrefs should only be used for data that’s trivial to replace when lost- clearing the cache on a mobile device will wipe it out. If you need runtime data persistence that’s reliable, you’ll have to learn how to serialize and deserialize your own data and write it to local files, or webservers.

So, if the “Username” here is just an indicator of how the game should call you, and you can just ask them for it again if the key doesn’t exist in PlayerPrefs, then that’s fine, but if your tying real game data to that name and it MUST persist between sessions, then you’ll need something a little more involved.

What do you mean by “tying it to real game data”? I really only need the name so I can call it when writing dialogue for characters in my game. So , I would just pull PlayerName ( which is why I wanted to use a static variable) , whenever I wanted to use it. What else should I use?

He’s saying it could be deleted by wiping the cache. Say your player wiped the cache and then they had to re-enter their name, would you be okay with that? If the answer is yes, then there’s nothing to worry about :slight_smile:

1 Like

A static variable is fine- I wasn’t talking about for using it, I was talking about for saving it, so it persists between sessions. Best not to get into a discussion on serializing and saving data to the disk if the name isn’t that important.

1 Like

From what I’ve observed , static variables are saved through scenes (with quitting) using DonotDestroyOnLoad? As I modified a static integer ( incremented it by 1) in one scene and then quit the game , then accessed it by calling it with Debug.Log in another scene , however it still showed up as 0. However , when I applied DoNotDestroyOnLoad to the script containing the static variable and then progressed through the game without quitting ( meaning I went from level to level in - game) , the static variable showed as 1.

I should also note that I am using serialize data to save and load the player’s data ( though that’s an entirely different subject).

DontDestroyOnLoad keeps the selected GameObject instance, any attached MonoBehaviour instances, and any child GameObjects and their attached MonoBehaviours, alive through scene changes. It does this by placing them in a special ‘additive’ scene that’s never unloaded. Since non-additive scene changing destroys all object instances in the unloaded scene, this can be helpful so that certain objects like audio managers, camera managers, etc, don’t need to be recreated from scratch and waste resources.

Static variables are not tied to an instance, so DontDestroyOnLoad has no effect on them one way or another- nor do scene changes. Assigning a value to a static variable will keep that value until you quit the game or assign it some other value (or the object that it’s referencing is destroyed). Quitting the game ends the session, and anything not saved explicitly outside of the program (to a file, to a server, or to the registry) won’t survive- this is the same for static variables, instance scene objects (whether they’re set to DontDestroyOnLoad or not), and everything else.

Unity confuses this issue by offering the ability to enter Play Mode while still in the editor to test things out- the same rules still apply though, with the added caveat that ending Play Mode is the same as ending the game session in a build. Any changes that are made in Play Mode will not persist when exiting, except those that have been explicitly saved to a file, to the registry, or to a server.

Alright , that makes sense , and upon further testing , I see that after I quit the scene , the static variable is now back to 0. I guess my question would be , what’s the best way I could modify these static variables and save them regardless of runtime , so that when I quit the game ( say I added 20 to the money variable), for instance his money variable would be the same when I run it again? I know PlayerPrefs is an option , but that doesn’t seem usable for large projects. I am trying to serialize data , but if I can’t save these variables after they are modified , it doesn’t really work.

Here is my GameSave class for reference ( important parts).

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using UnityEngine.UI;

public  class GameNewSave : MonoBehaviour
{
 
    public  static string PlayerName = " ";
     public static int Education;
    public static int money ;
    public static int relationshipMom;
    public static int relationshipDad;
    public static int relationshipFriend1;
    public static  int relationshipFriend2;
    public static int relationshipFriend3;
    public static int relationshipPrinciple;
    public GameObject panel;
    public GameObject NoDataPanel;
    public string sceneName = "BackgroundInfoScene";
    public Color loadToColor = Color.white;

      void Awake()
    {
        DontDestroyOnLoad(this);
    }

  public void SaveData()
    {
        BinaryFormatter bf = new BinaryFormatter();
        FileStream file = File.Open(Application.persistentDataPath + "/playerInfo.dat", FileMode.Open);
        PlayerData data = (PlayerData)bf.Deserialize(file);
        PlayerName = data.PlayerName;
        money = data.money;
        Education = data.Education;
        relationshipMom = data.relationshipMom;
        relationshipDad = data.relationshipDad;
        relationshipFriend1 = data.relationshipFriend1;
        relationshipFriend2 = data.relationshipFriend2;
        relationshipFriend3 = data.relationshipFriend3;
        relationshipPrinciple = data.relationshipPrinciple;

        file.Close();
    }


    [System.Serializable]
     class PlayerData
    {
        public  string PlayerName = " " ;
        public int Education;
        public int money;
        public int relationshipMom;
        public int relationshipDad;
        public int relationshipFriend1;
        public int relationshipFriend2;
        public int relationshipFriend3;
        public int relationshipPrinciple;

    }
}

Of course you can save them to disk after they’re modified :slight_smile:
Then, read them back when you load the game and assign them to the appropriate variables =)

Saving data is when you serialize. Just in case yours is backwards.

Here are a couple of quick links for a refresher, if you don’t have any handy: Persistence: Saving and Loading Data - Unity Learn
Basic serialization | Microsoft Learn

But isn’t that what I’m technically doing above? Would it be something like this?

Modify Script

GameNewSave.money += 1; // modify variable
GameNewSave.money = GameNewSave.data.money; // save it to the data created in GameNewSave so it can be called later

And then in another script , could I just call it with something like this.

Debug.Log (GameNewSave.money); //  call the newly modified money variable , that persists since it is saved to data.

Just came up with this off the top of my head , but is something like this what you’re suggesting?

I’m going to partially ignore your response, not to be rude but just so I don’t get confused.
This is usually how I think about it in my head…
If the class can be saved on its own, serialize that to save it.
If you have to move your used variables (copy them) to another class that can be saved, then just keep track of them normally where they are, and copy them to the serializable class when required for saving (or back from one when loading).

So, for your script, you’re tracking all of those variables. Now, when you save you have to create an instance of the serializable class and copy over the data.
data.name = myclass.name;

… And so forth.

Does that make sense, or was I a bit too lazy in my explanation? :slight_smile: I can improve it some, if it’s unclear.

Oh, and I think you’re going backwards. You’re deserializing in a ‘save’ method. You want to serialize there, and deserialize when you load**.

I understand the copying data part a bit better now , however , I’m still confused on how I would serialize (save) the class then. I think this means that the problem originates in the fact that my Save and Player Data functions aren’t written correctly. As you said , I’m deserializing instead of serializing?

I’m still pretty new to saving data using serializing , as I used to just use PlayerPrefs. So , I think a more in depth explanation like you said would be cool.

k, well if you look at the links I posted, they should help.
One is a session from Unity, and the other is a small microsoft write up. It’s actually not bad, as some of their docs are not great. :slight_smile:

Basically you have those variables, let’s pretend you just have 2.
So, you update these and use them throughout your game.

Now, you create a class that can be saved (serializable). You put 2 variables that “are the same”, so to speak, as the ones you used in game.
When you go to save, you create a new instance of that other class. You copy a → otherA and b->otherB then serialize them. See the links for the exact syntax, as I’d have to look it up to make sure I got it right, too :slight_smile: lol

You just go backwards when reading it when the game starts. Then, once they’re safely loaded back into your regular variables, you go about updating and using them as normal during your session — only saving when you want to. However you decide to do that. :slight_smile:

If you try one or both links, perhaps you can just do a quick update on your code and test it. Then, if anything is still not working, reply here showing the updated stuff & what’s broken. :slight_smile:

1 Like

It’s one of those situations where you can do things one of many many different ways, and which way you choose is really just a matter of preference and whatever seems easiest for your setup.

PlayerPrefs saves to the registry on Windows builds, and to caches on Android and iOS. It’s good for preference data that you want to save but isn’t a big deal if it’s lost. Volume settings, screen resolution, text scales- most of the things you normally see in “Options” menus can be handled this way. If a value is lost, your code should just use the default for that option and make the user change it again (if they like), so the fact that the data is so fragile shouldn’t hurt you as long as you don’t use it for anything really important.

Aside from that, you’ll need to serialize and save / deserialize and load the data yourself. Lots of options here. As mentioned, you can have different classes handling this independently, or do it in one big object all at once.

In the former case, you’ll end up with a dozen little save files on the disk simultaneously (the story progress save file, the character data save file, the achievement progress save file, etc…). This is a pain in the ass to keep track of, and easy to cheat with- imagine duplicating the file with your money, buying a ton of stuff until you’re broke, then replacing the “broke” file with the earlier copy and getting your money back- and your items are still there because they’re a different file. This is only one of the numerous ways in which this can be abused, and more importantly having the save operations so spread out just over-complicates the project.

In the latter case, you pick and choose which data you want from each object and collect it into one big “save data” serializable object that has everything you need to load the game with. This can be managed in a manner similar to PlayerPrefs (everytime your character’s level increases, store the new value to the central SaveData object, in addition to the character’s status script). Even better, you can have an event called PreparingToSave or something that every object with savable data signs up for when the game starts. When the event fires, all objects that are listening for it are notified, and will copy over whatever data they have that they want to keep to the central SaveData object. In the next frame, the SaveData object is serialized, and saved to disk, and the reverse of this process occurs when loading.

This is more realistic, and it means you only need to handle the actual saving and loading in one place.

In either case, you’ll also have to decide how you want the data serialized- BinaryFormatter comes with .NET and works fine, but it’s a bit slow and pretty limited. It does binary serialization, which means the data it outputs is all 1s and 0s and just gibberish without knowing how to deserialize it. JsonUtility, on the other hand, comes with Unity and allows you to turn a serializable object into a string. This can be especially useful for transmitting save data over the internet, but it works for local files too if you like having a bit of readability (unless you encrypt it, you can just open it up in a text editor and read it and it makes something resembling sense).

Other alternatives include XML, ZeroFormatter, MessagePack… It just depends on the balance of features, readability, security, speed, and filesize that you need.

For sure, Json (JsonUtility in Unity) is a great option. Something I’ve been suggesting more often to people for these things. I just wanted to add that, because recently I was talking about the BinaryFormatter, but at the same time, I was trying to respond to an already posted BF piece of code… and that’s why :slight_smile:
Still doesn’t hurt to clear up a few misunderstandings, as you may like to use it someday. :slight_smile: