我正在隨機編程"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;
}
}
所以感謝您的以下解釋!:)
uj5u.com熱心網友回復:
如前所述,只需使用即可使您的生活更輕松,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;
}
如果這對你來說更好理解
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/385950.html
