PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0

Wednesday, July 6, 2022

[FIXED] How to have by-reference locals in coroutines in Unity?

 July 06, 2022     c#, coroutine, iterator, pass-by-reference, unity3d     No comments   

Issue

I have some functions that take in an Enemy instance and change one of its fields. The Enemy class has some basic fields like speed, damage, attack range. Each function just stores one of the normal value of the enemy and then change the current field to some value for an amount of time and then change it back to the normal state (I code in Unity and use Coroutine for this). The difference is which field to store (speed or damage or attack range, etc). So I want to make a single function that takes in a delegate that returns the field that it wants to change:

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;
}

and then use it like this

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

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

But Iterators can't have by-reference locals. How to bypass this?


Solution

You actually don't need the return value of your delegate. You also don't need the Enemies since you don't use it in the routine anyway.

This is of course still not as beautiful as ref parameters would be but you could simply use a callback like

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);
}

and call it like

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

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

Instead of the Stat you could also just use a Action<float>



Answered By - derHugo
Answer Checked By - Cary Denson (PHPFixing Admin)
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Newer Post Older Post Home

0 Comments:

Post a Comment

Note: Only a member of this blog may post a comment.

Total Pageviews

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
Comments
Atom
Comments

Copyright © PHPFixing