using UnityEngine; namespace HotUpdate { /// /// 用地表 MeshCollider 的碰撞高度作为放置 Y。原点在底面中点的物件直接用该值。 /// public static class GroundSit { const float RayStartY = 80f; const float RayLength = 160f; public static float Height(Vector3 xz, Transform searchRoot = null, float fallback = 0f) { Physics.SyncTransforms(); var ray = new Ray(new Vector3(xz.x, RayStartY, xz.z), Vector3.down); var bestDist = float.MaxValue; var y = fallback; var hitAny = false; foreach (var col in Collect(searchRoot)) { if (col == null || !col.enabled) continue; if (!IsGroundCollider(col)) continue; if (!col.Raycast(ray, out var hit, RayLength)) continue; if (hit.distance >= bestDist) continue; bestDist = hit.distance; y = hit.point.y; hitAny = true; } if (hitAny) return y; foreach (var col in Collect(searchRoot)) { if (col == null || !col.enabled) continue; if (!col.Raycast(ray, out var hit, RayLength)) continue; if (hit.distance >= bestDist) continue; bestDist = hit.distance; y = hit.point.y; hitAny = true; } return hitAny ? y : fallback; } static MeshCollider[] Collect(Transform searchRoot) { if (searchRoot != null) return searchRoot.GetComponentsInChildren(); return Object.FindObjectsByType(FindObjectsSortMode.None); } static bool IsGroundCollider(MeshCollider col) { for (var t = col.transform; t != null; t = t.parent) { if (t.name.IndexOf("ground", System.StringComparison.OrdinalIgnoreCase) >= 0) return true; } return false; } } }