0

I'm trying to create status effect's for my game those are things that affect your player's statistics over time for example. However I'm having trouble with remembering the passed variable i.e the one that should be modified. Let's say you have some status effect that reduces your Health by 10 % for 10 seconds the way I do it is by instantiating a new class passing some parameters in along with the variable that needs to be modified in this case player's health, but the problem is that once the constructor is gone the reference is being broken between those 2 and from then on I just edit some variable that is never being used.

Here's how i instantiate a Status Effect

    /// <summary>
    /// Creates a status effect which ticks at specified period of time without any condition.
    /// </summary>
    public StatusEffect(float increase, EffectIncreaseType increaseType, float timeOfStatusEffect, float tickTime)
    {
        this.increase = increase;
        this.endTimeOfStatusEffect = Time.time + timeOfStatusEffect;
        this.tickTime = tickTime;
        increaseCalculator = increaseType == EffectIncreaseType.Percentage ? increaseCalculator = (a) => (int)(increase / 100f * a) : increaseCalculator = (a) => (int)increase;
    }

And here's how I use it now

    public bool TryTrigger(ref int affectedProperty)
    {
        if (condition.Invoke(affectedProperty))
        {
            affectedProperty += increaseCalculator.Invoke(affectedProperty);
        }
        return condition.Invoke(affectedProperty);
    }

This is not what i want first of all it requires a field to be passed to the method TryTrigger not a property second of all you are not supposed to know what variable is required all the time you should just passed it in the start and then try triggering that with the class itself working with that variable in the back stage. Is that possible ? Is there a better approach for making Status Effects (DoT,HoT) ? Also I will like to make this work for instant status change for example decrease your health by 30 % for 1 minute but I'm not sure if my current setup is good for that.

Asimm
  • 37
  • 6
  • This is totally wrong in the Unity milieu, Asimm. For procs just use this ... http://stackoverflow.com/a/36249404/294884 – Fattie Aug 20 '16 at 20:33
  • And for trivial timers in Unity you just use `Invoke` or `InvokeRepeating`. – Fattie Aug 20 '16 at 20:33

1 Answers1

5

There's no way to store a "ref" to a variable in .NET; that's deliberate. It eliminates the class of bugs common in C / C++, where you store a ref to a variable past its lifetime and bad things happen.

The way to do what you want is instead, pass in an Action<T> that sets the variable (or property) you want to change, and then when you want to change it, you invoke the action.

How then does that solve the problem? Because C# makes sure that the variable captured by the delegate is always long-lived.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • The way it currently is (i'm not saying it's working as i want it or the problem is fixed) is that i constantly call the TryTrigger function passing the appropriate variable, but i'm simply testing it and i know exactly which variable i will need later on when different classes pass some variable to this it will get messy and my current set up wont work. – Asimm Aug 20 '16 at 18:58
  • But Eric, that means I must calculate all the stuff outside this class so I can pass it to this one right ? – Asimm Aug 20 '16 at 18:59
  • @Asimm : you can still calculate all your stuff inside your class, and just pass two delegates; a setter and a getter that do nothing but get or set the property on your object. e.g.: `Action setter = (newValue) => { a.Weight = newValue; };` – Menno van den Heuvel Aug 23 '16 at 09:56