【问题标题】:Logic issue spawning a set number of game objects when game object is destroyed if collides with something?如果与某物发生碰撞,当游戏对象被破坏时产生一定数量的游戏对象的逻辑问题?
【发布时间】:2016-05-20 05:21:11
【问题描述】:

我在 Unity 中使用 C# 进行基本游戏时遇到了两难境地 - 我需要在随机位置生成 10 个立方体,但是一旦生成了一个立方体,如果它检测到与此脚本中的另一个游戏对象发生碰撞,我会销毁它 附加到立方体对象:

void OnCollisionStay(Collision col){

        if (col.gameObject.tag == "Maze" || col.gameObject.tag == "Player") {

            //Destroy cube
            Destroy(this.gameObject);
            spawnCubes.numCubesExist--;

            Debug.Log ("touching!!" + spawnCubes.numCubesExist);

            spawnCubes.touchedMaze = true;

        }
    }

在我场景的另一个脚本中,我在这里生成立方体。我正在使用 public static int numCubesExist 来枚举场景中的立方体数量(尽管这不起作用)并使用 NUMTOBESPAWNED 来设置场景中应该最终出现的立方体数量。

在多维数据集脚本中,如果检测到碰撞,numCubesExist 会减 1,并且当产生多维数据集时,cubeSpawner (); 会增加。我的逻辑是,我的 while 语句将继续产生 UNTIL numCubesExist == NUMTOBESPAWNED 但这不会发生。

void Start () {

        while(numCubesExist <= NUMTOBESPAWNED)
        {
            cubeSpawner ();
        }

    }
void cubeSpawner()
    {
        //Random textures
        switch (Random.Range (0, 3)) {
        case 0:
            cube.GetComponent<Renderer> ().material = color1;

            break;

        case 1:
            cube.GetComponent<Renderer> ().material = color2;

            break;

        case 2:
            cube.GetComponent<Renderer> ().material = color3;
            break;

        case 3:
            cube.GetComponent<Renderer> ().material = color4;

            break;

        }

        //Random positions
        if (UIManagerScript.sceneNum == 0) {
            position = new Vector3 (Random.Range (7.0F, 26.0F), (float)1.4, Random.Range (-9.0F, 10.0F));
            Debug.Log (position);
        }
        else if(UIManagerScript.sceneNum == 1) {
            position = new Vector3 (Random.Range (7.0F, 47.0F), (float)1.4, Random.Range (-9.0F, 10.0F));
            Debug.Log (position);
        }
        else if(UIManagerScript.sceneNum == 2) {
            position = new Vector3 (Random.Range (-4.7F, 44.0F), (float)1.4, Random.Range (-23.0F, 25.0F));
            Debug.Log (position);
        }

        //spawn
        Instantiate (cube, position, Quaternion.identity);
        Debug.Log ("spawned it!"+numCubesExist);
        numCubesExist++;
    }

在打印所有生成语句之后打印多维数据集脚本碰撞中的我的 Debug.Log 语句,所以我看到的是多维数据集生成正确的数字,然后其中一半被销毁而不是被替换OnCollisionStay。所以我的立方体总是比NUMTOBESPAWNED 少。

我是 Unity 新手——实现这一目标的最佳方法是什么?我应该在哪里调用我的 while 循环(更新只会产生一百万个立方体)?

编辑枚举多维数据集:

GameObject[] allObjects = GameObject.FindGameObjectsWithTag("blueCube");
        foreach (GameObject go in allObjects) {
            cubesInScene++;
        }

【问题讨论】:

  • 让我直说。立方体在 OnCollisionStay 中生成和销毁,但您希望场景中的立方体数量始终为 NUMTOBESPAWNED 数量?
  • 不 - 只是最初。当我开始场景时,我希望在所有生成和销毁完成后有 NUMTOBESPAWNED 立方体。 (我在碰撞时破坏的唯一原因是因为否则我会在墙内生成立方体)
  • 您可能有赛车状况。假设你想要 5 个立方体。您的 while 循环会生成所有 5 个,这意味着立方体的数量与预期相符。 while 循环结束,然后其中一个立方体检测到它与某物发生碰撞并将其自行移除。此时立方体的数量为 4,但 while 循环已经结束。
  • 只是为了澄清您基本上已经注意到的内容:Start() 总是在第一个 OnCollisionStay() 之前调用。您可以在此处查看事件的全部顺序:docs.unity3d.com/Manual/ExecutionOrder.html
  • @NickOtten 是的——你有什么建议可以解决这个问题?

