C#如何在不阻塞程序的情况下使函数/方法等待(Unity)

时间:2019-05-17 20:49:24

标签: c# unity3d fork wait

我想在游戏RestoreHealth()中统一模拟游戏中的生命恢复。

我是否想通过创建一个子进程来思考它,所以当我调用wait时,它不会影响任何当前正在运行的进程或线程,并且该子进程将在函数完成后死亡。

public void RestoreHealth() {
    if (health >= MaxHealth) return; // health and MaxHealth are Class variables

    if (health % 10 != 0) {     // if health is not dividable by 10
        int temp = health % 10; // then we round it to the closest 
                                //tenth
        temp = 10 - temp;
        health += temp;
    }

    int i = health;

    for (; i < MaxHealth; i += 10) {  // where the health grows till 100
        health += 10;
        // sleep(1000);  // make function wait for '1 second' to iterate again

        Debug.Log("Health: " + health);
    }
}

在这种情况下,如何在C#中创建子进程或统一处理并使其等待?

是否像C中的Fork();一样?

此外,当玩家最初受到伤害时会调用此函数。

解决方案

注意:我将“健康”改为“盔甲”

public IEnumerator RestoreArmour() {
        while (_Armour < _MaxArmour) {
            _Armour++;
            Debug.Log("Health: " + _Armour);
            yield return new WaitForSeconds(ArmourRegenRate); // ArmourRegenRate is a 
                                                             // float for the seconds
        }
    }

并使用它来启动协程

 void Start(){

    StartCoroutine(player.RestoreArmour());
}

2 个答案:

答案 0 :(得分:5)

基本协程概念

在Unity中,您与协同程序一起实现这种异步的“线程化”行为

IEnumerator RestoreHealth() {
   while (health != MaxHealth) {
       health++;
       yield return new WaitForEndOfFrame();
   }
}

然后用

调用它
StartCoroutine(RestoreHealth());

重新启动协程

为了阻止现有的协程开始运行并启动新的协程,这是您要达到的目的:

private Coroutine _myCoroutine = null;

void SomeMethod()
{
    if (_myCoroutine != null)
        StopCoroutine(_myCoroutine);

    _myCoroutine = StartCoroutine(SomeOtherMethod());
}


玩家受到伤害后,暂停盔甲恢复X秒

一种常见的功能是在玩家X秒钟内未受到伤害时可以恢复盔甲:

private bool _shouldRestoreArmour = true;
private Coroutine _pauseArmorCoroutine = null;

void Update()
{
    if (_shouldRestoreArmour)
        Armor += ArmorRegenerationPerSecond * Time.deltaTime;
}

void PlayerTakeDamage() 
{
    if (_pauseArmorCoroutine != null) 
        StopCoroutine(_pauseArmorCoroutine);

    _pauseArmorCoroutine = StartCoroutine(PauseRestoreArmor());

    // Take damage code
}

IEnumerator PauseRestoreArmor()
{
    _shouldRestoreArmor = false;
    yield return new WaitForSeconds(RESTORE_ARMOR_DELAY_TIME);
    _shouldRestoreArmor = true;
}

在此情况下,玩家将一直恢复装甲,但在受到伤害后的X秒内除外。如果玩家多次受到伤害,我们将简单地放弃先前的协程并开始一个新的协程,这样距最后一击将有X秒钟的刷新时间。

答案 1 :(得分:0)

假设您以更新方法运行此计时器,则可以创建一个计时器

private float timer = 1;
private float timerReset = 1;

private void Update(){
  RestoreHealth();
}

public void RestoreHealth() {
  if (health >= MaxHealth) return; // health and MaxHealth are Class variables

  if (health % 10 != 0) {     // if health is not dividable by 10
    int temp = health % 10; // then we round it to the closest tenth
    temp = 10 - temp;
    health += temp;
  }
  int i = health;
  for (; i < MaxHealth; i += 10) {  // where the health grows till 100
    if(timer > 0){
      timer -= 1 * time.deltaTime;
    }else{
      health += 10;
      Debug.Log("Health: " + health);
      timer = timerReset;
    }
  }

}

或者您可以简单地每秒给玩家1点生命值,或者例如任意数量

    public void RestoreHealth() {
      if (health >= MaxHealth) return; // health and MaxHealth are Class variables

      if (health % 10 != 0) {     // if health is not dividable by 10
        int temp = health % 10; // then we round it to the closest tenth
        temp = 10 - temp;
        health += temp;
      }
      int i = health;
      for (; i < MaxHealth; i += 10) {  // where the health grows till 100

          health += 10 * 1 * time.deltaTime;
          Debug.Log("Health: " + health);
          timer = timerReset;

      }

    }

因此,在这种情况下,您的播放器每秒获得10点生命值,但是该值始终会上升,因此在短短的一秒钟内,播放器生命值将每100ms增加1点生命值