1

So I'm working with a customizer for my snake game and I am using PlayerPrefs to save the preference look of the snake. Now everytime I test-run the game it the saved string in playerprefs doesn't load it's just empty.

I've already tried getting the string data on the Start(), Awake(), and Update() method and none of them loads the data. Also I've add PlayerPrefs.Save() in each line I save the data.

Here's my code for updating all mesh to be the same as the saved string. I've put it in the Update Method.

lesnek = GameObject.FindGameObjectsWithTag("LeWorm");

        objName = PlayerPrefs.GetString("meshName");

        if (PlayerPrefs.HasKey("meshName"))
        {
            if (objName == PlayerPrefs.GetString("meshName"))
            {
                leMesh = Resources.Load<GameObject>(@"Models\" + objName);
            }
            else
            {
                objName = PlayerPrefs.GetString("meshName");
                leMesh = Resources.Load<GameObject>(@"Models\" + objName);
            }
        }
        if (objName != null || objName != "")
        {
            objName = "Sphere";
            leMesh = Resources.Load<GameObject>(@"Models\" + objName);
        }

        foreach (GameObject change in lesnek)
        {
            if (objName != null || objName != "")
            {
                if (change.GetComponent<MeshFilter>() == null)
                {
                    change.AddComponent<MeshFilter>();
                    change.GetComponent<MeshFilter>().mesh = leMesh.GetComponent<MeshFilter>().sharedMesh;
                    PlayerPrefs.SetString("meshName", objName);
                    PlayerPrefs.Save();
                }
                else
                {
                    change.GetComponent<MeshFilter>().mesh = leMesh.GetComponent<MeshFilter>().sharedMesh;
                    PlayerPrefs.SetString("meshName", objName);
                    PlayerPrefs.Save();
                }
            }
        }

Every time I run this code I get an error and doesn't load or save the string in the playerprefs.

Zacqwerty
  • 13
  • 6
  • If you are getting an error, please provide us with the error message. – adisib May 11 '19 at 03:56
  • So if i remove this if (objName != null || objName != "") statement I get this error message: UnassignedReferenceException: The variable leMesh of ChangerPasserScript has not been assigned. You probably need to assign the leMesh variable of the ChangerPasserScript script in the inspector. UnityEngine.GameObject.GetComponent[MeshFilter] () (at C:/buildslave/unity/build/Runtime/Export/GameObject.bindings.cs:28) ChangerPasserScript.Update () (at Assets/Scripts/ChangerPasserScript.cs:52) – Zacqwerty May 11 '19 at 04:20
  • Possible duplicate of [What is the correct Resource.Load path?](https://stackoverflow.com/questions/26903835/what-is-the-correct-resource-load-path) – shingo May 11 '19 at 05:20
  • well the resource.load is correct and i have tried to get the string through printing it in the console and it just prints nothing – Zacqwerty May 11 '19 at 05:46

2 Answers2

0

The Gameobject "leMesh" is not being found. The first step is to make sure it does get found. So let's make sure we are informed about its status in order to debug this:

if (PlayerPrefs.HasKey("meshName"))
    {
        Debug.Log("PlayerPrefs does have the key we are looking for and it is " + PlayerPrefs.GetString("meshName"));

        /// This is redundant you just set objName to the string earlier
        /// objName = PlayerPrefs.GetString("meshName");
        if (objName == PlayerPrefs.GetString("meshName"))
        {
            leMesh = Resources.Load<GameObject>(@"Models\" + objName);
        }
        else
        {
            /// And here you do it again, constantly trying to get that string
            /// In order to find the object, of course if the string doesnt exist
            /// youll simply get an unassigned referenceException on this line:
            /// change.GetComponent<MeshFilter>().mesh = leMesh.GetComponent<MeshFilter>().sharedMesh
            objName = PlayerPrefs.GetString("meshName");
            leMesh = Resources.Load<GameObject>(@"Models\" + objName);
        }
    }

Now if your console log tells you that meshName returns a value then you're accessing the resources wrong in which case trying removing "@" from infront of "Models". Otherwise there is no playerPrefs string called meshName.

ref

SteenPetersen
  • 188
  • 2
  • 17
  • Yes i know, anyways thanks for shortening my redundant code but my issue here is PlayerPrefs ok, So i have this meshName pp/playerprefs now i save a string which the name of the mesh everytime i change the mesh now when it comes to loading the mehsName pp or getting it, it always say in the console " ". Just blank..... – Zacqwerty May 11 '19 at 10:50
  • Also I've been guessing that why pp is not getting the string is that because it takes alot of memory to the system like a heavy load – Zacqwerty May 11 '19 at 10:56
0

There are a few problems here, and your null reference error is a major contributor.

I will comment your code to show you where you are going wrong and provide an alternative solution.

// If possible it would be better to assign this object in the inspect rather then 
// using a GameObject.Find method, Also this is error prone due to the timing of 
// the call, for example if this is in a start this Object may not exist yet.
// Another solution would to be create an event and when you load the skin
// Have that event fire off that its been loaded and everything that needs
// to listen to it will get the change.
lesnek = GameObject.FindGameObjectsWithTag("LeWorm");

//  GetString has an alternative method where you can pass a default value
//  I would recommend using this method instead.
objName = PlayerPrefs.GetString("meshName");    // POINT A

// Honestly this check seems a tad bit redundant since you already
// attempted to load this preference.
// POINT B
if (PlayerPrefs.HasKey("meshName"))  // Since you have said this is empty playerPrefs is empty.
{
    // At this point it should equal this since you already set it to this in Point A
    if (objName == PlayerPrefs.GetString("meshName"))
    {
        leMesh = Resources.Load<GameObject>(@"Models\" + objName);
    }
    else
    {
        // This case should never get called, because of Point A and your if condition.
        objName = PlayerPrefs.GetString("meshName");
        leMesh = Resources.Load<GameObject>(@"Models\" + objName);
    }
}

if (objName != null || objName != "")  // This completely nullifies all the work in Point B
{
    objName = "Sphere";
    leMesh = Resources.Load<GameObject>(@"Models\" + objName);
}
foreach (GameObject change in lesnek)
{
    if (objName != null || objName != "")
    {
        if (change.GetComponent<MeshFilter>() == null)
        {
            change.AddComponent<MeshFilter>();
            change.GetComponent<MeshFilter>().mesh = leMesh.GetComponent<MeshFilter>().sharedMesh;
            PlayerPrefs.SetString("meshName", objName);
            PlayerPrefs.Save();
        }
        else
        {
            change.GetComponent<MeshFilter>().mesh = leMesh.GetComponent<MeshFilter>().sharedMesh;
            PlayerPrefs.SetString("meshName", objName);
            PlayerPrefs.Save();
        }
    }
}

Without going into to much detail and assuming this is in a form of initialize method rather then start this is the changes I would make

// This would be better as a class variable rather then a local variable
string meshName = PlayerPrefs.GetString("meshName", "Sphere");  
// Skipping point B because it is redundant
leMesh = Resources.Load<GameObject>(@"Models\" + meshName);  // Is this a GameObject or is it a Mesh???

MeshFilter leMeshFilter = leMesh.GetComponent<MeshFilter>();
if(leMeshFilter != null)
{
    foreach (GameObject change in lesnek)
    {
        MeshFilter meshFilter = change.GetComponent<MeshFilter>();
        if(meshFilter != null)
        {
            meshFilter.mesh = leMeshFilter.sharedMesh;
        }
        else
        {
            meshFilter = change.AddComponent<MeshFilter>();
            meshFilter.mesh = leMeshFilter.sharedMesh;
        }
    }
}

The only thing this example doesnt do is save your PlayerPreference. This is something that should be done only when you change the skin. So whereever you do that save the preference.

AresCaelum
  • 1,558
  • 1
  • 13
  • 18
  • thanks, havent tried it yet but i do have a questions.. does pp take a lot of memory to load in? – Zacqwerty May 12 '19 at 00:16
  • @Zacqwerty I've never had an issue with it taking a lot of memory. – AresCaelum May 12 '19 at 00:46
  • didn't worked it just worked just like my work the save string did not laod – Zacqwerty May 12 '19 at 12:35
  • @Zacqwerty Then you must have saved an empty string into meshName. If the string does not exist in `PlayerPrefs` it will return Sphere, if it is returning an empty string then the key exists with nothing in it. Might be a good idea to clear your preferences – AresCaelum May 12 '19 at 12:46
  • Run your project with `PlayerPrefs.DeleteKey("meshName")` somewhere, then restart your project without it. – AresCaelum May 12 '19 at 12:48
  • I am running the code in the `Update()` method so it would check and get the existing gameobjects always is it wrong to get the pp in update method? @Eddge – Zacqwerty May 13 '19 at 02:18
  • Loading should always only ever be done when it is needed, if you are loading this in an update, then you are loading from resources in update, you are going to have performance issues Unfortunately telling me this doesn't work does not help solve the problem. it seems weird that if you remove the player pref then attempt to load it you would still get an empty key, EVEN when using the overloaded method that lets you specify a default. As such I will need to ask for an MCVE. you can find how to do that here: https://stackoverflow.com/help/mcve – AresCaelum May 13 '19 at 12:16
  • So uh I didn't read as much of it but I get the idea... So as you start the game and head into the customizer scene, you could see a Shape Change button which when press load an array of buttons to change shape of the char, once one of the button is pressed saves the string meshName in the PlayerPrefs file, now the ChangerPasser script is what controls the mesh of the char throughout the whole game, the mesh that the script uses comes from is from the meshName PlayerPrefs. Guess this would help you identify it. – Zacqwerty May 13 '19 at 12:26
  • ok I fixed the problem sorry for causing you stress because of my problem. Well it turns out in my color changer script it has `PlayerPrefs.DeleteAll()` and I just noticed it when I remember that someone told me to check my color changer script. Thanks alot bro for cleaning my code! – Zacqwerty May 14 '19 at 13:00