如何在 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);
}
我有一些函数接受 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);
}