I am trying to create a data structure like in the picture, where I can easily add and remove the reward type. It is for a roguelike level-up system where basically I want to get a reward for a specific character like a warrior or mage from a specific rarity.
I am more experienced with Lua than Unity and in Lua language, it would look like this,
`{
["Melee"] =
{
[1] = {
[1] = {"Stat", "Strength", 10},
[2] = {"Ability", "Swirl", 1},
},
[2] = {
[1] = {"Stat", "Strength", 50},
[2] = {"Stat", "PhysicalDefense", 10},
},
},
["Healer"] =
{
[1] = {
[1] = {"Stat", "MagicalAttack", 5},
[2] = {"Ability", "Regeneration", 1},
},
[2] = {
[1] = {"Stat", "MagicalDefense", 15},
[2] = {"Ability", "Regeneration", 1},
},
},
}`
then for getting a spesific reward I would do reward = ["Melee][1][1]
. However, in Unity, using dictionaries disables scriptableobject's function to add elements inside editor. So how can I create a scriptableobject that I can add elements inside the editor with the same structure?
CodePudding user response:
You don't need dictionaries in order to access items by index.
Simply use a plain array or List
and do
public class Warrior : ScriptableObject
{
public Rarity[] rarities;
}
public class Rarity : ScriptableObject
{
public Reward[] rewards;
}
public class Reward : ScriptableObject
{
public enum RewardType { Stat, Ability }
public RewardType type;
public int value;
}
And finally reference these in a
public Warrior[] warriors;
Then if really needed for the first level you can still setup a dictionary on runtime like e.g.
public Dictionary<string, Warrior> Warriors = new ();
private void Start ()
{
foreach(var warrior in warriors)
{
Warriors.Add(warrior.name, warrior);
}
}
Then the rest you would access like e.g.
var reward = Warriors["Melee"].rarities [0].rewards[1];
Debug.Log($"{reward.type} - {reward.name} - {reward.value}");
Have in mind that in c# indices are 0-based
However, if you are more familiar with your way and prefer a general dictionary approach you can totally do so!
You could simply write this as a JSON and can then chose among the various JSON libraries to convert it into a dictionary again.
{
"Melee" : [
[
{
"type":"Stat",
"name":"Strength",
"value":10
},
{
"type":"Ability",
"name":"Swirl",
"value":1
}
],
...
],
"Healer" : ...
}
then you would not use ScriptableObject and only use e.g.
[Serializable]
public class Reward
{
public enum RewardType { Stat, Ability }
public RewardType type;
public int value;
public string name;
}
and then deserialize this into e.g.
var Warriors = JsonConvert.DeserializeObject<Dictionary<string, Reward[][]>>(theJsonString);
var reward = Warriors["Melee"][0][0];
Debug.Log($"{reward.type} - {reward.name} - {reward.value}");
where theJsonString
can be read form a file or a web request etc
This example uses Newtonsoft JSON.Net which is available for Unity via the package manager.
Personally I would though rather go with explicitly named fields and classes instead of those jagged arrays.