【问题标题】:Physics2D.OverlapCircleAll not detecting other gameobjectsPhysics2D.OverlapCircleAll 未检测到其他游戏对象
【发布时间】:2019-09-30 21:24:04
【问题描述】:

我有一个敌人的预制件,它会在玩家周围的随机位置多次生成。但是,有时这会使一个敌人预制件与另一个敌人预制件重叠。

所以,我编写了一个脚本,它使用Physics2D.OverlapCircleAll() 在实例化敌人预制件之前检测任何对撞机,从而避免敌人预制件与现有敌人重叠。我的问题是OverlapCircleAll() 没有检测到预制件的其他实例。

我也已经尝试过Physics2D.OverlapBoxAll。如果我生成的这些“敌人预制件”超过30,至少有一个会与另一个敌人重叠

这是用于检测重叠的代码:

public void SpawnEachEnemy(GameObject Enemy)
{
    Vector3 futurePosition = new Vector2(UnityEngine.Random.Range(UpperLeft.transform.position.x, DownRight.transform.position.x),
                                UnityEngine.Random.Range(UpperLeft.transform.position.y, DownRight.transform.position.y));
    bool correctPosition = false;
    while (!correctPosition)
    {
        Collider2D[] collider2Ds = Physics2D.OverlapCircleAll(futurePosition,0.2f);
        if (collider2Ds.Length > 0)
        {
            //re-spawning to prevent overlap
            futurePosition = new Vector2(UnityEngine.Random.Range(UpperLeft.transform.position.x, DownRight.transform.position.x),
                                UnityEngine.Random.Range(UpperLeft.transform.position.y, DownRight.transform.position.y));
        }
        else
        {
            correctPosition = true;
        }
    }

    GameObject b = Instantiate(Enemy) as GameObject;
    b.transform.position = futurePosition;
    b.transform.parent = this.transform;
}

【问题讨论】:

  • 请编辑您的问题以包含minimal reproducible exampleOverlapCircleAll 可能返回意外值的原因有很多,但问题中没有足够的信息来确定这里发生了什么。投票结束,直到添加 minimal reproducible example
  • Physics2D.OverlapCircleAll(...) 函数是否会返回任何内容?你确定每个敌人都有一个对撞机吗?还可以考虑调整 Physics2D.OverlapCircleAll(..., r) 的半径以查看它是否检测到任何敌人。您提供的代码似乎正确。
  • @Ruzihm 这个代码已经是一个可重现的例子,你只需要从循环中调用这个函数并传递一个有碰撞器的游戏对象。
  • @Vitulus 每个名字都是同一个预制件的克隆我确信有一个对撞机。我已经尝试使用不同的半径,结果是一样的,overlapCircleAll 返回一些碰撞器,但不是一些靠近生成位置的碰撞器,所以会发生重叠......
  • 如果 OverlapCircleAll 返回一些碰撞器,它应该总是靠近生成位置(又名 futurePosition)。确定不是这样吗?

标签: c# unity3d


【解决方案1】:

Louis Garczynski 提到了一些可能性,但没有提及的是,如果这些都在单个帧的范围内实例化(基于评论的猜测 SpawnEachEnemy 在循环中被调用),那么您可能需要在 Physics2D 设置下启用Auto Sync Transforms

minimal reproducible example 在新的 3D 项目场景中附加到相机时应该可以在启用Auto Sync Transforms 的情况下正常工作,并且在禁用时将无法防止重叠。这可能是阻止它为您工作的原因:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TestScript : MonoBehaviour
{
    Vector3 upperLeft;
    Vector3 downRight;

    GameObject prefab;

    // Start is called before the first frame update
    void Start()
    {
        transform.position = new Vector3(0, 0, -3);
        upperLeft = new Vector3(-1, -1);
        downRight = new Vector3(1, 1);

        prefab = GameObject.CreatePrimitive(PrimitiveType.Sphere);
        DestroyImmediate(prefab.GetComponent<SphereCollider>());
        prefab.transform.localScale = 0.4f * Vector3.one;
        prefab.AddComponent<CircleCollider2D>();

        for (int i = 0; i < 12; i++)
        {
            SpawnEachEnemy(prefab);
        }

        prefab.SetActive(false);

    }


    public void SpawnEachEnemy(GameObject Enemy)
    {
        Vector3 futurePosition;
        Collider2D[] collider2Ds;

        do { 
            futurePosition = new Vector2(
                UnityEngine.Random.Range(
                    upperLeft.x,
                    downRight.x),

                UnityEngine.Random.Range(
                    upperLeft.y, 
                    downRight.y));

            collider2Ds = Physics2D.OverlapCircleAll(futurePosition, 0.2f)
        } 
        while (collider2Ds.Length > 0)

        GameObject b = Instantiate(Enemy) as GameObject;
        b.transform.position = futurePosition;
        b.transform.parent = this.transform;
    }
}

【讨论】:

  • 完美!!!我启用了自动同步转换,现在一切正常!!!非常感谢!!!!
【解决方案2】:

我在编写一些功能测试时遇到了这个问题。

作为 Ruzihm 的绝妙答案的附录(被困了很长时间,直到我发现它!)。

If your game does not explicitly need AutoSyncTransforms every frame, then its preferable to leave it off, as it can cause a performance hit.

您应该只将 autoSyncTransforms 设置为 true,以便在现有项目中实现物理向后兼容性

如果您只是在测试或加载框架上需要它,那么:

您可以手动调用转换同步:

Physics.SyncTransforms();Physics2D.SyncTransforms();

或在开始时设置 Physics.autoSyncTransforms = true;,然后在 Start() 方法结束时设置为 false。

其中任何一个都更可取,因为您不会在后续帧上受到惩罚。

如果您的发现必须在正常运行中使用 AutoSyncTransform 或 SyncTransform()。考虑使用Coroutine 来推迟实例化,这样脚本就不会一次创建很多东西。

理想情况下,您希望每秒尽可能多的帧,因此在连续帧上一次产生一个/几个东西“可能”对游戏玩法影响很小。而不是因为脚本试图一次创建太多内容而导致整体性能下降和潜在的卡顿。

【讨论】:

    【解决方案3】:

    首先你的代码可以简化成这样:

    public void SpawnEachEnemy(GameObject Enemy)
    {
        Vector3 futurePosition;
        do
        {
            futurePosition = new Vector2(
                UnityEngine.Random.Range(UpperLeft.transform.position.x, DownRight.transform.position.x),
                UnityEngine.Random.Range(UpperLeft.transform.position.y, DownRight.transform.position.y)
            );
    
        } while (Physics2D.OverlapCircleAll(futurePosition,0.2f).Length > 0)
    
        GameObject b = Instantiate(Enemy) as GameObject;
        b.transform.position = futurePosition;
        b.transform.parent = this.transform;
    }
    

    我还建议在您的循环中添加一个安全计数器,以避免在没有空间时出现无限循环。

    现在,很多事情都可能出错:

    • 也许OverlapCircle 和 spawn 不在同一个地方?虽然设置父级不会修改世界位置,但我仍然会在设置父级后设置位置。不是这里的问题。

    • 可能重叠的尺寸太小了?你确定你的敌人的半径是 0.2 个单位吗?考虑使用Debug.DrawLine绘制扫描圆的半径。

    • 也许你的敌人不在DefaultRaycastLayers 的层中?尝试使用更大的圆半径并在OverlapCircleAll 实际工作时添加Debug.Log

    • 还有一些其他可能的原因,例如禁用的碰撞器或太小的碰撞器等。不过,这应该涵盖最可能的错误。

    【讨论】:

      【解决方案4】:

      谢谢Ruzihm! 几天来我一直在寻找这个答案,我在使用 Physics2D.OverlapCircle 的代码时遇到了同样的问题。我很惊讶在其他任何地方都没有找到提到自动同步转换的人。

      if ( Physics2D.OverlapCircle(position, radio) == null) {
         
         GameObject obstacleInst = Instantiate(obstacle, transform);
      
         obstacleInst.transform.position = position;
         obstacleInst.transform.localScale = new Vector3(scale, scale, 1);
         obstacleInst.transform.rotation = Quaternion.Euler(new Vector3(0, 0, Random.Range(0, 360)));
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-24
        • 2017-04-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多