Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

[NOT SOLVED][C#] Saving variables from inspector, same script on multiple objects

Discussion in 'Scripting' started by Elmdran, Jan 4, 2015.

  1. Elmdran

    Elmdran

    Joined:
    Oct 28, 2014
    Posts:
    34
    Hello. I'm making an incremental game and I have a script that handles the different items you can buy and that script is on all of the items, I set the prices for each individual item in the inspector and I'm trying to save this using playerprefs.

    This is what it looks like now:

    Code (CSharp):
    1.  
    2. public class ItemManager : MonoBehaviour {
    3.  
    4.     public UnityEngine.UI.Text itemInfo;
    5.     public Click click;
    6.     public float cost;
    7.     public int tickValue;
    8.     public int count;
    9.     public string itemName;
    10.     private float baseCost;
    11.  
    12.     void Awake(){
    13.         cost = PlayerPrefs.GetFloat ("ItemCost");
    14.         tickValue = PlayerPrefs.GetInt ("ItemTick");
    15.         count = PlayerPrefs.GetInt ("Amount");
    16.     }
    17.  
    18.     void OnApplicationQuit(){
    19.         PlayerPrefs.SetFloat ("ItemCost", cost);
    20.         PlayerPrefs.SetInt ("ItemTick", tickValue);
    21.         PlayerPrefs.SetInt ("Amount", count);
    22.     }
    23. }
    24.  
    But when I start the game all values are set to 0. Is there a solution to this or should I use a different method of saving? Thanks!
     
  2. renman3000

    renman3000

    Joined:
    Nov 7, 2011
    Posts:
    6,680
    I am wondering if PlayerPrefs.Save(); is whats needed.
     
  3. Elmdran

    Elmdran

    Joined:
    Oct 28, 2014
    Posts:
    34
    Do you have any idea on how I could otherwise solve this?
     
  4. renman3000

    renman3000

    Joined:
    Nov 7, 2011
    Posts:
    6,680
    It is just a suggestion. Add that line in after your series of sets.
     
  5. Elmdran

    Elmdran

    Joined:
    Oct 28, 2014
    Posts:
    34
    Ah, well I tried that and it doesn't work. When I play everything costs 0, I have 0 of every item and I get 0 tickvalue
     
  6. renman3000

    renman3000

    Joined:
    Nov 7, 2011
    Posts:
    6,680
    Not sure what to tell you. I have used this before and it worked. Tho, I did not retrieve values on Awake, nor set on application quit
     
  7. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,377
    This is on EVERY item? So there's more than one?

    But it sets the same playerprefs in every single one.

    This means that the value in the LAST item that has OnApplicationQuit called will be the ones saved. Whatever values are in that specific item will be the value in it when everything loads back up. And if it has 0 for all the values, then it's going to be 0.
     
  8. fire7side

    fire7side

    Joined:
    Oct 15, 2012
    Posts:
    1,819
    If you have the same script on all the items accessing the same variable, that doesn't seem like it will work. Each object will need a unique variable name to keep it all straight. I don't really see anything wrong with your save code. You might want to just get a key input or something while you are working on the script. It would probably be better to put all the objects into an array, and then save the variables from one save script, giving them a unique name. I think there may be a script on the wiki that might help with that.
     
  9. DRRosen3

    DRRosen3

    Joined:
    Jan 30, 2014
    Posts:
    681
    You're going to need to make a database by making a List<T> of these items, and then find a way to save that list somewhere.
     
  10. Elmdran

    Elmdran

    Joined:
    Oct 28, 2014
    Posts:
    34
    I have an array of all the items in another script, could I just make a for loop to cycle through those items, and go
    PlayerPrefs.SetInt("item1" + i);
    i++;

    and the same thing for loading them?¨

    EDIT: Made a horrible attempt at getting that to work.
     
    Last edited: Jan 4, 2015
  11. fire7side

    fire7side

    Joined:
    Oct 15, 2012
    Posts:
    1,819
    The array will have to hold only the integers and floats from the objects, so you make an int array, same size as object array, and then fill it with a for loop by getting the object and the value. Then save it, and do the reverse when loading. The array script is here: http://wiki.unity3d.com/index.php/ArrayPrefs2
     
  12. Elmdran

    Elmdran

    Joined:
    Oct 28, 2014
    Posts:
    34
    Thanks for the reply but I'm afraid I'm too noob to make anything of that. I need some assistance, how do I start?
     
  13. fire7side

    fire7side

    Joined:
    Oct 15, 2012
    Posts:
    1,819
    Ok, say you have an int which is GoldBags on each GameObject.
    I don't know what type of array you used, and that determines how you get the size of the array, but for a built in array I think you use Length:
    Code (csharp):
    1.  
    2. int[] goldBagNumber = new Int[gameObjectArray.Length];
    3. for(int i = 0; i < gameObjectArray.Length; i++){
    4. goldBagNumber[i] = gameObjectArray[i].GetComponent<scriptName>().goldbags;
    5. }
    6.  
    Then get the script I linked and read how you save an array and use that script to save it, and do the reverse to load.
     
  14. Elmdran

    Elmdran

    Joined:
    Oct 28, 2014
    Posts:
    34
    I'm trying the best I can, am I close?
    Code (CSharp):
    1. void OnApplicationQuit(){
    2.         int[] itemNumber = new int[items.Length];
    3.         for (int i = 0; i < items.Length; i++) {
    4.             itemNumber[i] = items[i].GetComponent<ItemManager>().cost;
    5.             PlayerPrefsX.SetIntArray("ItemCosts", itemNumber);
    6.             PlayerPrefs.Save();
    7.         }
    8.     }
    And would I need to create another for loop to load the playerprefs in Start?
     
  15. DRRosen3

    DRRosen3

    Joined:
    Jan 30, 2014
    Posts:
    681
    You don't want to use an Array. Array's are unchangeable (in size). You want something more dynamic, which is why I suggested a List. List's sizes can be changed, while array's cannot.
     
  16. Tomnnn

    Tomnnn

    Joined:
    May 23, 2013
    Posts:
    4,148
    You can also write your own serialize function to save all of your data to a text file. Make a string, save all of your values into that string separated by a delimiter of choice, write it to a text file. When your program runs, load the values out of the text file, separating the string into a string[] with the split function and converting values to numbers.

    If you get good at that, you can save any kind of data. You can also choose a different directory and have more flexibility than playerprefs (if it's not a web game). You even have the option to store the data in an external text file, for future mod support in other games :D
     
  17. Elmdran

    Elmdran

    Joined:
    Oct 28, 2014
    Posts:
    34
    Care to get me started on that? Like how would it work saving data from the diffrerent gameobjects without having an array. Until I tried that as well, fire7side I feel like I'm close but it doesn't work yet. I have a separate script called SaveData.cs and this is what I've got:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class SaveData : MonoBehaviour {
    5.  
    6.     public GameObject[] items;
    7.  
    8.     void Start(){
    9.         int[] itemLoad = new int[items.Length];
    10.         for (int i = 0; i < items.Length; i++) {
    11.             itemLoad[i] = items[i].GetComponent<UpgradeManager>().cost;
    12.             PlayerPrefsX.GetIntArray("ItemCosts");
    13.         }
    14.     }
    15.  
    16.     void OnApplicationQuit(){
    17.         int[] itemSave = new int[items.Length];
    18.         for (int i = 0; i < items.Length; i++) {
    19.             itemSave[i] = items[i].GetComponent<UpgradeManager>().cost;
    20.             PlayerPrefsX.SetIntArray("ItemCosts", itemSave);
    21.             Debug.Log ("Saved: " + itemSave);
    22.         }
    23.     }
    24. }
    The gameobjects array I just dragged in my three items that I want to save data to from.
    My debug says "Saved: System.Int32[]" three times and if I debug
    Code (csharp):
    1. itemSave[i]
    i get "Saved: 10, 30, 60", which is the costs of the items of the objects.
     
  18. DRRosen3

    DRRosen3

    Joined:
    Jan 30, 2014
    Posts:
    681
    Tomnnn hinted at it. You're going to need to be able to serialize all of this. You have a bunch of items, if I understand the original post correctly. You can create a new script (and let's say call it ItemDatabase). In that script, you create a List<T> of items (List<Item>). Anytime you have a new item (one that doesn't match one in the list already) you add that item to the list. Then when it comes time to save all of this, you serialize the list. When you need to load all of it, you deserialize it. You'll have to use Google to get your head wrapped around all of it. Without seeing ALL of your code I can't write it for you.
     
  19. Elmdran

    Elmdran

    Joined:
    Oct 28, 2014
    Posts:
    34
    Well if you have time https://drive.google.com/folderview?id=0B9QmgFdXd_dtYm1kN0MyWmlBRWM&usp=sharing here is all of my code :)
     
  20. DRRosen3

    DRRosen3

    Joined:
    Jan 30, 2014
    Posts:
    681
    I'll see what I can do, but no promises though. I'm working on a project of my own currently. In any case, you should do some research on serializing, because even if I do write the code for you, you'll need to be able to understand it.
     
  21. Elmdran

    Elmdran

    Joined:
    Oct 28, 2014
    Posts:
    34
    Understanding the code I'm good at, figuring out how to type it is a whole other thing. Thank you so much for answering by the way and if you were to take your time and help me.
     
  22. fire7side

    fire7side

    Joined:
    Oct 15, 2012
    Posts:
    1,819
    Well, it looks like it worked to me, you just didn't read it back into an array and fill the object array. I also don't agree with having someone else write your code for you. It's not that hard and the whole purpose is learning how to do this stuff. You only need an array for the save, you can keep the objects in a list if they vary. However, playerprefs is for a limited amount of information, so if you are going to do huge saves you will need to serialize. There's a tutorial here:
    http://gamedevelopment.tutsplus.com...oad-your-players-progress-in-unity--cms-20934
    If you have someone do it for you, you are only cheating yourself. It's like not learning to read and faking it the rest of your life.
    Whenever I do something like this, I start a new project and do a simplified version. Then when I understand it, I add it to my main project.
    I haven't even saved a game yet. I haven't quite finished, but I have total confidence I can do it because I didn't cheat and have someone else write my scripts for me.
     
    Last edited: Jan 4, 2015
  23. Elmdran

    Elmdran

    Joined:
    Oct 28, 2014
    Posts:
    34
    I thought that is what I was doing in the Start function
     
  24. fire7side

    fire7side

    Joined:
    Oct 15, 2012
    Posts:
    1,819
    OK, yeah, you have to reverse the process. The object array is equal to the items you are loading.
     
  25. Elmdran

    Elmdran

    Joined:
    Oct 28, 2014
    Posts:
    34
    I'm trying this
    Code (CSharp):
    1. void Start(){
    2.         itemSave = new int[items.Length];
    3.         int[] itemLoad = new int[items.Length];
    4.         for (int i = 0; i < items.Length; i++) {
    5.             itemLoad[i] = PlayerPrefsX.GetIntArray("ItemCosts");
    6.            
    7.         }
    8.     }
    But I just get Cannot implicitly convert type `int[]' to `int'
     
  26. Dameon_

    Dameon_

    Joined:
    Apr 11, 2014
    Posts:
    542
    #1: This approach is terrible. As already stated, serialization is what's needed here.

    #2: @Elmdran - you are obviously out of your depth and need to spend more time on the basics before you tackle this. You're attempting to store an array into a non-array variable. If you understood arrays and variables properly, this wouldn't be happening, and you would understand the error message you're getting.

    It's frustratingly common to see people jump in the deep end when they have yet to grasp the basics, grabbing snippets of code and trying to make them suit a purpose with nearly random changes. Eventually, they create a tangled snarl of code that doesn't work, or manifests weird bugs, or uses hundreds of lines of code to do something that only takes a few lines.

    You have to learn to walk before you can run. Otherwise, you wind up with a thread with over 20 responses trying to walk you through saving and loading an array step by step.
     
    Tomnnn likes this.
  27. fire7side

    fire7side

    Joined:
    Oct 15, 2012
    Posts:
    1,819
    Actually, I'm not even sure what you are doing there, but saving is as simple as:
    PlayerPrefsX.SetIntArray("ItemCosts", intArray_I_JustFilled);

    Loading is: empty_array_I_just_created = PlayerPrefsX.GetIntArray("ItemCosts");

    You have already filled the array, so it shouldn't be hard.

    That's it. You just have to fill the int array before you save it.
    When you load you just create and array and have it equal the loaded array.
     
  28. Tomnnn

    Tomnnn

    Joined:
    May 23, 2013
    Posts:
    4,148
    Maybe if this thread goes on too long I'll just post the source for an older game of mine that used plain text saving & loading :p
     
    image28 likes this.
  29. image28

    image28

    Joined:
    Jul 17, 2013
    Posts:
    457
    funny
     
  30. fire7side

    fire7side

    Joined:
    Oct 15, 2012
    Posts:
    1,819
    Playerprefs is a good solution for many circumstances and worth knowing. It's the best place to start as a programmer. Why doesn't he just play games and not bother writing them?
     
  31. Tomnnn

    Tomnnn

    Joined:
    May 23, 2013
    Posts:
    4,148
    PlayerPrefs is probably the only inexpensive solution for web, but for desktop serializing large amounts of data might get messy if you try to make a terrain chunking system and save huge strings into playerprefs. You can also customize and extend the functionality of a serializing solution you've made yourself / have access to the source of.

    It's from 2 years ago and tailored to the project written at the time, but here it is :D

    @Elmdran if you can read code well, there will be a lot of useful things here. I use "/../" because I was saving to an external folder, since I wanted players to be able to read and modify their character files. Parsing that data into something useful is in another class.

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class Utils
    5. {
    6.     //check for game directory
    7.     public static void fixFolders()
    8.     {
    9.         string path = Application.dataPath + "/../OpenFiles";
    10.         if(!System.IO.Directory.Exists(path))
    11.         {
    12.             System.IO.Directory.CreateDirectory(path);
    13.             System.IO.Directory.CreateDirectory(path + "/characters/");
    14.             System.IO.Directory.CreateDirectory(path + "/userpref/");
    15.         }
    16.     }//fixFolders
    17.  
    18.     //append specifics to path and then save
    19.     public static bool saveData(string datapath, string data)
    20.     {
    21.         string filename = data.Split("\n"[0])[0];
    22.         filename = filename.Substring(5);
    23.         string path = Application.dataPath + "/../OpenFiles/characters/" + filename + "/";//dir
    24.         if(!System.IO.Directory.Exists(path))
    25.         {
    26.             System.IO.Directory.CreateDirectory(path);
    27.             path += "chardata.txt";//file
    28.             System.IO.File.WriteAllText(path, data);
    29.             return true;
    30.         }
    31.         else if(System.IO.Directory.Exists(path))//overwrite existing
    32.         {
    33.             path += "chardata.txt";
    34.             System.IO.File.WriteAllText(path, data);
    35.             return true;
    36.         }
    37.  
    38.         return false;//character create / save failed for some reason
    39.     }//saveData
    40.  
    41.     //crash log for stuffs
    42.     public static void logCrash(string r)
    43.     {
    44.         string filename = "Crash_" + System.DateTime.Now;
    45.         string path = Application.dataPath + "/../OpenFiles/" + filename + ".txt";
    46.  
    47.         string error = "The application was closed because of the following:";
    48.         error += r;
    49.  
    50.         System.IO.File.WriteAllText(path, error);
    51.  
    52.     }//logCrash
    53.  
    54.     //append specifics to path and return info
    55.     public static string loadData(string datapath)
    56.     {
    57.         string path = Application.dataPath + "/../OpenFiles/characters/" + datapath + "/chardata.txt";
    58.         if(System.IO.File.Exists(path))
    59.         {
    60.             return System.IO.File.ReadAllText(path);
    61.         }
    62.        
    63.         return null;
    64.     }//loadData
    65.  
    66.     //delete character directory
    67.     public static void deleteData(string data)
    68.     {
    69.         string path = Application.dataPath + "/../OpenFiles/characters/" + data + "/";
    70.        
    71.         if(System.IO.Directory.Exists(path))
    72.         {
    73.             System.IO.Directory.Delete(path, true);
    74.         }
    75.     }//deleteData
    76.  
    77.     //get list of folders in the char dir
    78.     public static string[] getCharList()
    79.     {
    80.         string path = Application.dataPath + "/../OpenFiles/characters/";
    81.         string[] charNames = System.IO.Directory.GetDirectories(path);
    82.         for(int i = 0;i < charNames.Length;i++)
    83.         {
    84.             charNames[i] = charNames[i].Substring(charNames[i].LastIndexOf("/")+1);
    85.         }
    86.         return charNames;
    87.     }//getCharList
    88.  
    89.     //debug for editor only
    90.     public static void uDebug(string text)
    91.     {
    92.         if(Application.isEditor)
    93.             Debug.Log(text);
    94.     }//uDebug
    95.  
    96. }//class
    97.