Net.Like.Xue.Tokyo/Assets/BITKit/Unity/Scripts/Physics/GetClosePointFromCollider.cs

193 lines
6.6 KiB
C#
Raw Normal View History

2024-11-03 16:42:23 +08:00
using System.Collections;
using System.Collections.Generic;
2025-02-24 23:03:39 +08:00
using System.Globalization;
2024-11-03 16:42:23 +08:00
using System.Linq;
using System.Text;
2025-02-24 23:03:39 +08:00
using DrawXXL;
2024-11-03 16:42:23 +08:00
using UnityEngine;
namespace BITKit.Physics
{
public class GetClosePointFromCollider : IClosePointProvider
{
public string Name="Default";
2025-02-24 23:03:39 +08:00
public readonly Transform Transform;
2024-11-03 16:42:23 +08:00
public Vector3 Offset = default;
public LayerMask LayerMask=LayerMask.NameToLayer("Default");
public float Distance=1.6f;
public float MinHeight=0.32f;
public float MaxHeight = 1f;
private readonly Collider[] _colliders=new Collider[8];
private readonly Collider[] _mainCollider=new Collider[8];
public GetClosePointFromCollider(Transform transform)
{
Transform = transform;
}
public bool TryGetValue(out Vector3 position, out Collider collider)
{
StringBuilder reportBuilder = new();
reportBuilder.AppendLine($"检测任务:{Name}");
position = Transform.position + Transform.rotation * Offset;
var detectedLength = UnityEngine.Physics.OverlapSphereNonAlloc(position, Distance, _mainCollider, LayerMask);
reportBuilder.AppendLine($"检测到了{detectedLength}个碰撞体");
2025-02-24 23:03:39 +08:00
var validMeshColliders = new Queue<(Collider collider,Vector3 targetPosition)>();
var samplePoint = position;
samplePoint.y += Distance / 2;
2024-11-03 16:42:23 +08:00
foreach (var collider1 in _mainCollider.Take(detectedLength).OrderBy(ByTop).Reverse())
{
if (collider1.isTrigger)
{
reportBuilder?.AppendLine("碰撞体是触发器");
continue;
}
2025-02-24 23:03:39 +08:00
Vector3 closePoint;
2024-11-03 16:42:23 +08:00
switch (collider1)
{
2025-02-24 23:03:39 +08:00
case TerrainCollider terrainCollider:
{
closePoint = terrainCollider.ClosestPointOnBounds(samplePoint);
}
break;
case MeshCollider { convex: false } meshCollider:
{
var getClosestPointFromMesh =
new GetClosestPointFromMesh(meshCollider.sharedMesh,meshCollider.transform.InverseTransformPoint(samplePoint));
if (getClosestPointFromMesh.TryGetValue(out var localPosition, out collider))
{
localPosition = meshCollider.transform.TransformPoint(localPosition);
Debug.DrawLine(Transform.position,localPosition,Color.magenta);
if (Vector3.Distance(localPosition, position) < Distance)
{
closePoint = localPosition;
}
else
{
continue;
}
}
else
{
continue;
}
}
break;
default:
closePoint = collider1.ClosestPoint(samplePoint);
break;
2024-11-03 16:42:23 +08:00
}
2025-02-24 23:03:39 +08:00
if(collider1.Raycast(new Ray(Transform.position,Transform.forward),out var raycastHit,64) is false)
{
continue;
}
if (MathV.IsForward(position, Transform.forward, closePoint) is false)
2024-11-03 16:42:23 +08:00
{
2025-02-24 23:03:39 +08:00
//DrawBasics.PointTag(closePoint,"not forward");
continue;
2024-11-03 16:42:23 +08:00
}
2025-02-24 23:03:39 +08:00
if (Transform.position.y + MinHeight > closePoint.y)
2024-11-03 16:42:23 +08:00
{
2025-02-24 23:03:39 +08:00
DrawBasics.PointTag(closePoint,"not enough height");
continue;
2024-11-03 16:42:23 +08:00
}
2025-02-24 23:03:39 +08:00
2024-11-03 16:42:23 +08:00
2025-02-24 23:03:39 +08:00
var height = Mathf.Abs(closePoint.y - Transform.position.y);
2024-11-03 16:42:23 +08:00
if (height > MaxHeight)
{
reportBuilder?.AppendLine($"高度差距过大:{height}");
continue;
}
2025-02-24 23:03:39 +08:00
2024-11-03 16:42:23 +08:00
2025-02-24 23:03:39 +08:00
if (UnityEngine.Physics.Linecast(Transform.position, closePoint, out var raycastHit2, LayerMask))
2024-11-03 16:42:23 +08:00
{
if (raycastHit2.collider != collider1)
{
reportBuilder?.AppendLine($"检测到了其他碰撞体:{raycastHit2.transform.name}");
continue;
}
}
2025-02-24 23:03:39 +08:00
var length = UnityEngine.Physics.OverlapSphereNonAlloc(closePoint+Vector3.up*0.2f, 0.1f, _colliders, LayerMask);
2024-11-03 16:42:23 +08:00
switch (length)
{
2025-02-24 23:03:39 +08:00
case > 0:
2024-11-03 16:42:23 +08:00
reportBuilder.AppendLine("检测到了更多碰撞体");
for (var ii = 0; ii < length; ii++)
{
//Debug.DrawLine(vector3, _colliders[ii].ClosestPoint(vector3), Color.red, 8);
reportBuilder.AppendLine($"\t{_colliders[ii].name}");
}
continue;
}
2025-02-24 23:03:39 +08:00
2024-11-03 16:42:23 +08:00
reportBuilder.AppendLine("<color=green>成功</color>");
2025-02-24 23:03:39 +08:00
2024-11-03 16:42:23 +08:00
//BIT4Log.Log<GetClosePointFromCollider>(reportBuilder.ToString());
2025-02-24 23:03:39 +08:00
Debug.DrawLine(Transform.position,closePoint,Color.green);
validMeshColliders.Enqueue(new(collider1,closePoint));
}
var minDot = 64f;
Collider resultCollider = default;
Vector3 resultPosition=default;
while (validMeshColliders.TryDequeue(out var result))
{
var dot =Mathf.Abs(Vector3.Cross(Transform.forward, result.targetPosition-Transform.position).y);
DrawBasics.LineFrom(Transform.position,result.targetPosition-Transform.position,Color.red,text:dot.ToString(CultureInfo.InvariantCulture));
if(dot>minDot)continue;
resultCollider = result.collider;
resultPosition = result.targetPosition;
minDot = dot;
}
if (minDot < 64)
{
collider = resultCollider;
position = resultPosition;
return true;
2024-11-03 16:42:23 +08:00
}
collider = null;
return false;
}
private float ByTop(Collider arg)
{
return arg.bounds.center.y + arg.bounds.extents.y;
}
}
}