如何在 Unity 的协程中使用引用局部变量?

How to have by-reference locals in coroutines in Unity?

我有一些函数接受 Enemy 实例并更改其字段之一。敌人 class 有一些基本字段,如速度、伤害、攻击范围。每个函数只存储敌人的一个正常值,然后将当前字段更改为某个值一段时间,然后将其更改回正常状态(我在 Unity 中编写代码并为此使用协程)。不同之处在于要存储哪个字段(速度或伤害或攻击范围等)。所以我想创建一个函数,它接受一个委托,returns 它想要更改的字段:

delegate ref float Stat();

private IEnumerator EnemyStatModify(Enemies enemy, float duration, float percent, Stat stat)
{
    ref float enemyStat = ref stat();
    float normalStat = enemyStat;
    enemyStat *= (1 - percent);
    yield return new WaitForSeconds(duration);
    enemyStat = normalStat;
}

然后像这样使用它

EnemyStatModify(enemy, state.duration, state.timeBtwHits, () => ref enemy.speed);

EnemyStatModify(enemy, state.duration, state.timeBtwHits, () => ref enemy.damage);

但是迭代器不能有局部引用。如何绕过这个?

您实际上不需要委托的 return 值。您也不需要 Enemies,因为无论如何您都不会在例程中使用它。

这当然仍然不如 ref 参数那么漂亮,但您可以简单地使用像

这样的回调
delegate void Stat(float newValue);


private IEnumerator EnemyStatModify(float duration, float percent, float currentValue, Stat onUpdated)
//or
//private IEnumerator EnemyStatModify(float duration, float percent, float stat, Action<float> onUpdated)
{
    onUpdated?.Invoke(currentValue * (1 - percent));

    yield return new WaitForSeconds(duration);

    onUpdated?.Invoke(currentValue);
}

并这样称呼它

StartCoroutine(EnemyStatModify(state.duration, state.timeBtwHits, enemy.speed, (newValue) => 
{ 
    enemy.speed = newValue; 
}));

StartCoroutine(EnemyStatModify(state.duration, state.timeBtwHits, enemy.damage, (newValue) => 
{ 
    enemy.damage = newValue; 
});

您也可以只使用 Action<float>

而不是 Stat

一个简单的解决方法是为协程提供 getter 和 setter 委托。这将使您在任何时候都能获得统计数据,而不仅仅是开始:

delegate float GetStat();
delegate void SetStat(float x);

private IEnumerator DelayedEnemyStatModify(Enemies enemy, float duration, float percent, GetStat getStat, SetStat setStat)
{
    yield return new WaitForSeconds(duration/2f);
    float enemyStat = getStat();
    float normalStat = enemyStat;
    enemyStat *= (1 - percent);
    setStat(enemyStat);
    yield return new WaitForSeconds(duration/2f);
    setStat(normalStat);
}

或者在您 always/only 一开始就获取统计数据的情况下,只需按值传递它:

delegate void SetStat(float x);

private IEnumerator EnemyStatModify(Enemies enemy, float duration, float percent, float enemyStat, SetStat setStat)
{
    float normalStat = enemyStat;
    enemyStat *= (1 - percent);
    setStat(enemyStat);
    yield return new WaitForSeconds(duration);
    setStat(normalStat);
}