【问题标题】:Unity Destroying Instantiated clone stops instantiatingUnity Destroying Instantiated clone 停止实例化
【发布时间】:2019-05-07 22:30:43
【问题描述】:

我有这段代码,用来实例化一个精灵

AppleSpawner.cs

public class appleSpawner : MonoBehaviour
{
  private int isRunning = 1;
  private readonly int[] positions = { -10, -5, 0, 5, 10 }; 
  public int NumberOfSeconds;
  System.Random rand = new System.Random();

  private void Update()
  {
      if (isRunning == 1) StartCoroutine(Wait());    
  }

  public IEnumerator Wait()
  {
      int randomX = rand.Next(5);
      isRunning = 0;
      yield return new WaitForSeconds(NumberOfSeconds);
      Instantiate(this, new Vector3(randomX, 5, 0), transform.rotation);

  }
}

问题#1:这是在实例化新副本之间等待 X 秒的最佳/最简单方法吗?

我也有一个角色,有一个 oncollision 事件,如果它与其中一个副本发生冲突,它应该摧毁它。这很好用,问题是,如果我与最后生成的副本发生碰撞,它会破坏它,然后副本停止生成

character.cs

private void OnCollisionEnter2D(Collision2D collision)
{
  if (collision.gameObject.tag == "apple")
    {
        Destroy(collision.gameObject);
        points++;
        text.text = "points: " + pont;
    }
}

【问题讨论】:

  • 您的播放器碰撞的每个对象似乎都是AppleSpawner,是您的实例化的来源,而Character 最终会破坏。如果您想继续生成对象,您可以实例化另一个名为 Apple 的类,而碰撞将破坏该类。
  • 我真的不明白这一点(Unity 初学者)我正在破坏一个新复制的苹果精灵,不是吗?
  • 在这种情况下,ApplySpawner 正在生成自己的实例,因此当最后一个实例被销毁时,它无法再次生成自己。将Instantiate(this, new Vector3(randomX, 5, 0), transform.rotation); 更改为this 以外的其他值应该可以解决所有精灵都被销毁后的生成问题。
  • 您正在销毁新复制的精灵,但这些副本是AppleSpawner,如果它们是Apple 或其他一些游戏对象,AppleSpawner 不会受到Apple 碰撞的影响
  • 这可能是一个比硬编码游戏对象更好的选择,你可以有一个 public GameObject gObjToSpawn 并传入你要生成的精灵游戏对象并在 Instantiate(gObjToSpawn, new Vector3(randomX, 5, 0), transform.rotation); 中使用它

标签: c# unity3d instantiation


【解决方案1】:

不要在一个类中混用不同的职责。

随着类的规模越来越大,它会使您的代码容易出错并且越来越难以维护。你应该有一个产卵器,它会产生苹果,还有一个带有碰撞器的苹果预制件。两个不同的脚本。

public class Spawner : MonoBehaviour {
    private static readonly int[] positions = { -10, -5, 0, 5, 10 }; 
    public int NumberOfSeconds;
    private System.Random rand = new System.Random();
    public GameObject Prefab;

    public IEnumerator Start() {
        while (true) {
            int randomX = positions[rand.Next(5)];
            Instantiate(Prefab, new Vector3(randomX, 5, 0), transform.rotation);
            yield return new WaitForSeconds(NumberOfSeconds);
        }
    }
}

在您的情况下,带有该组件的对象不应该有碰撞器或精灵,因此它们永远不会在与玩家碰撞时被破坏。生成的预制件是玩家收集或避免的常规苹果。

由于 spawner 不会产生另一个 spawner,我们将 spawn 逻辑放在一个循环中。

你可能想要数组中的随机位置而不是原始随机数,所以我修复了它。

概括。

现在你的生成器只做了一个功能——生成。它不再绑定到苹果,所以你可以用另一个刷怪笼刷出胡萝卜。逻辑保持不变。

Start 中的魔法是什么?

您可以将Start 设为协程。它就像任何其他协程一样工作:运行到yield returnyield break 或函数结束。后两者结束协程,否则等待,然后继续运行。比Update控制协程中的flag更好。

如果您需要一个每帧都运行的脚本,请使用Update

【讨论】:

    【解决方案2】:

    首先,创建一个名为“Applespawner”的新空游戏对象。将 Applespawner.cs 放入其中。

    改变这个

    private void Update()
    {
        if (isRunning == 1) StartCoroutine(Wait());    
    }
    

    private void Start()
    {
        if (isRunning == 1) StartCoroutine(Wait());    
    }
    

    您在Awake() 中将isRunning 设置为0,在Update 函数中调用IEnumerator 毫无意义。

    您应该将此行添加到您的 Applespawner.cs public GameObject Apple = null;

    并将您的 Apple 预制件附加到编辑器中 Applespawner.cs 的 Apple 插槽。如果您不知道如何制作预制件,请在 Google 上搜索。

    我认为有 2 种最佳方式可以让您每 X 秒启动一次游戏对象。

    • 第一种方式

      public IEnumerator Wait()
      {
          while(true){
              yield return new Waitforseconds(X seconds);
              Instantiate an object.
          }
       }
      
    • 第二种方式

      float spawnRate = 1f;
      float nextTimeToSpawn = 0;
      
      private void Update()
      {
          if (Time.time >= nextTimeToSpawn){
      
              nextTimeToSpawn = Time.time + 1f / spawnRate;
              //Spawn something
          }    
      }
      

    我个人更喜欢第二种方式。希望这会有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-05-27
      • 1970-01-01
      • 2021-11-15
      • 2016-03-19
      • 2019-08-07
      • 2019-04-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多