标签: c# unity3d


【解决方案1】:

这是我看到的,希望对您有所帮助!

  1. 您的生成器不能保证立方体不会在“迷宫”或“玩家”对象旁边(或进入)生成,因此很可能它会时不时地发生,并且您的立方体在生成后立即被摧毁。正如“Nick Otten”所强调的那样,当这种情况发生时,您的生成循环已经结束,因此不会生成新的立方体来代替被破坏的立方体。
    要解决这个问题,您可以做几件事。以下是一些示例:

    • 在场景中创建生成器 GO 并保证“迷宫”和“玩家”都在其预定义的范围之外(假设是 10 个单位的地球),并且保证立方体在内部生成;你可以让它变得简单——就像编码一样——并在你的生成器的“地球”中添加一个对撞机,并使用IgnoreLayerCollision 使不需要的物品被击退(“留在外面”)和其他人掉下来(“留在里面”)。例如。立方体排斥并且玩家留在里面,反之亦然。
    • 您可以在“生成阶段”应用不同的碰撞机制。 IE。在OnCollisionEnter 上,您使对象相互排斥/反弹/等等,而不是立方体被破坏。生成阶段一结束,就可以保证没有任何东西接触,您可以切换到“破坏机制”/“播放模式”
    • 缓慢且开销较大,因此我不建议这样做,但您可以继续生成和生成,直到所有立方体都留下(即生成后没有一个被破坏)
  2. 您为什么不创建一个立方体预制队列(并在脚本中隐藏/重新排列它们而不是销毁),而不是“numCubesExist”之类的?这是一个很好的教程:Object Pooling Tutorial我也推荐 Sebastian 的其他教程,他在 Unity 教学方面做得很好

  3. 在你的立方体生成器方法中,你为什么不做这样的事情而不是开关?

    //class variable
    private Material[] colorMats; //fill up in Start() with color mats.
    //then in cubeSpawner:
    cube.GetComponent<Renderer>().material = colorMats[Random.Range(0, colorMats.Length)];
    因此,每当您更改材料(例如添加新材料)时,您只需在 Start() 中的一处更改初始化代码

【讨论】:

  • 谢谢,但这并不能解决我的问题。当玩家开始移动时(游戏已经正式开始),我需要有 NUMTOBESPAWNED(例如:7)个立方体才能在场景中 2. 不动。通过不破坏它们并让它们弹开,它们会弹到空中并继续移动。如果我关闭对撞机,它们会在墙内生成。我无法使用你的球体技术,因为我在迷宫中生成我的立方体(到处都是墙)
  • 有没有办法在所有销毁完成后仅枚举场景中的立方体数量,然后生成已销毁的数量?必须有办法解决这个问题..
  • @skyguy 是的,有。那是“不推荐”的分支。您可以使用的最简单的一个是“FindObjectOfType”(或“FindObjectsOfType”)。此外,如果它是一个 mase 并且已经烘焙,您可以创建一个 NavMesh 并在里面生成东西,即在立方体所在的地方:docs.unity3d.com/Manual/nav-BuildingNavMesh.html
  • 好吧,我没有成功枚举场景中立方体中的数字,但如果我再次调用 spawn,场景中立方体数量达到正确数字所需的次数是我需要反复执行此操作,因为一些立方体会因与墙壁碰撞而被破坏。如果我在更新中这样做,我会得到错误。你有什么建议?我已经更新了代码
  • @skyguy 我建议我在回答中描述的内容。你这样做的方式是不对的。您将收到一个接一个错误以及严重的性能和稳定性问题。你必须重构你的代码并正确地做事。作为另一种我也不推荐的技巧或解决方法,您可以在地图上放置大量空游戏对象,并将立方体生成到其中一些上,这样您就可以确保将它们放置在正确的位置。例如。放置 30 个 GO,您将只生成 10 个立方体(随机选择 10 个 GO),玩家看起来会有些随机。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-06-29
  • 1970-01-01
  • 1970-01-01
  • 2023-03-31
  • 1970-01-01
  • 2016-02-05
  • 1970-01-01
相关资源
最近更新 更多