嗨,我正在研究使用随机地形的游戏,我想在该地形上生成对象。为此,我创建了所谓的Surface Populator脚本。
这是脚本:
public SurfaceSpawnerData spawnerData;
private float randomX;
private float randomZ;
private Renderer r;
void Start()
{
r = GetComponent<Renderer>();
for (int i = 0; i < spawnerData.spawnableObjects.Length; i++)
{
spawnerData.spawnableObjects[i].currentObjects = 0;
}
spawnerData.SpawnedObjects.Clear();
SpawnObjects();
}
void Update()
{
}
void SpawnObjects()
{
RaycastHit hit;
for (int i = 0; i < spawnerData.spawnableObjects.Length; i++)
{
int currentObjects = spawnerData.spawnableObjects[i].currentObjects;
int numOfObjects = spawnerData.spawnableObjects[i].numberOfObjects;
if (currentObjects != numOfObjects)
{
if (Physics.Raycast(new Vector3(randomX, r.bounds.max.y + 5f, randomZ), -Vector3.up, out hit))
{
randomX = Random.Range(r.bounds.min.x, r.bounds.max.x);
randomZ = Random.Range(r.bounds.min.z, r.bounds.max.z);
if (hit.point.y >= spawnerData.spawnableObjects[i].spawnerStartHeight && hit.point.y <= spawnerData.spawnableObjects[i].spawnerEndHeight)
{
spawnerData.SpawnedObjects.Add(Instantiate(spawnerData.spawnableObjects[i].spawnablePrefab, hit.point, Quaternion.identity));
spawnerData.spawnableObjects[i].currentObjects += 1;
}
}
}
}
}
脚本还从可编写脚本的对象中获取数据:
[CreateAssetMenu]
public class SurfaceSpawnerData : ScriptableObject
{
public SpawnableObjects[] spawnableObjects;
public List<GameObject> SpawnedObjects;
[System.Serializable]
public class SpawnableObjects
{
public GameObject spawnablePrefab;
public float spawnerStartHeight = 2f;
public float spawnerEndHeight;
public int currentObjects;
public int numberOfObjects;
}
}
当将此脚本放入update方法中时,该脚本当前可以很好地工作,但是由于其对性能的影响,我不想这样做。因此,我想知道是否有一种方法可以停止Unity start方法的退出,直到我的SpawnObjects()函数停止运行为止。如果这是不可能的,如果您对如何仅运行一次而不使用更新功能有任何其他想法,请通知我。
我对使用C#作为一种语言还是比较陌生的,如果我错过了一个简单的解决方法,我感到抱歉。任何帮助,将不胜感激。谢谢。
答案 0 :(得分:2)
由于SpawnObjects
是同步方法,Start
直到SpawnObjects
完成后才会返回。
据我了解,您的问题是,Physics
中的任何内容在初始化期间(Awake
,OnEnable
,Start
)不可用,而仅在物理块(请参阅ExecutionOrder),例如例如FixedUpdate
或Update
。
所以回答您的问题:您可以使用Coroutine和WaitForFixedUpdate
来进行实例化:
void Start()
{
r = GetComponent<Renderer>();
for (int i = 0; i < spawnerData.spawnableObjects.Length; i++)
{
spawnerData.spawnableObjects[i].currentObjects = 0;
}
spawnerData.SpawnedObjects.Clear();
StartCoroutine(DoInstantiate());
}
private IEnumerator DoInstantiate()
{
// wait until Physics are initialized
yield return new WaitForFixedUpdate();
SpawnObjects();
}
或在ScriptReference/Coroutine中可以看到,您可以通过直接将Start
设置为例行程序来简化此过程喜欢
IEnumerator Start()
{
r = GetComponent<Renderer>();
for (int i = 0; i < spawnerData.spawnableObjects.Length; i++)
{
spawnerData.spawnableObjects[i].currentObjects = 0;
}
spawnerData.SpawnedObjects.Clear();
// wait until Physics are initialized
yield return new WaitForFixedUpdate();
SpawnObjects();
}