using System; using System.Collections; using System.Collections.Generic; using System.Data; using System.Linq; using System.Text; using UnityEngine; namespace BITKit { public interface IClosePoint { Vector3 CurrentPoint { get; } Collider Collider { get; } bool TryGetClosePoint(out Vector3 vector3); } [Serializable] public class GetClosePointFromCollider : IClosePoint { [SerializeField] private string name; [SerializeField] private Transform transform; [SerializeField] private Vector3 offset = Vector3.one; [SerializeField] private LayerMask layerMask; [SerializeField] private float distance; [SerializeField] private float minHeight=0.32f; [SerializeField] private float maxHeight = 1f; public Vector3 CurrentPoint { get; set; } public Collider Collider { get; set; } private Collider[] _colliders=new Collider[8]; private Collider[] _mainCollider=new Collider[8]; public bool TryGetClosePoint(out Vector3 vector3) { vector3 = default; StringBuilder reportBuilder = new(); reportBuilder.AppendLine($"检测任务:{name}"); var position = transform.position + transform.rotation * offset; var detectedLength = Physics.OverlapSphereNonAlloc(position, distance, _mainCollider, layerMask); reportBuilder.AppendLine($"检测到了{detectedLength}个碰撞体"); for (var i = 0; i top) { reportBuilder?.AppendLine("高度不足"); continue; } var nextPos = position; nextPos.y = collider.bounds.center.y; if (collider.Raycast(new Ray(nextPos, transform.forward), out _, distance) is false) { reportBuilder?.AppendLine("未检测到前方"); continue; } var height = Mathf.Abs(top - transform.position.y); if (height > maxHeight) { reportBuilder?.AppendLine($"高度差距过大:{height}"); continue; } if (Physics.Linecast(transform.position, vector3, out var raycastHit2, layerMask)) { if (raycastHit2.collider != collider) { reportBuilder?.AppendLine($"检测到了其他碰撞体:{raycastHit2.transform.name}"); continue; } }; var length = Physics.OverlapSphereNonAlloc(vector3, 0.01f, _colliders, layerMask); switch (length) { case 1: if (_colliders[0] != collider) { reportBuilder.AppendLine($"检测到了其他碰撞体{_colliders[0].name}"); continue; } break; case > 1: 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; } Collider = collider; vector3.y = top; CurrentPoint = vector3; reportBuilder.AppendLine("成功"); //BIT4Log.Log(reportBuilder.ToString()); return true; } //BIT4Log.Log(reportBuilder.ToString()); return false; } } /// /// 获取碰撞点可以翻越后的点 /// [Serializable] public class GetVaultPointFromCollider : IClosePoint { public Transform root; public Transform groundReference; public LayerMask layerMask; public float maxHeight = 1.2f; public float maxVaultDistance=1; public float radius; public float distance; public Vector3 StartPosition; public Vector3 EndPosition; public Vector3 CurrentPoint { get; set; } public Collider Collider { get; set; } private Rigidbody rigidbody; private bool isInitialized; public bool TryGetClosePoint(out Vector3 vector3) { if (isInitialized is false) { rigidbody = groundReference.GetComponent(); isInitialized = true; } if (rigidbody) { vector3 = default; if (rigidbody.velocity.GetLength() < 0.1f) return false; } //var reportBuilder = new System.Text.StringBuilder(); StringBuilder reportBuilder=null; var forward = root.forward; var sourceStartPosition = groundReference.position; sourceStartPosition.y = root.position.y; var startPosition = sourceStartPosition; var collider = UnityEngine.Physics.OverlapSphere(startPosition, radius, layerMask); reportBuilder?.AppendLine($"检测到了{collider.Length}个碰撞体"); foreach (var hit in collider) { var top = hit.bounds.center + hit.bounds.extents; if(top.y{hit.name}"); if(top.y>groundReference.transform.position.y+maxHeight) { reportBuilder?.AppendLine("高度超出可翻越高度"); continue; } var start = sourceStartPosition+forward*8; //start.y = hit.bounds.center.y; var ray = new Ray(start, -forward); if (hit.Raycast(ray, out var colliderHit, 8) is false) { reportBuilder?.AppendLine("未检测到背面,算法错误"); //Debug.DrawRay(ray.origin, ray.direction * 8, Color.red, 8); continue; } EndPosition = colliderHit.point + colliderHit.normal*0.4f; EndPosition.y = top.y; try { foreach (var x in UnityEngine .Physics .OverlapSphere(EndPosition, 0.1f, layerMask)) { if(Equals(x, hit)) continue; throw new OperationCanceledException($"终点有其他碰撞体{x.name}"); } } catch (OperationCanceledException e) { reportBuilder?.AppendLine(e.Message); continue; } if(UnityEngine.Physics.Raycast(EndPosition,Vector3.down,out _,1.6f,layerMask) is false) { //Debug.DrawRay(EndPosition, Vector3.down*1.6f, Color.red, 8); reportBuilder?.AppendLine("未检测到地面,跳过"); continue; //Debug.DrawRay(EndPosition, Vector3.down, Color.red, 8); } var fixdPosition = colliderHit.point; fixdPosition.y=hit.bounds.center.y; var start2 = fixdPosition; start2.y += 0.1f; var end2 = fixdPosition; end2.y -= 0.1f; if(UnityEngine.Physics.Linecast(start2,end2,out var downHit,layerMask)) { reportBuilder?.AppendLine($"检测到了障碍物{downHit.collider.name}"); //BIT4Log.Log(reportBuilder.ToString()); continue; } start = startPosition; start.y = hit.bounds.center.y; ray = new Ray(start, forward); if(hit.Raycast(ray,out colliderHit,8) is false) { reportBuilder?.AppendLine("未检测到正面,算法错误"); //Debug.DrawRay(ray.origin, ray.direction * 8, Color.red, 8); continue; } StartPosition = colliderHit.point; StartPosition.y = top.y; StartPosition += colliderHit.normal * 0.4f; var closeStart = hit.ClosestPoint(StartPosition); var closeEnd = hit.ClosestPoint(EndPosition); var lineDistance = Vector3.Distance(closeStart, closeEnd); if(lineDistance > maxVaultDistance) { reportBuilder?.AppendLine($"长度{lineDistance}超出可翻越距离{maxVaultDistance}"); //Debug.DrawLine(closeStart,closeEnd, Color.yellow, 4); //BIT4Log.Log(reportBuilder.ToString()); continue; } if(Physics.Linecast(closeStart+Vector3.up*0.1f,closeEnd+Vector3.up*0.1f,out var _hit,layerMask)) { //Debug.DrawLine(closeStart+Vector3.up*0.1f,_hit.point, Color.red, 4); reportBuilder?.AppendLine("检测到了障碍物"); continue; } else { //Debug.DrawLine(closeStart+Vector3.up*0.1f,closeEnd+Vector3.up*0.1f, Color.green, 4); } vector3 = colliderHit.point; vector3.y = top.y; vector3 += colliderHit.normal * 0.4f; reportBuilder?.AppendLine(); if(reportBuilder is not null) BIT4Log.Log(reportBuilder.ToString()); CurrentPoint = vector3; Collider = hit; return true; } reportBuilder?.AppendLine($"failed"); if(reportBuilder is not null) BIT4Log.Log(reportBuilder.ToString()); vector3 = default; return false; } } }