【问题标题】:How to Spawn Objects in Unity3D with a Minimum Distance between如何在 Unity3D 中以最小距离生成对象
【发布时间】:2022-01-18 21:30:22
【问题描述】:

我正在编程一个随机的"Stone" Spawner,目前有一个大问题。我有一些解决方法的想法,但想知道一种性能友好的方法。

所以我去Spawn the Objects on the Sphere Surface 的方式是这样的:

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

public class SpawnObjects : MonoBehaviour
{
    public Vector3 centerOfSphere = new Vector3(0, 5000, 0);
    public float radiusOfSphere = 5000.0f;

    public List<GameObject> stones;
    public int stonesToSpawn = 1;

    void Start()
    {
        Vector3 center = transform.position + centerOfSphere;       //Setting the center position of the Sphere

        //This for loop is spawning the Stones on a random position on Sphere Surface
        for (int i = 0; i < stonesToSpawn; i++)
        {
            Vector3 pos = RandomCircle(center, radiusOfSphere);
            Quaternion rot = Quaternion.FromToRotation(Vector3.forward, center - pos);
            Instantiate(stones[Random.Range(0, stones.Count)], pos, rot);
        }
    }

    //Method returns a Random Position on a Sphere
    Vector3 RandomCircle(Vector3 center, float radius) 
    {
        float alpha = UnityEngine.Random.value * 360;
        float beta = UnityEngine.Random.value * 360;
        Vector3 pos;
        pos.x = radius * Mathf.Cos(beta) * Mathf.Cos(alpha);
        pos.y = radius * Mathf.Cos(beta) * Mathf.Sin(alpha);
        pos.z = radius * Mathf.Sin(beta);

        return pos;
    }
}

非常感谢您的以下解释! :)

【问题讨论】:

标签: c# unity3d


【解决方案1】:

正如所说,让您的生活更轻松,只需使用Random.onUnitSphere,这样您的整个方法RandomCircle(顺便说一句,更改名称!)就可以缩小到

private Vector3 RandomOnSphere(Vector3 center, float radius)
{
    return center + Random.onUnitSphere * radius;
}

然后为了使它们之间的距离最小,可能有多种方法,但我想最简单的-蛮力-方法是:

  • 存储已使用的职位
  • 当您获得一个新的随机位置时,检查与现有位置的距离
  • 不断获取新的随机位置,直到找到一个与现有位置不太接近的位置

这当然很大程度上取决于您的用例以及对象的数量和最小距离等 - 换句话说,我让您自己确保请求的数量和最小距离对于给定的球体完全可行半径。

你总是可以离开一个“紧急出口”并在例如之后放弃。 100 次尝试。

类似的东西,例如

// Linq offers some handy query shorthands that allow to shorten
// long foreach loops into single calls
using System.Linq;

...

private const int MAX_ATTEMPTS = 100;

public float minimumDistance = 1f;

void Start()
{
    var center = transform.position + centerOfSphere;

    // It is cheaper to use with square magnitudes
    var minDistanceSqr = minimumDistance * minimumDistance;

    // For storing the already used positions
    // Already initialize with the correct capacity, this saves resources
    var usedPositions = new List<Vector3>(stonesToSpawn);

    for (int i = 0; i < stonesToSpawn; i++)
    {
        // Keep track of the attempts (for the emergency break)
        var attempts = 0;
        Vector3 pos = Vector3.zero;
        do
        {
            // Get a new random position
            pos = RandomOnSphere(center, radiusOfSphere);
            // increase the attempts
            attempts++;

            // We couldn't find a "free" position within the 100 attempts :(
            if(attempts >= MAX_ATTEMPTS)
            {
                throw new Exception ("Unable to find a free spot! :'(");
            }
        }
        // As the name suggests this checks if any "p" in "usedPositions" is too close to the given "pos"
        while(usedPositions.Any(p => (p - pos).sqrMagnitude <= minDistanceSqr)));
        
        var rot = Quaternion.FromToRotation(Vector3.forward, center - pos);
        Instantiate(stones[Random.Range(0, stones.Count)], pos, rot);

        // Finally add this position to the used ones so the next iteration
        // also checks against this position
        usedPositions.Add(pos);
    }
}

在哪里

usedPositions.Any(p => (p - pos).sqrMagnitude <= minDistanceSqr))

基本上等于做类似的事情

private bool AnyPointTooClose(Vector3 pos, List<Vector3> usedPositions, float minDistanceSqr)
{
    foreach(var p in usedPositions)
    {
        if((p - pos).sqrMagnitude <= minDistanceSqr)
        {
            return true;
        }
    }

    return false;
}

如果你更容易理解的话

【讨论】:

  • 谢谢你,这对我帮助很大:)我希望这个答案也能帮助其他人:)
猜你喜欢
  • 1970-01-01
  • 2015-02-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多