Im looking for a way to access the Nth object of a JS class. for example, heres my script: (note that its basically a mock up for the time being)
public var Inv :List.<Items>;
public class Items{
var Name : String;
var Image : Texture;
var Level : int;
var Unlocked : boolean;
var Amount : double;
var Exp : double;
public function Items(Name, Image, Level, Unlocked, Amount, Exp){
this.Name = Name;
this.Image = Image;
this.Level = Level;
this.Unlocked = Unlocked;
this.Amount = Amount;
this.Exp = Exp;
}
}
public var Skill :List.<SkillInfo>;
public class SkillInfo{
var Name : String;
var Image : Texture;
var Level : int;
var Exp : double;
var ExpNext : double;
var Maxed : boolean;
public function SkillInfo(Name, Image, Level, Exp, ExpNext, Maxed){
this.Name = Name;
this.Image = Image;
this.Level = Level;
this.Exp = Exp;
this.ExpNext = ExpNext;
this.Maxed = Maxed;
}
}
so what i want to be able to do is find the say : 5th element, in the 1st Inv list in the 1th list list lol(like [0].lists.[0][5] would return like “true” (if unlocked for var if it equaled true) basically [base content list].lists.[which internal list (i.e. skills or inv)][index of required variable].
the point of this is to be able to itterate through using for loops to collect a lump sum of all data. this would also have the addec benifit of making the system expandable without any code change other then actually adding and populating the list.
TLDR; is there a way to iterate through variables located in a class by index rather than name?
the alternative would be to have a script that knows each variable so it would have to manually iterate through all variables by name. i.e. lists[0].inv[0].name,lists[0].inv[0].image … which would get super annoying when the lists could contain tons of variables.
not really sure of any other easy to use data structures that will allow the use of the inspector (arrays dont let you do that sadly)
You can loop through members in a class using System.Reflection - it’s a complicated procedure and I’m not going to get into it here, but that’s what you’ll want to Google.
However, I’ll say that 9 times out of 10, when the right answer to a question is “Reflection”, you’re probably asking the wrong question*. It seems like you have already architected a solution to whatever your actual goal here is and have determined that being able to iterate through members in a class is your one missing link - my advice would be to take a step backwards, explain what your actual goal is (e.g. are you trying to create a save-game system or what?), and I’ll bet you a dollar that we can provide a cleaner, faster, more reliable, easier solution to your problem than Reflection would provide.
that tenth time is usually an Editor script, where using Reflection is completely appropriate.
The order at which reflection returns your members is Not Documented, which is a nice way of saying “completely friggin’ arbitrary” and “up to whatever the internal workings of the compiler feels like”, so there’s no guarantee that you’ll get them back in the same order that they’re in the file.
In addition; don’t use reflection for editors. Use the SerializedObject representation of objects, which has a way of iterating through all variables that are much smoother and works well with serialization.
hmm, yeah thats exactly what im trying to do, more specifically is a “global variables” object containing a script filled with data that all objects in the current scene can access and modify. where at save, that data is extracted, put into a string using dilemiters(possibly serialized tho not sure yet) then saved to file. on load it simply runs the procedure in reverse, filling the tables with data respective to the way it was put in.
if theres a better way to store this data/manipulate it im most certainly all ears! one thing we need however is inspector manipulability. where by i should be able to see the contents of any given datastructure and modify them in the inspector. thats the reason we did things this way. but yeah extracting data in a simple and orderly fassion is i guess at the root of what i need.
if you have a better way to structure data i’d be happy to give it a shot. I personally didn’t come up with this data structure myself (a friend of mine who i’m working with did)haha so if i could present a better alternative that would make things easier then im totaly up for that!
Readability is one of the most important tenants of clean code, so I would suggest you stick with variable names.
What you have described in your second post sounds to me like serialization. You want a way to transform your instances into strings for inspection or saving. I’m afraid I can’t help you with the details in javascript, but Googling the keyword serialization might get you started.
Reflection will not work for this, as reflection returns members is a completely arbitrary order, and may even differ platform to platform.
Instead build a data structure based on a dictionary or list. You can build a custom struct that holds the variable name and value. Then you can add an indexer to the class to allow you to acces the properties.
As a general note this data structure is a bad idea. You really don’t want global variables. This route will only end in tears. You have been warned.
What you’re trying to achieve is a bad practice in general (for all the reasons already explained above), but if you’re still inclined to do so, you could use indexers in C#:
public class Items
{
public string Name;
public Texture Image;
public int Level;
public bool Unlocked;
public double Amount;
public double Exp;
public object this[int i]
{
set
{
switch (i)
{
case 0:
Name = (string)value;
break;
case 1:
Image = (Texture)value;
break;
case 2:
Level = (int)value;
break;
case 3:
Unlocked = (bool)value;
break;
case 4:
Amount = (double)value;
break;
case 5:
Exp = (double)value;
break;
default:
Debug.LogError("Items Error: Assign failed, index "+i+" not available!");
break;
}
}
get
{
switch (i)
{
case 0:
return (object)Name;
case 1:
return (object)Image;
case 2:
return (object)Level;
case 3:
return (object)Unlocked;
case 4:
return (object)Amount;
case 5:
return (object)Exp;
default:
return null;
}
}
}
}
So now you can use:
Items myItem = new Items();
myItem[0] = "Sword of Thousand Truths";
myItem[1] = 9001;
string itemName = (string)myItem[0];
int level = (int)myItem[1];
As I was figuring, serialization is the answer you’re looking for. You’ll want to create a class like so:
[System.Serialized]
public class MyStoredData {
public string Name;
public Texture Image;
public int Level;
public bool Unlocked;
public double Amount;
public static MyStoredData LoadMasterData(){
/// TODO
}
public void SaveMasterData() {
/// TODO
}
}
.... and then, in a MonoBehaviour:
public class SomeClass : MonoBehaviour {
public static MyStoredData masterData {
get {
if (m_masterData == null)
m_masterData = LoadMasterData();
return m_masterData;
}
}
private static MyStoredData m_masterData;
}
Every object will now be able to access SomeClass.masterData.Name (and the rest), and it’ll work nicely. And after anytime you change anything in this data, you call SomeClass.masterData.SaveMasterData(); to save it to file. (You could even encapsulate all your data members with setter functions that do this automatically)
If you want to have more than one of these sets of data, you can easily save them to different files by passing in a string (filename) to your save/load functions; the code as-is assumes you only need one file with a hard-coded name.
As for the implementation of the save and load functions, this video is a handy tutorial for how serialization works.
Added bonus: Using serialization is pretty future-proof, as well. Unity has a property that allows you to rename serialized fields.