我试着编写了一个脚本,在任意位置繁殖对象,而不让它们相互碰撞.它无法正常工作,因为OverlayBox几乎每次都会返回空值,即使它触及正方形也是如此.

Here is the script:

var quadBoundaries = quad.GetComponent<MeshCollider>().bounds;
var squareRadius = new Vector2(1, 1);

        foreach (var square in squaresToSpawn)
        {
            _isOverlapping = true;
            while (_isOverlapping)
            {
                _spawnPoint = new Vector2(Random.Range(quadBoundaries.min.x + 1.5f, quadBoundaries.max.x - 1.5f), 
                    Random.Range(quadBoundaries.min.y + 1.5f, quadBoundaries.max.y - 1.5f));

                _collisionWithSquare = Physics2D.OverlapBox(_spawnPoint, squareRadius, 
                    0, LayerMask.GetMask("Square Layer"));

                if (_collisionWithSquare is null)
                {
                    square.transform.position = _spawnPoint;
                    _isOverlapping = false;
                }
            }
        }   

The quadBoundaries are the boundaries of a quad I placed so the squares will randomly spawn in a limited space.
My understanding is that I am generating a random point in the quad boundaries and then I check if on that point a square of scale (1,1) will fit without touching any other thing that has a collider and is on the square layer. if it touches then I generate a new point until the collision is null so I can place the square at the designated position.
But a bunch of things that I don't understand are happening.
First, the squares are touching each other. Second, just a few specific squares are registering a collision but even those are being touched by other squares. Third, when I scale up the square radius (for example 10,10) I get a big split between the squares (shown in the picture bellow).

radius= (10,10)

I must add that all squares have a collider, are all on the square layer and the quad is on a different layer.
Can anybody explain to me what I'm not getting here? Thanks a lot!

推荐答案

在回答之前,我想说,这样的产卵算法是非常危险的,因为你可以进入一个无限循环,当没有新的正方形的地方.至少,要使此代码更安全,您可以添加一个重试计数,以查找要生成的位置.但我会把它留给你的良知.

要使此算法工作,您应该了解,在单位的所有物理更新固定更新.所以,你对PhisycsPhisics2D所做的所有操作,都是在处理对象的状态,这是在上一次物理更新中执行的.当你改变物体的位置时,物理核心不会立即捕捉到这种变化.作为一种解决办法,您可以在修复的更新中分别生成每个对象.就像这样:

public class Spawner : MonoBehaviour
{

    [SerializeField] private GameObject[] _squaresToSpawn;
    [SerializeField] private GameObject _quad;
    
    // Start is called before the first frame update
    void Start()
    {
        StartCoroutine(Spawn());
    }

    private IEnumerator Spawn()
    {
        var quadBoundaries = _quad.GetComponent<MeshCollider>().bounds;
        var squareRadius = new Vector2(1, 1);
        Vector2 spawnPoint;
        
        foreach (var square in _squaresToSpawn)
        {
            yield return new WaitForFixedUpdate();
            var isOverlapping = true;
            var retriesCount = 10;
            while (isOverlapping && retriesCount > 0)
            {
                
                spawnPoint = new Vector2(Random.Range(quadBoundaries.min.x + 1.5f, quadBoundaries.max.x - 1.5f), 
                    Random.Range(quadBoundaries.min.y + 1.5f, quadBoundaries.max.y - 1.5f));

                var hit = Physics2D.OverlapBox(spawnPoint, squareRadius,
                    0, LayerMask.GetMask("Square"));
                
                if (hit is null)
                {
                    square.transform.position = spawnPoint;
                    isOverlapping = false;
                }
                else
                {
                    retriesCount--;
                    if (retriesCount == 0)
                    {
                        Debug.LogError("Can't find place to spawn the object!!");
                    }
                }
            }
        }  
    }
}

But such code will have effect of continious spawning: enter image description here

使对象在一个帧内正常繁殖.您应该手动将所有繁殖的对象边界框存储在代码中,并手动判断新的繁殖边界框是否与先前繁殖的对象发生冲突.

Csharp相关问答推荐

try 使用Microsoft Curve通过外部c#应用程序将Azure AD B2C用户分配到组- . PostAsynock错误CS1061

默认的PSHost实现是什么(用于RunspacePool)?

我无法在Program.cs中实例化我的学生类

ß != ss与ICU进行不区分大小写的比较

Regex在c#中完全匹配

ASP.NET Core:如何在IPageFilter中注入ApplicationDbContext

如何删除文件的基础上嵌入的时间戳嵌入文件名

应用程序启动器,可 Select 物理屏幕

mocking对象的引发事件并作为用于调用方法的参数对象传递到那里

如何解决提交按钮后 Select 选项错误空参照异常

MigraDoc文档

Swagger没有显示int?可以为空

如何在我的C#应用程序中设置带有reactjs前端的SignalR服务器?

在DoubleClick上交换DataGridViewImageColumn的图像和工具提示

HttpClient SendAsync与多线程环境中的ArchiveZip

Content WithTargetPath实际上是有效的MSBuild项吗?

Azure Functions v4中的Serilog控制台主题

多个选项卡上的MudForm验证

如何在C#中正确类型化带有泛型的嵌套类

将字符串类型日期输入(yyyy-mm-ddthh:mm:ss)转换为MM/dd/yyyy格式