如何在无Terrain的场景中依据高度随机生成路点对象?
问题背景
原有Unity脚本依赖Terrain组件实现随机路点生成,但当前场景采用资源包中的山地模型(无Terrain组件),需要修改脚本适配新场景。
原有脚本
using System.Collections; using System.Collections.Generic; using UnityEditor; using UnityEngine; public class SpawnObjects : MonoBehaviour { public GameObject prefab; public Terrain terrain; public int numberOfObjects; public float duration; public float yOffset = 0.5f; private float terrainWidth; private float terrainLength; private float xTerrainPos; private float zTerrainPos; void Awake() { //Get terrain size terrainWidth = terrain.terrainData.size.x; terrainLength = terrain.terrainData.size.z; //Get terrain position xTerrainPos = terrain.transform.position.x; zTerrainPos = terrain.transform.position.z; StartCoroutine(Generate()); } IEnumerator Generate() { //Generate the Prefab on the generated position for (int i = 0; i < numberOfObjects; i++) { //Generate random x,z,y position on the terrain float randX = UnityEngine.Random.Range(xTerrainPos, xTerrainPos + terrainWidth); float randZ = UnityEngine.Random.Range(zTerrainPos, zTerrainPos + terrainLength); float yVal = Terrain.activeTerrain.SampleHeight(new Vector3(randX, 0, randZ)); //Apply Offset if needed yVal = yVal + yOffset; GameObject objInstance = (GameObject)Instantiate(prefab, new Vector3(randX, yVal, randZ), Quaternion.identity); if (duration > 0) { yield return new WaitForSeconds(duration); } } } }
修改后的适配脚本
using System.Collections; using System.Collections.Generic; using UnityEngine; public class SpawnObjects : MonoBehaviour { public GameObject prefab; // 拖拽场景中的山地模型到此处 public GameObject mountainModel; public int numberOfObjects; public float duration; public float yOffset = 0.5f; // 可选:扩展生成范围边界,避免过度贴近模型边缘 public float boundsExpand = 1f; private Bounds mountainBounds; void Awake() { Renderer mountainRenderer = mountainModel.GetComponent<Renderer>(); if (mountainRenderer == null) { Debug.LogError("山地模型必须挂载Renderer组件,无法获取生成范围!"); return; } mountainBounds = mountainRenderer.bounds; mountainBounds.Expand(boundsExpand); StartCoroutine(Generate()); } IEnumerator Generate() { for (int i = 0; i < numberOfObjects; i++) { // 在山地包围盒范围内随机生成X、Z坐标 float randX = Random.Range(mountainBounds.min.x, mountainBounds.max.x); float randZ = Random.Range(mountainBounds.min.z, mountainBounds.max.z); // 从山地上方发射向下射线,检测地表高度 Ray ray = new Ray(new Vector3(randX, mountainBounds.max.y + 10f, randZ), Vector3.down); if (Physics.Raycast(ray, out RaycastHit hit, mountainBounds.size.y + 20f)) { // 确保命中的是目标山地模型(可通过标签进一步过滤) if (hit.collider.gameObject == mountainModel) { float yVal = hit.point.y + yOffset; Instantiate(prefab, new Vector3(randX, yVal, randZ), Quaternion.identity); } else { // 命中其他对象,重新生成坐标 i--; } } else { // 射线未命中,重新生成坐标 i--; } if (duration > 0) { yield return new WaitForSeconds(duration); } } } }
核心修改点
- 替换依赖对象:移除
Terrain变量,改用GameObject mountainModel,直接关联场景中的山地模型。 - 基于包围盒确定生成范围:通过山地模型的
Renderer.bounds获取X、Z轴的生成边界,替代原Terrain的尺寸计算逻辑。 - 射线检测替代地形采样:用向下射线检测山地表面的方式获取Y轴坐标,取代
Terrain.SampleHeight,适配模型地形。 - 容错逻辑:当射线未命中山地或命中其他对象时,重新生成坐标,确保路点仅生成在山地表面。
- 可选优化:通过
boundsExpand调整生成范围,或给山地模型设置专属标签,在射线检测时通过hit.collider.tag精准过滤。
内容的提问来源于stack exchange,提问作者Daniel Lip
相关产品推荐
相关产品推荐

