Hi everyone, newbie here,
What I want to do:
I have a class called Character, each instance representing a character in my roleplaying/strategy game. I want to create a list of traits characters can have. For example “Strong”, which would give a character more health. Now to me, it doesn’t make sense to create a class for each trait and instantiate that class each time to add it to the list of traits of that character. I’m sure there is a better way.
I’m coming from python programming, and I will just show what I would do there:
traits = {
"strong": { "name" : "Strong", "bonusHealth": 3}
}
// in the character class
character_traits = {}
// when the game is running
character_traits["strong"] = traits["strong"]
// when the trait could affect something
if "strong" in character_traits :
whatever += bonusHealth
If the above is really stupid, please propose better ways, I’m eager to learn
All trait information would be readonly, I would like to keep the information about all traits all in one file. Other files should then be able to call the information from that file.
You don’t have to instantiate the trait each and every time. You’d only instantiate it once and you can recycle the trait.
Also, in your code you still have to write this if chain that requires implementing how the trait behaves based on the name. Why not let the trait decide that instead of having this huge if case.
You can do something like this:
(this is intended as a simple example, do not expect this to work out of the box)
public interface ITrait
{
string Name { get; }
void ApplyTrait(Entity entity);
}
//create an instance of this and give it the name 'Strong'.
//if you want another called like StrongPlus, create that and give it a larger modifier
public class HealtTrait : ScriptableObject, ITrait
{
#region Fields
public float HealthModifier;
#endregion
#region ITrait Interface
public string Name { get { return this.name; } }
public void ApplyTrait(Entity entity)
{
entity.Health += this.HealthModifier;
}
#endregion
}
public class DefenseTrait : ScriptableObject, ITrait
{
#region Fields
public float DefenseModifier;
#endregion
#region ITrait Interface
public string Name { get { return this.name; } }
public void ApplyTrait(Entity entity)
{
entity.Defense += this.DefenseModifier;
}
#endregion
}
You can then just have a list of traits that get filled with the SOs, you just loop them and call ‘ApplyTrait’.
Traits could now be even more robust. You could have conditions on the trait… like:
public class HighLevelTrait : ScriptableObject, ITrait
{
#region Fields
public int MinLevel;
public float DefenseModifier;
#endregion
#region ITrait Interface
public string Name { get { return this.name; } }
public void ApplyTrait(Entity entity)
{
if(entity.Level >= this.MinLevel)
{
entity.Defense += this.DefenseModifier;
}
}
#endregion
}
Or have composite traits:
public class CompositeTrait : ITrait
{
#region Fields
public readonly List<ITrait> Traits = new List<ITrait>();
#endregion
#region ITrait Interface
public string Name { get; set; }
public void ApplyTrait(Entity entity)
{
foreach(var trait in Traits)
{
if(trait != null) trait.ApplyTrait(entity);
}
}
#endregion
}
Representing something as a class and adding instances is essetialy OOP way of doing things.
You can have ITrait interface, List for Character, multiple traint implementation and a TraitFactory for getting instances without knowledge of what they actually are.
I guess, mostly because I thought it would be less efficient than what I imagined. As said in my OP, I come in Python, where you only use classes if your it really, really makes sense. Also, because I’m still inexperienced with C#, I like to see what ideas people on the forum can give me. Things I sometimes didn’t even know were possible.
Python is intended mostly for fast scripting and oop desing is exactly opposite, it is more about modelling reality by representing various aspects of problem as classes and combinations of their instances. Normally you model your game and optimize it only when model is proven to work as expected, that’s probably optimal flow for this.
If you try to use unity/c# (one paradigm) with python (completely different paradigm) approach in mind you will quickly face a lot of problems what can be described as class “I want to do standard things via weird ways but it is not working as I expected”.