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. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

[Solved]Need the right way to get thousands of lines of data into my application

Discussion in 'Scripting' started by Svarr, Dec 21, 2015.

  1. Svarr

    Svarr

    Joined:
    Dec 20, 2015
    Posts:
    22
    Hi,
    I have created a class with a constructor. That class contains some strings, integers, a sprite and a List<String>.
    Now, for every instance of the class I need at least 3 lines of code (one for construction, one for construction of the List and - if that list only has to contain one entry - one List<string>.Add()).
    Additionally I need to create a property for every single sprite and fill it in the editor by hand (the Resource.Load() function didn't work).

    All of the above is not a big deal ... yet.
    When I'm done, I will have written over 700 instances of that class (if instance is the right term for it), pumping more than 2,100 lines of code into the script (at least it doesn't contain anything else).

    My question is, is that OK, or is there a better way to achieve what I want? (Like writing all the class instances into an external file or database the script can read)
    Thank you for your time. :D
     
  2. zrrz

    zrrz

    Joined:
    Nov 14, 2012
    Posts:
    40
    No one is going to arrest you for it, but yes there is probably a better way.
    Some solutions in *sort of* ascending order of difficulty.
    1. Add all your parameters into a list and then use a for loop, like so:
      Code (CSharp):
      1.  
      2. Foo[] parameters = {1, 2, 3...};
      3. void CreateObjects() {
      4.     for(int i = 0; i < numObjs; i++) {
      5.         myObjects.Add(new MyObject());
      6.         myObjects[i].foo = parameters[i];
      7.     }
      8. }
      9.  
    2. Use JSON or XML. There are some good editors out there that make it easy to enter data. From there you just use .NETs XML parser or download a JSON parser.
    3. Reevaluate your need for 700 instances of a class. Maybe you actually want a dataset of some kind and just a class to access that?
    If you need further help, put some code up on github or pastebin and let us see it.

    Also, Resources.Load works great but can be tricky. If you need help getting that to work, let me know.
     
  3. Celestipoo

    Celestipoo

    Joined:
    Jul 1, 2013
    Posts:
    379
    Check out Game Data Editor. You can put all your data in a spreadsheet and import it with GDE, then use the GDE code generation to create the classes you need to interact with your data.
     
  4. Svarr

    Svarr

    Joined:
    Dec 20, 2015
    Posts:
    22
    Thank you for your reply.
    1. I'm not sure if I understand it. For every parameter my Class takes, I would have to create an array? So the class instances get constructed with default values, put into a list(which happens anyway [meaning I put them into a List via constructor as of now]) and not till then their properties get their real values?
    Haven't thought of that. Why is it that the new MyObject() isn't named? They can exist inside a List without being defined as a property in the script? That would be incredible, since I totally forgot about the problem of having over 700 variables in that script (spamming the Mono recommendations), when I started this thread. And I would get rid of the ID class property...
    But CreateObjects() would have to be called every time the game starts, right?

    2. Having a json or xml file would make this data easily editable by anyone. In effect that's not really a problem but I like to pretend I'm working on a product which is to be released. I do this to practice working with Unity and approaching it with this premise seems to me like a reasonable thing (making me care for things that I personally would disregard). Or would the file be built into the game (as an asset)?

    3. What would a dataset look like?

    Resources.Load
    It would be a great relief to get this working. This is my attempt.
    Code (CSharp):
    1. stringpathtest=Application.dataPath + "/Sprites_Textures/Cards/spr1.png";
    This string printed resembles the correct path from C:/ right to the file. In the documentation there is only a name given. So I tried it without ".png", which didn't work either. Now I'll try it with removing certain parts of the path (ie. Application.dataPath). Do I need to create a folder named "Resources" in the Assets folder? I think that's the only thing I haven't tried yet.


    Thanks for your reply. Buying Software for this project shouldn't be necessary, as I won't publish it (I would get in trouble copyright-wise ;) ).
    But I'll try and keep the GDE in the back of my head if I ever work on a commercial project.
     
    Celestipoo likes this.
  5. Celestipoo

    Celestipoo

    Joined:
    Jul 1, 2013
    Posts:
    379
    Saving time is valuable for both personal and commercial products. Good luck :)
     
  6. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Just obfuscate before launch if editing the file worries you. Or load it all at editor time and let unity serialise it into the build.
     
  7. Flipbookee

    Flipbookee

    Joined:
    Jun 2, 2012
    Posts:
    2,751
    @Svarr, I may be wrong, but I think you want to store that data in a static List field so that it will be initialized only once and shared between all instances?
     
  8. Svarr

    Svarr

    Joined:
    Dec 20, 2015
    Posts:
    22
    This is correct.
     
  9. zrrz

    zrrz

    Joined:
    Nov 14, 2012
    Posts:
    40
    I just meant that writing them all into an array/list and then iterating through that list can be cleaner than putting the variables in class by class.
    I also definitely suggest overloading your default constructor if you go this route, like so:
    Code (CSharp):
    1.  
    2. class MyObject {
    3. public MyObject(int num, string str, List<Foo> foos) {_num = num; _str = str; _foos = foos; }
    4. }
    5.  
    Note that you can't have a constructor if you derive from MonoBehaviour. Disregard if inheriting from MonoBehaviour is necessary.
    C# is a pointer-based language. As long as SOMETHING has a reference to it the garbage collector will not destroy it. Because of that,
    Code (CSharp):
    1. myObjects.Add(new MyObject());
    works just fine because the list has a reference to it.

    Yes it has to be called every time the game starts. But calling a function that loops 700 times is the same thing as calling a function 700 times performance-wise.

    If the XML/JSON file is getting sent locally with the game, then you're correct that it could be edited. If you are downloading it from a read only server, then editing it gets significantly more difficult.
    You could look into using unitys ScriptableObject class to create an editor script that would let you enter the info in a spreadsheet/XML-like way. The ScriptableObject should get built into binary with the game. If you go this route be prepared for a little headache with UnityEditor if you're not familiar with it.

    I worded this poorly. I meant a database or something like Game Data Editor that Celestipoo suggested (though I haven't tried that one).

    From http://docs.unity3d.com/ScriptReference/Resources.Load.html "Returns the asset at path if it can be found otherwise returns null. Only objects of type will be returned if this parameter is supplied. The path is relative to any Resources folder inside the Assets folder of your project, extensions must be omitted." So yea, it has to be in the Resources folder in the Assets folder, and you don't use file extensions.
     
  10. Svarr

    Svarr

    Joined:
    Dec 20, 2015
    Posts:
    22
    I already have overloaded the constructor. The class doesn't contain anything else except a CompareTo method (-> derives from IComparable), which I will probably drop if I do it like your first suggestion.

    Nice!



    I don't really want to get into ScriptableObjects and Unity's serialisation right now.


    The only database I kind of know is mySQL. And I have no idea how I could get data from there into Unity. At any rate, I would have to write the code that populates the database which is the same as writing that code in a Unity Script (plus the code that implements the database in the first place).
    So I think my best option is your first solution (or the version how I understood it).


    I've read that today and tried it. It didn't work either.

    A huge thank you for your help so far! :D
     
  11. Svarr

    Svarr

    Joined:
    Dec 20, 2015
    Posts:
    22
    Update on the Resources.Load problem:
    I have added the second param (typeof(Sprite)) and now it works like a charm.
     
  12. Svarr

    Svarr

    Joined:
    Dec 20, 2015
    Posts:
    22
    Changed Title.
    I now have a reliable way to import the objects. All int and string props get read out from a file and sprites and lists get filled via script.