74 lines
2.4 KiB
C#
74 lines
2.4 KiB
C#
using UnityEngine;
|
|
|
|
namespace HotUpdate
|
|
{
|
|
/// <summary>
|
|
/// 用地表 MeshCollider 的碰撞高度作为放置 Y。原点在底面中点的物件直接用该值。
|
|
/// </summary>
|
|
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 cols = Collect(searchRoot);
|
|
var offsets = new[]
|
|
{
|
|
Vector3.zero,
|
|
new Vector3(0.35f, 0f, 0.35f),
|
|
new Vector3(-0.35f, 0f, 0.35f),
|
|
new Vector3(0.35f, 0f, -0.35f),
|
|
};
|
|
foreach (var offset in offsets)
|
|
{
|
|
if (TryHit(cols, xz + offset, groundOnly: true, out var y))
|
|
return y;
|
|
}
|
|
foreach (var offset in offsets)
|
|
{
|
|
if (TryHit(cols, xz + offset, groundOnly: false, out var y))
|
|
return y;
|
|
}
|
|
return fallback;
|
|
}
|
|
|
|
static bool TryHit(MeshCollider[] cols, Vector3 xz, bool groundOnly, out float y)
|
|
{
|
|
var ray = new Ray(new Vector3(xz.x, RayStartY, xz.z), Vector3.down);
|
|
var bestDist = float.MaxValue;
|
|
y = 0f;
|
|
var hitAny = false;
|
|
foreach (var col in cols)
|
|
{
|
|
if (col == null || !col.enabled) continue;
|
|
if (groundOnly && !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;
|
|
}
|
|
return hitAny;
|
|
}
|
|
|
|
static MeshCollider[] Collect(Transform searchRoot)
|
|
{
|
|
if (searchRoot != null)
|
|
return searchRoot.GetComponentsInChildren<MeshCollider>();
|
|
return Object.FindObjectsByType<MeshCollider>(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;
|
|
}
|
|
}
|
|
}
|