簡體   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