繁体   English   中英

Physics2D.OverlapCircleAll 未检测到其他游戏对象

[英]Physics2D.OverlapCircleAll not detecting other gameobjects

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

因此,我编写了一个脚本,它使用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;
}

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

启用自动同步转换

当附加到新 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;
    }
}

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

作为 Ruzihm 的精彩答案的附录(在我发现之前被卡住了很长时间。)。

如果您的游戏没有明确地需要每帧 AutoSyncTransforms,那么最好将其关闭,因为它可能会导致性能下降。

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

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

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

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

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

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

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

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

首先,您的代码可以简化为以下内容:

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 不会发生在同一个地方? 虽然设置父级不会修改世界 position,但我仍然会在设置父级后设置 position。 不是这里的问题。

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

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

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

谢谢你, 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)));
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM