Search Unity

PlayerPrefs problem

Discussion in 'Scripting' started by ellenblomw, Nov 10, 2018.

  1. ellenblomw

    ellenblomw

    Joined:
    Mar 4, 2018
    Posts:
    153
    Hi guys,

    I am writing a script where the player chooses a username, but if he/she hasn't choosen one I want a default to set in. But when I press play its just blank if I haven't choosen a username:

    Code (CSharp):
    1.     [SerializeField]
    2.     InputField username;
    3.  
    4.     void Update()
    5.     {
    6.         PlayerPrefs.SetString("userName", username.text);
    7.         if (PlayerPrefs.HasKey("userName") == false)
    8.         {
    9.             PlayerPrefs.SetString("userName", "No name");
    10.         }
    11.     }
    Second code
    Code (CSharp):
    1.         private static string userName;
    2.  
    3.         // Use this for initialization
    4.         void Start()
    5.         {
    6.             //Get name of user, No name if none is chosen
    7.             babyName = PlayerPrefs.GetString("userName", "No name");
    8.         }
    9.  
    10.         public override string GetParameterValue(string ParamName)
    11.         {
    12.             if (ParamName == "NAME")
    13.                 return userName;
    14.             return null;
    15.         }
    16.     }
    What am I doing wrong?

    Respectfully,
    Ellen
     
  2. csofranz

    csofranz

    Joined:
    Apr 29, 2017
    Posts:
    1,556
    Well, for one, an empty string "" is still a string. If you fetch the current name from the input field, and store that in PlayerPrefs, it will always return true for HasKey. But also note that you do not call PlayerPrefs.Save(), so there is a good likelihood that your changes aren't written back...
     
  3. ellenblomw

    ellenblomw

    Joined:
    Mar 4, 2018
    Posts:
    153
    - Well, for one, an empty string "" is still a string. If you fetch the current name from the input field, and store that in PlayerPrefs, it will always return true for HasKey.
    - Ok I understand the problem. Thank you very much! But is there any way to check if it's just ""? I tried this but it did not work :/
    Code (CSharp):
    1.         if (PlayerPrefs.GetString("userName") == "")
    2.         {
    3.             PlayerPrefs.SetString("userName", "No name");
    4.         }

    - But also note that you do not call PlayerPrefs.Save(), so there is a good likelihood that your changes aren't written back...
    - Hmm they do return a username in my different scenes, why is it that it works even if I do not call Save? Weird, hmm
     
  4. csofranz

    csofranz

    Joined:
    Apr 29, 2017
    Posts:
    1,556
    To find out if a string is empty, examine it's length property. If it's '0' (I prefer '<1'), the string does not contain any characters:

    Code (CSharp):
    1. string theName = PlayerPrefs.GetString("testing");
    2. if (theName.length < 1) {
    3.    // empty string, but not null
    4. }
     
  5. ellenblomw

    ellenblomw

    Joined:
    Mar 4, 2018
    Posts:
    153
    Ok will try that. I should probably not be doing this in update? Maybe better to use OnMouseDown?
     
  6. csofranz

    csofranz

    Joined:
    Apr 29, 2017
    Posts:
    1,556
    You should probably only do that whenever the text itself changes (look at the input field definition, you can usually call a method if that happens), or when the user clicks on your new 'Accept Name' button that you'll probably be aadding wight now :)
     
  7. ellenblomw

    ellenblomw

    Joined:
    Mar 4, 2018
    Posts:
    153
    Thank you very much, it worked like a charm!! Franz = awesome :D

    - or when the user clicks on your new 'Accept Name' button that you'll probably be aadding wight now :)
    - Hehe correct!
     
  8. SparrowGS

    SparrowGS

    Joined:
    Apr 6, 2017
    Posts:
    2,536
    Also,
    Code (CSharp):
    1. string s;
    2. if(s == ""){
    3. //empty string
    4. }
     
    ellenblomw likes this.
  9. ellenblomw

    ellenblomw

    Joined:
    Mar 4, 2018
    Posts:
    153
    @csofranz: do you also know if there is any way of telling if a string ends with an s, and in that case erase the s from the saved string?

    Example: Lets say I have a text that reads ”Usernames party”, and username is Emma, that text then says ”Emmas party”. But if username is Charles, my text would read ”Charless party” - which is wrong and kind of annoying for all the Charles out there.

    Something like:

    Code (CSharp):
    1. thename = PlayerPrefs.GetString(”Testing”);
    2. if (thename.ENDS-with-an-s){
    3. Remove S from (”Testing”)
    4. PlayerPrefs.Save
    5. }
     
  10. SparrowGS

    SparrowGS

    Joined:
    Apr 6, 2017
    Posts:
    2,536
    I'm not native to english, but isn't it 's like "Sparrow's party"? (you're all invited btw ;))
     
  11. ellenblomw

    ellenblomw

    Joined:
    Mar 4, 2018
    Posts:
    153
    Haha yeah it might be true? Not native english either. But it’s actually in swedish and we don't use ’ that way - sadly for me. I would have come to your party either way though
     
  12. csofranz

    csofranz

    Joined:
    Apr 29, 2017
    Posts:
    1,556
    Actually, in most cases, if the name ends on the letter 'S', you just append an apostrophe, while on other names you ad an apostrophe . So "Christian" turns to "Christian's party" while "Charles" turns to "Charles' party".

    So how do you tell if the name ends on a letter, or even string? use the surprisingly named EndsWith method.

    Code (CSharp):
    1. if (name.EndsWith("s") {
    2.   // only add an apostrophe
    3.   name = name + "'";
    4. } else {
    5.   // add apo and 's'
    6.   name = name "'s";
    7. }
    Oh, and I'm not a native speaker either
     
  13. ellenblomw

    ellenblomw

    Joined:
    Mar 4, 2018
    Posts:
    153
    EndsWith , should have figured. N00b question . Thanks!!

    Well is there a way to just remove the S rather than adding the apostrophe? I guess using - ”s” would mean that it removes all S:s in the name?
     
  14. csofranz

    csofranz

    Joined:
    Apr 29, 2017
    Posts:
    1,556
    Unfortunately, C# isn't that simple. But if you want to remove a certain string from the end of a string, this is how you do it:

    Code (CSharp):
    1. lookfor = "s"; // or other stuff you want to remove from the end of a string, but not the middle
    2. if (name.EndsWith(lookfor))
    3.     {
    4.        name = name.Substring(0, name.LastIndexOf(lookfor));
    5.     }
    If you are interested how this works (and learn a lot more about the string class, look up the C# documentation, it's worth your while).
     
    ellenblomw likes this.
  15. ellenblomw

    ellenblomw

    Joined:
    Mar 4, 2018
    Posts:
    153
    Yes I just dont find the documentation very understandble :/, its a bit abstract. I have ordered a book though, lets hope it contains lots about strings because I just figured that if I use this approach my user will be called Charle without S in all of the scenes where its not an S after the username
     
  16. ellenblomw

    ellenblomw

    Joined:
    Mar 4, 2018
    Posts:
    153
    Thank you very much!
     
  17. SparrowGS

    SparrowGS

    Joined:
    Apr 6, 2017
    Posts:
    2,536
    Always check the API ;)

    if you're into books i also recommend you get this one(or just read the online PDF)
    http://lecturer.ukdw.ac.id/~mahas/dossier/gameng_AIFG.pdf

    also, English be weird af.
    why do you spell kite and night like that, you should either say kight or nite imo
    just to name one example, not to mention all those silent K's, my english teach used to tell us "you spell it the way you hear it" sure....

    speaking of it.. what's up with capital letters too, haha
    we(Hebrew) have 2 types of letters, but they are different styles like you have cursive
     
  18. orb

    orb

    Joined:
    Nov 24, 2010
    Posts:
    3,037
    I have to agree the current MSDN documentation for C# isn't always the clearest. I know what I'm looking for, I know the language decently well, yet I feel like I know less after reading some of their examples. It's better to use some 3rd party sites, like DotNet Perls. Clear, concise, well-organised overview of how to do things. It's a much better tutorial than Microsoft have come up with so far.

    And here's a tip: C# has extension methods. This seems like a great case for using one, extending the string type with a Possessive() method or something. The magic goes inside something like this:
    Code (CSharp):
    1. namespace MyExtensions // Change to something better, like your utility namespace
    2.   public static class StringExtensions
    3.   {
    4.     public static string Possessive()
    5.     {
    6.       string s;
    7.       // Insert code to add apostrophes and stuff here
    8.       return s
    9.     }
    10.   } // End class
    11. } // End namespace
    Then you just use it as a string method:
    Code (CSharp):
    1. using MyExtensions;
    2. ...
    3. string name = "Charles";
    4. name = name.Possessive();
    You can build up all sorts of extensions to .NET classes and types this way. I use it for string manipulation unique to my own projects and extending randomisation to include an array-based card shuffler, for example.

    There are more exceptions to some rules than there are words following said rule in most languages it seems. At least you don't have to deal with K changing between the familiar K-sound to a semi-guttural depending on seemingly random factors, or place names starting with a silent L, like near me ;)
     
    ellenblomw likes this.
  19. ellenblomw

    ellenblomw

    Joined:
    Mar 4, 2018
    Posts:
    153
    Thank you very much orb! I will for sure look into this.

    "There are more exceptions to some rules than there are words following said rule in most languages it seems. At least you don't have to deal with K changing between the familiar K-sound to a semi-guttural depending on seemingly random factors, or place names starting with a silent L, like near me"

    Hahahaha, trust me, I am very happy to not have to be dealing with that!
     
  20. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,187
    I just thought I'd add this...

    Code (CSharp):
    1.  
    2. String.IsNullOrEmpty(stringVariable)
    3.  
    4. !String.IsNullOrEmpty(stringVariable)
    5.  
    This will check if the string is null or has no characters. There is also another check if the string has nothing but spaces in it.
     
    Last edited: Nov 13, 2018
    xVergilx, orb and ellenblomw like this.
  21. ellenblomw

    ellenblomw

    Joined:
    Mar 4, 2018
    Posts:
    153
    Thanks Brathnann! Always good to have more alternatives.

    Ok so I've narrowed it down to this. I have the code set for the username, so in another scene the player inputs username and it is stored as a playerPrefs. Then when I need to call the username and I need to put an s after the name I have put together the script below. It works, yey! Buuut, I get an error even though it works.

    Error:

    NullReferenceException: Object reference not set to an instance of an object
    I2.Loc.CallbackBabyCertainSCond.GetParameterValue (System.String ParamName) (at Assets/CallbackBabyCertainSCond.cs:23)
    I2.Loc.LocalizationManager.GetLocalizationParam (System.String ParamName, UnityEngine.GameObject root) (at Assets/I2/Localization/Scripts/Manager/LocalizationManager_Parameters.cs:129)
    I2.Loc.LocalizationManager+<ApplyLocalizationParams>c__AnonStorey4.<>m__0


    It points to the snippet I have marked out in the script below:
    Code (CSharp):
    1. namespace I2.Loc
    2. {
    3. public class CallbackBabyCertainSCond : RegisterGlobalParameters
    4.     {
    5.         private string babyNameL;
    6.         private string babyNameS;
    7.  
    8.         // Use this for initialization
    9.         void Start()
    10.         {
    11.             //Get name of baby, or Baby Boo if no name is choosen
    12.             babyNameL = PlayerPrefs.GetString("NameBaby");
    13.         }
    14.  
    15.         public override string GetParameterValue(string ParamName)
    16.         {
    17.             if (ParamName == "USERS")
    18.             {
    19.                 //Username ends with s? Then do this:
    20.                if (babyNameL.EndsWith("s")) <----- ERROR POINTS TO THIS
    21.                 {
    22.                     babyNameS = babyNameL + "'";
    23.                     return babyNameS;
    24.                 }
    25.  
    26.                 //Username does not end with s? Then do this:
    27.                 if (babyNameL.EndsWith("s") == false)
    28.                 {
    29.                     return babyNameL;
    30.                 }
    31.             }
    32.             return null;
    33.         }
    34.     }
    35. }
    I want to understand this and I want my code error free. Is there anyone out there who understands what the heck I am doing wrong? Or are all of you on Sparrows party :D?
     
    Last edited: Nov 12, 2018
  22. mholmes

    mholmes

    Joined:
    Dec 8, 2012
    Posts:
    414
    1. void Start()
    2. {
    3. //Get name of baby, or Baby Boo if no name is choosen
    4. babyNameL = PlayerPrefs.GetString("NameBaby");
    5. }
    You need to check if your player prefs has a value first before trying to set a value. I don't recommend using player prefs its not a good practice and not reliable. I recently ran into a similar issue where my player pref data was getting magically lost. A good solution would be building a script called "Data" for example. Something like this:

    Sample Data class/script:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using System;
    5. using System.Net;
    6. using System.IO;
    7.  
    8. public class Data : MonoBehaviour
    9. {
    10.     public static Value_1 = "";
    11.     public static Value_2 = "";
    12.     public static Value_3 = "";
    13. }
    I set the values to empty by default. Here is how you will access your data across scenes:

    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using System.IO;
    5. using System.Net;
    6. using UnityEngine;
    7.  
    8. public class A_Generic_Script : MonoBehaviour
    9. {
    10.     private void Do_Something()
    11.     {
    12.         Data.Value_1 = "A New Value";
    13.     }
    14. }
    As you can see in this sample, you can access the data in any script, scene or anywhere you need the data. You also do not need to use Do Not Destroy when you load a new scene. You can also create static functions simular to what your looking for:

    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using System.IO;
    5. using System.Net;
    6. using UnityEngine;
    7.  
    8. public class A_Generic_Script : MonoBehaviour
    9. {
    10.     private void Do_Something()
    11.     {
    12.         Data.Value_1 = "A New Value";
    13.     }
    14.  
    15.     public string Default_Name(string User_Name)
    16.     {
    17.         string strValue = "";
    18.    
    19.         if(User_Name.length < 1)
    20.         {
    21.             strValue = "No Name";
    22.         }
    23.         else
    24.         {
    25.             strValue = User_Name;
    26.         }
    27.        
    28.         Return strValue;
    29.     }
    30. }
    or you could use the your name check system as a global function:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using System;
    5. using System.Net;
    6. using System.IO;
    7.  
    8. public class Data : MonoBehaviour
    9. {
    10.     public static Value_1 = "";
    11.     public static Value_2 = "";
    12.     public static Value_3 = "";
    13.  
    14.     public string Default_Name(string User_Name)
    15.     {
    16.         string strValue = "";
    17.      
    18.         if(User_Name.length < 1)
    19.         {
    20.             strValue = "No Name";
    21.         }
    22.         else
    23.         {
    24.             strValue = User_Name;
    25.         }
    26.          
    27.         Return strValue;
    28.     }
    29. }
    use it like this:

    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using System.IO;
    5. using System.Net;
    6. using UnityEngine;
    7. using UnityEngine.UI;
    8.  
    9. public class A_Generic_Script : MonoBehaviour
    10. {
    11.     public TEXT _Text;
    12.    
    13.     private void Do_Something()
    14.     {
    15.         //Verify Name
    16.         string Name = Data.Default_Name(_Text);
    17.     }
    18.    
    19.    
    20. }
     
  23. ellenblomw

    ellenblomw

    Joined:
    Mar 4, 2018
    Posts:
    153
    Hello, wow and thank you for your thourough reply on using Data. I will for sure look into this and try to switch to it. But right now i have a beta test ongoing with 90 users so I need to get it working with PlayerPrefs. I can not have all the Charles become Charle or Charless :p.

    When you say I need to check if it has a value first, you mean with haskey in start func? Because I dont get any error if I just use the:

    Code (CSharp):
    1. namespace I2.Loc
    2. {
    3. public class CallbackBabyCertainSCond : RegisterGlobalParameters
    4.     {
    5.         private string babyNameL;
    6.  
    7.         // Use this for initialization
    8.         void Start()
    9.         {
    10.             //Get name of baby, or Baby Boo if no name is choosen
    11.             babyNameL = PlayerPrefs.GetString("NameBaby");
    12.         }
    13.  
    14.         public override string GetParameterValue(string ParamName)
    15.         {
    16.             if (ParamName == "USERS”)
    17.                    return babyNameL;
    18.            return null;
    19.        }
    20.    }
    21. }
    This returens the username without the error mentioned above. So I dont see how checking the value in the start func of the more complicated code would solve the error in this case? Could you please explain?
     
    Last edited: Nov 12, 2018
  24. ellenblomw

    ellenblomw

    Joined:
    Mar 4, 2018
    Posts:
    153
    So I fixed the first error, but now I get this second one. But the code works as intended so I don't understand why it says argument is null? It isn't.


    ArgumentNullException: Argument cannot be null.
    Parameter name: value
    System.String.EndsWith (System.String value) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System/String.cs:776)
    I2.Loc.CallbackBabyCertainSCond.GetParameterValue (System.String ParamName) (at Assets/CallbackBabyCertainSCond.cs:25)
    I2.Loc.LocalizationManager.GetLocalizationParam (System.String ParamName, UnityEngine.GameObject root) (at Assets/I2/Localization/Scripts/Manager/LocalizationManager_Parameters.cs:129)
    I2.Loc.LocalizationManager+<ApplyLocalizationParams>c__AnonStorey4.<>m__0 (System.String p) (at Assets/I2/Localization/Scripts/Manager/LocalizationManager_Parameters.cs:29)
    I2.Loc.LocalizationManager.ApplyLocalizationParams (System.String& translation, I2.Loc._GetParam getParam, Boolean allowLocalizedParameters) (at Assets/I2/Localization/Scripts/Manager/LocalizationManager_Parameters.cs:72)
    I2.Loc.LocalizationManager.ApplyLocalizationParams (System.String& translation, UnityEngine.GameObject root, Boolean allowLocalizedParameters) (at Assets/I2/Localization/Scripts/Manager/LocalizationManager_Parameters.cs:29)
    I2.Loc.Localize.OnLocalize (Boolean Force) (at Assets/I2/Localization/Scripts/Localize.cs:190)
    I2.Loc.Localize.Awake () (at Assets/I2/Localization/Scripts/Localize.cs:115)


    Code right now:
    Code (CSharp):
    1.         public override string GetParameterValue(string ParamName)
    2.         {
    3.             if (ParamName == "BABYS")
    4.             {
    5.                 if (babyNameL != null) {
    6.                 //Name of baby username ends with s? Then do this:
    7.                 if (babyNameL.EndsWith(lookfor))
    8.                 {
    9.                     babyNameS = babyNameL + "'";
    10.                     return babyNameS;
    11.                 }
    12.  
    13.                 //Name of baby username does not end with s? Then do this:
    14.                 if (babyNameL.EndsWith("s") == false)
    15.                 {
    16.                     return babyNameL;
    17.                 }
    18.             }
    19.             }
    20.             return null;
    21.         }
    Error is for line: if (babyNameL.EndsWith(lookfor))
     
    Last edited: Nov 13, 2018
  25. ellenblomw

    ellenblomw

    Joined:
    Mar 4, 2018
    Posts:
    153
    Solved it, couldn't put a "lookfor" variable in the line, had to use "s". In case anyone runs into this thread and wants to know
     
  26. orb

    orb

    Joined:
    Nov 24, 2010
    Posts:
    3,037
    Yeah, I'd call that variable "postfix" or "tail" or something :)