To preface this question, I'm a hobby programmer that's been learning on/off for the past 7 years, and mostly dabbled with Node.JS in several different settings and projects. I now decided to take the leap to another major language and picked up C# to start learning game development and the likes. I am in the process of building a skill tree and I can't really understand how to store the information I need for each skill in a clean and orderly fashion without a bunch of empty GameObjects (Unity) holding that info.
I know (at least my favorite way of) how to do this in Node.JS, but I can't find the right information on converting this to C#.
Node.JS example
var skillTree = [
{
name: "Skill1",
effect: skill1Func,
unlocked: true,
prereqs: [ ]
},
{
name: "Skill2",
effect: skill2Func,
unlocked: false,
prereqs: [1, 5]
}
];
As you can see, it's just an array of objects, all following the same properties, but the properties are pre-determined instead of added. I just can't find the right path to go to store this information for use in C#, so if anyone could help me out, that would be appreciated!
CodePudding user response:
This answer basically has it all.
I anyway wanted to add a Unity specific suggestion / extension:
Instead of "hard coding" this in a script at all and using index based int[] PreReqs
wouldn't it be more dynamic and extendable to simply create and configure skills in the Unity editor?
I would therefore use ScriptableObject
which basically allows you to create skill assets which live in the Assets and are not attached to a specific GameObject
.
[CreateAssetMenu]
public class Skill : ScriptableObject
{
[SerializeField] private SkillEffect effect;
[SerializeField] private Skill[] preReqs;
public string Name => name;
public SkillEffect Effect => effect;
public bool Unlocked;
public Skill[] PreReqs => preReqs;
}
Then you would create instances of this via Assets
-> Right click -> Create
-> Skill
, name and configure it. This way you an easily directly link them among each other in the preReqs
and don't have to rely on any indices.
In your final consumer component you would finally reference them all in a field
public Skill[] skillTree;
And another extension of this - depending on your needs for the Effect
: If Effect
is not e.g. an enum
but rather a custom method you could simply make this Skill
an abstract
type and have different child skills based on it like e.g
public abstract class Skill : ScriptableObject
{
[SerializeField] private Skill[] preReqs;
public string Name => name;
public abstract void Effect();
public bool Unlocked;
public Skill[] PreReqs => preReqs;
}
and then e.g.
[CreateAssetMenu]
public class SayHelloSkill : Skill
{
public override void Effect()
{
Debug.Log("Hello World!");
}
}
you can pass whatever parameters you need to the method and basically execute any code on them while you create instances of each skill and reference them in the skillTree
as before. I personally call this "Scriptable Behavior" and though it is slightly abusing the idea of ScriptableObject
I find it quite powerful
CodePudding user response:
Typically you would create a class object to define the structure of the data. Then you can create a variable of the type of that class and populate the data in the constructor. Example:
public class skillItem {
public string Name { get; set; }
public SkillEffect Effect { get; set; }
public bool Unlocked { get; set; }
public int[] PreReqs { get; set; }
}
public skillItem[] skillTree = new skillItem[] {
{
Name = "skill1",
Effect = skill1Func,
Unlocked = false,
PreReqs = new int[] { 1, 5 }
},
{
Name = "skill2",
Effect = skill2Func,
Unlocked = false,
PreReqs = new int[] { 20, 30 }
}
}