Situation: I have a character component and many small property components. The character component knows all property components. These components could look like this:
public class Character : MonoBehaviour
{
public Endurance endurance;
public Stamina stamina;
public Vitality vitality;
//...
}
public class Endurance : CharacterProperty
{
public float value;
}
Problem: In my game, I would like to introduce a class Validator that can check if a character property satisfies a condition. Such an example could be “Is the value of endurance higher than 500?”. The validator would return true or false, depending on whether the condition is fulfilled or not.
However, in Unity, everything seems to be instance-dependent. If I add a component Buff, for instance, which grants a modifier to a character property as long as a condition is fulfilled, it could look like this:
public class Buff : MonoBehaviour
{
public CharacterProperty target;
public Validator validator;
public Modifier modifier;
private boolean inEffect;
private void Update(){
if(validator.Validate(target)){
if(!inEffect) target.Add(modifier);
else {
if(inEffect) target.Remove(modifier);
}
}
}
The problem here is I always need an instance to work with the buff. However, this is not something that I know in the editor, I don’t know which target character property instance is supposed to get the buff. Furthermore, thus I cannot tell the validator of the buff that it should check the endurance value of the target and not vitality, for instance. Regardless how I organize my objects, be it component or asset (ScriptableObject), I don’t see any way to explicitely tell my object which character property it should target.
How do I tell the validator of a buff that it should target the endurance property value of the character? UnityEvent appears to enable some kind of serialization that almost does what I aim for, however, it depends on specified instances. It is not quite what I am looking for, because I am not dealing with events, but rather looking for some kind of dispatching/selection option.
How would I do this without
- introducing an enumeration that has a value for every character property in existence and a dispatcher that switches based on the given enumeration value and retrieves the related character property.
- introducing a dictionary and hashing character properties or other identifying values to retrieve the related character property (think of string-property dictionary and storing the string key with objects that should target the related character property).
From my own research, the only way I found is something that I call selectors, either as custom classes using the SerializeReferenceAttribute or ScriptableObjects with only one instance per definition:
[Serializable]
public class EnduranceSelector : PropertySelector<Endurance> { }
public class PropertySelector<TProperty> where TProperty : CharacterProperty
{
public TProperty Get(Character target) {
return target.gameObject.GetComponent<TProperty>();
}
}
This doesn’t taste so good, because it doesn’t scale well with character properties. For every character property, I would have to add another class deriving from PropertySelector for it to be able to referenced.
