Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

C#: Getting class instance/object from string? (or other suggestions)

Discussion in 'Scripting' started by MDragon, Jan 17, 2014.

  1. MDragon

    MDragon

    Joined:
    Dec 26, 2013
    Posts:
    329
    Hello there,

    I've spent pretty much the last two hours on this, excluding the amount of time I spent brainstorming and testing before leading up to this solution.

    Basically, I'm still working on a saving and loading system, but I realized I have to split my data into two parts: permanent data and temporary stored data. I can easily get the temporary stored data (or so I think...), but my problem is getting the permanent data.

    What I did was create a base class, create an instance of that class (or is it called an object?) that has all the data filled in for that level or such, and then I am attempting to get that filled in class by name. However, this is done by typing in the name of the class's instance (like "W1L1" - a relatively simple system) so I can get the matching instance's data.

    However, I may end up with a ton of these instances (my levels alone would be the majority, but still, they'd be a ton). And so, rather than a million if or switch statements to compare that string to pre-defined names (again- each instance has its own name value for quick output purposes). I've come upon System.Reflections (Type.GetType(name)), but that doesn't seem to work.

    Any suggestions? Please feel free to ask for clarifications, because I have no idea how well I described this. Also, here are primary snippets of my code:

    (Also, please note that I basically learned and am learning C# by myself as I go. Took quite a bit to figure out all at once classes, "instances" (or objects?), static objects/instances/variables (rather than static classes), enums, and such. My terminology may thus be quite a bit off. And it's public static on purpose so I can very easily access the data- which may not make sense now that I think about it, since those are just reference instances that won't be used. Rather, the copy instances/variables will be used globally... I may have wrote this last sentence wrong)

    Code (csharp):
    1. public class Control : MonoBehaviour {
    2.     public LevelType thisType;    // for choosing enum, for a quick switch statement. Very general script
    3.         // ignore the above line if you wish, but it basically defines if the current scene is a level select, world select, or inside a level
    4.     public string levelIDInput;
    5.         // Input from Inspector, the above is how the instance is matched and then assigned... theoretically
    6.        
    7.         public enum LevelType{
    8.         Other,
    9.         WorldSelect,
    10.         LevelSelect,
    11.         Game
    12.     }
    13.    
    14.     // Next two sets are the base classes
    15.     public class levelData{
    16.         public string worldID{ get; set;}
    17.         public string levelID{ get; set;}
    18.         public string levelName{ get; set;}
    19.         public int totalPickups{ get; set;}
    20.         public bool secretCheck{ get; set;}
    21.     }
    22.  
    23.     public class worldData{
    24.         public string worldID{ get; set;}
    25.         public int levelsTotal{ get; set;}
    26.         public int secretsTotal{ get; set;}
    27.     }
    28.    
    29.     // Next two sets are examples of instances, one of each
    30.     public static worldData W1 = new worldData{
    31.         worldID = "W1",
    32.         levelsTotal = 4,
    33.         secretsTotal = 0
    34.     };
    35.    
    36.     public static levelData W1L1 = new levelData{
    37.         worldID = "W1",
    38.         levelID = "W1L1",
    39.         levelName = "The Beginning",
    40.         totalPickups = 6,
    41.         secretCheck = false
    42.     };
    43.    
    44.         void Start () {        // Uses enum to define what type of scene this is, then acts accordinly    
    45.         if (thisType == LevelType.Other) {
    46.             print ("Undefined LevelType?");
    47.         }
    48.  
    49.         if (thisType == LevelType.WorldSelect) {
    50.             print ("This is a world menu!");
    51.             // Some random testing removed
    52.         }
    53.  
    54.         if (thisType == LevelType.LevelSelect){
    55.             print ("This is a level menu!");
    56.         }
    57.  
    58.         if(thisType == LevelType.Game){
    59.             Type thisLevel = Type.GetType(levelIDInput);
    60.             // The above is what I tried, then I would get all the values
    61.             //         of the class instance into more scene-wise permanent variables
    62.             //        for a variety of uses, including in other programs
    63.            
    64.             //Quite a bit of not-so-random testing removed
    65.         }
    66.     }
    67.    
    68. }
    Edit: Added a bit to the code that was more or less necessary
     
    Last edited: Jan 17, 2014
  2. BrUnO-XaVIeR

    BrUnO-XaVIeR

    Joined:
    Dec 6, 2010
    Posts:
    1,687
    This doesn't make much sense. You try to read/write properties of an object that is not an object.
    If you have an object and need to know its type before doing something you simple do

    object.GetType() == typeof(T);
     
  3. MDragon

    MDragon

    Joined:
    Dec 26, 2013
    Posts:
    329
    Ignore my example (on line 59). It was me working in circles, trying to find a solution.

    Actually, if I can just get a way to use the Inspector to easily select one of those objects, that would solve this. However, listing every single class would be unreasonable, which is why I'm trying to just use a typed–into string.

    So... Ignoring my example, how would I READ or otherwise get an object (and therefore its values) by having the name in a string?
     
    Last edited: Jan 17, 2014
  4. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Why not just serialize to XML, Bson or Json?
     
  5. MDragon

    MDragon

    Joined:
    Dec 26, 2013
    Posts:
    329
    Hmm... I've heard of Json, but know nothing about it or Bson. However, XML I sort of have some experience with (messed with some files during web development, and it's pretty easy and simple to edit at least), but zero with programming. I guess I'll start to look into XML. :) I remember various threads going over XML, but I wasn't sure if it was really necessary.

    However, what would be an example of this? Would I move all the data to XML? How would I call it, in pseudo-code, with a string?

    Sorry if somehow my words came out as a garbled message of misconceptions. I'm sort of brain dead with a headache at the moment.
     
  6. Flipbookee

    Flipbookee

    Joined:
    Jun 2, 2012
    Posts:
    2,788
    Why not just serialize using Unity's built-in serialization? From your example it looks like at runtime you will only have to read the data, so using ScriptableObject and custom assets would fit perfectly.
     
  7. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    This is you're doing simple stuff. Or you can use PlayerPrefs to store some data if you're not going overboard. Or if you want to do something dynamic you could do it with my JSON .NET asset. For example, let's say you have a class called LeadPipe:

    Code (csharp):
    1.  
    2. public class LeadPipe
    3. {
    4.       public int Damage { get; set; }
    5.       public int Health { get; set; }
    6.       public string DisplayName = "Lead Pipe";
    7. }
    8.  
    Now to serialize it you just do:

    Code (csharp):
    1.  
    2. var pipe = new LeadPipe() { Damage = 520, Health = 100 };
    3.  
    4. var pipeAsString = JsonConvert.SerializeObject(pipe);
    5.  
    Now that pipe object is converted to a string and you can save it to disk or whatever. Now to turn it back into a LeadPiple, load the string and do this:

    Code (csharp):
    1.  
    2.  
    3. var pipe = JsonConvert.DeserializeObject<LeadPipe>(pipeAsString);
    4.  
    5.  
    And there you have it... from a string back to a pipe again.

    https://www.assetstore.unity3d.com/#/content/11347
     
  8. MDragon

    MDragon

    Joined:
    Dec 26, 2013
    Posts:
    329
    Sorry, forgot to mention a few things:
    1) Not trying to buy any assets. My overall game is pretty simple
    2) This is for mobile development. Would this work?
    3) Would the XML work without another (large) overhaul?

    Edit: I see that it works for C# - although I'm not sure if I'll use it as the $20 doesn't seem worth it for something so "simple".
     
    Last edited: Jan 17, 2014
  9. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Not a problem. I would still suggest Json. Have a look at JSON Object. It's a little more work to use (a little more manual) but it's free. I'm not sure if it actually instantiates classes for you though or if you have to do that manually.

    https://www.assetstore.unity3d.com/#/content/710

    There's also SimpleJSON, LitJSON and JsonFX but each has its own shortcomings. Some do not handle collections properly, and some do not work at all on Mobile. I couldn't really tell you on mobile support, you'd just have to read up on them but they are all alternatives.

    XML as long as you're inheriting from ScriptableObject should work but I think there are some things that the built in Unity serializer doesn't work with, just don't remember off the top of my head. Also can't speak to mobile support on that. The different mobile platforms have varying degrees of implementation for the XML classes.
     
  10. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    I would agree with using AssetDatabase for your serialization. It comes with Unity and it works great, no matter the complexity of your data. You basically save a .asset in Resources folder and then you can load it up any time you want, mobile, webplayer, any platform.

    I got some pretty wicked class structures in a "temple run" style game. I had the whole game auto-generated from data serialized into a single file, including all the references towards prefabs, texture, and so on.

    JSon is great if you need to pass your data over the web, using WWW. Or if you need to serialized data outside the editor's scope. If you don't have to do that, there's no point is not using AssetDatabase.

    As for Type.GetType(string) not working, it's because you were using the class name, not the class assembly-qualified name. Really not the same thing. An assembly-qualified name looks like "TopNamespace.Sub\+Namespace.ContainingClass+NestedClass, MyAssembly, Version=1.3.0.0, Culture=neutral, PublicKeyToken=b17a5c561934e089"... Kind of a mess, but you're not suppose to type that by hand.
     
  11. MDragon

    MDragon

    Joined:
    Dec 26, 2013
    Posts:
    329
    Sorry for throwing more questions at potential solutions, but I can't find much info on creating a ". asset" file or using one for serialization. I've primarily just found methods to import, copy, etc assets as a whole. Am I supposed to make an XML file and use that somehow?

    Once again, sorry for the constant questions, but not sure where to really go next with this.

    Edit: After finally getting a tad bit off my headache, I decided to connect all the related info in this thread.

    Basically... I have to pay attention to ScriptableObjects, Serializing (had to honestly look up that definition), and AssetDatabase.

    Well, I guess it's time for me to delve into these things:
    1) How to serialize my current classes and make them into ScriptableObjects
    2) How to store those objects into .assets
    3) How to retrieve the data from those .assets serialized ScriptableObjects

    I haven't done too much research - I've found the first trails for the first two questions already in my preliminary searching and have yet to find #3 (and would appreciate a bit of leading again for this :D) - but thank you everybody for the information here. Although tonight's at an end for me, it seems like tomorrow will be full of progress.
    (End corny ending that was added for no reason, I blame the remaining bits of the headache ;) )

    Edit2:
    Ah, a beautiful intro to all three parts (or such) that I listed above....
    http://ivanozanchetta.com/gamedev/unity3d/unity-serialization-behind-scriptableobject/
    Once again, thank you.
     
    Last edited: Jan 17, 2014
  12. BrUnO-XaVIeR

    BrUnO-XaVIeR

    Joined:
    Dec 6, 2010
    Posts:
    1,687
    You write .asset files using System.IO just like writing any other files on .Net;
    I'm building a GDD toolset for my future projects and what I do there is I save the class object itself because I built those classes as ISerializable, you save the class instance to a file and C# can recreate the instance from that binary file stream. This is great for editor tools, performance is great, but for in-game you're proly better off with xml and scriptableObjects.
    Google out for C# serialization and System.IO.
     
  13. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    No. You write .asset using AssetDatabase. If it's in binary, Unity won't be able to read it natively and you'll be left alone to rebuild your object by yourself. A lot of pain for no real gain.
     
  14. MDragon

    MDragon

    Joined:
    Dec 26, 2013
    Posts:
    329