【问题标题】:I can't see an infinite loop but my game still freezes我看不到无限循环,但我的游戏仍然冻结
【发布时间】:2016-03-20 10:24:03
【问题描述】:

我有一些 Unity c# 游戏中的敌人的代码。该代码有一个降低生命值的函数和一些连接到触发器的代码,该触发器使用Invoke() 调用该函数。 Invoke 方法存储在 while 循环中,以便在运行状况大于 0 时执行。脚本如下。

我可以运行游戏,但只要敌人进入触发器,游戏就会冻结。这通常是由于无限循环,但在我看来它看起来是正确的。我有什么遗漏吗?

using UnityEngine;
using System.Collections;

public class Base : MonoBehaviour {

public float Health = 100f;
public float AttackSpeed = 2f;

//If enemy touches the base 
void OnCollisionEnter2D(Collision2D col){
    Debug.Log ("Base touched");
    if(col.gameObject.tag == "Enemy"){
        while(Health > 0f){
            Debug.Log ("Enemy attacking base");
            //call attack funtion in x seconds
            Invoke("enemyAttack", 2.0f);
        }
    }
}

//Enemy attack function that can be used with Invoke
void enemyAttack(){
    Health -= Enemy.Damage;
    Debug.Log ("Base health at: " + Health);
}


// Use this for initialization
void Start () {

}

// Update is called once per frame
void Update () {

    //Load Lose Screen when Base health reaches 0
    if (Health <= 0){
        Application.LoadLevel("Lose Screen");
    }
}
}

【问题讨论】:

  • 你在哪里分配 Enemy.Damage?我看到您已将 2.0f 传递给 Invoke,但没有将 Enemy.Damage 分配给此参数。
  • Enemy.Damage 是一个名为 damage 的公共静态浮点数,位于另一个名为 Enemy 的脚本中
  • 听起来您需要使用调试器并花时间逐步检查并评估所有变量以查看是否可以查明问题
  • 无限循环不会导致程序冻结,而是崩溃。冻结是由循环时间过长引起的,通常在 1 线程应用程序中(在循环完成之前无法更新 GUI)。解决方案很简单:多线程(嗯……或者使循环更快)。
  • while 循环看起来很可疑,因为它会导致你的角色在碰到敌人时死亡。此外,2.0f 意味着您的调用被延迟(see the docs),因此 while 循环只是不断地将函数调用排队,而不会真正降低玩家的健康状况(因此您会得到无限循环)

标签: c# unity3d while-loop infinite-loop freeze


【解决方案1】:

您的Invoke() 被一遍又一遍地呼叫,排队等候。你应该在这里使用协程。

void OnCollisionEnter2D(Collision2D col){
    Debug.Log ("Base touched");
    if (col.gameObject.tag == "Enemy"){
        if (Health > 0f){
            Debug.Log ("Enemy attacking base");
            StartCoroutine (enemyAttack ());
        }
    }
}

IEnumerator enemyAttack () {
    while (Health > 0f) {
        yield return new WaitForSeconds (2f);
        Health -= Enemy.Damage;
        Debug.Log ("Base health at: " + Health);
    }
}

【讨论】:

  • 但是一旦协程启动,它会每 2 秒永远消耗一次生命值,直到生命值归零。在造成伤害的物体退出碰撞触发器后,它应该停止消耗生命值(它没有直接这么说,但这是我能想到的最合乎逻辑的事情)
  • OnCollisionEnter2D 中的 if(Health&gt;0f) 有点不必要(因为协程无论如何都会重复检查,如果生命值低于 0,更新函数会终止游戏)。此外,逻辑似乎仍然不正确,因为玩家一旦接触敌人就会死亡(并且没有明显的方法阻止它)
  • 这回答了所提出的问题。他的代码设计为每 2 秒消耗一次生命值。如果不需要,OnCollisionEnter2D 中的 if 将阻止创建协程。
  • @unholy 羊,玩家碰到敌人不会死。现在的问题是,即使在敌人被摧毁后,协程也会继续运行并消耗生命值,直到达到 0
  • @lucasRHCP 当满足停止enemyAttack ()的条件时,需要调用StopCoroutine ("enemyAttack")
猜你喜欢
  • 2018-09-06
  • 1970-01-01
  • 2023-04-11
  • 2015-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多