iFactory.Cutting.Unity/Assets/BITKit/Unity/Scripts/Physics/IClosePoint.cs

232 lines
8.2 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using UnityEngine;
namespace BITKit
{
public interface IClosePoint
{
Collider Collider { get; }
bool TryGetClosePoint(out Vector3 vector3);
}
[System.Serializable]
public class GetClosePointFromCollider : IClosePoint
{
public Transform root;
public LayerMask layerMask;
public float distance;
public Collider Collider { get; set; }
public bool TryGetClosePoint(out Vector3 vector3)
{
vector3 = default;
if (UnityEngine.Physics.Raycast(root.position, root.forward, out var raycastHit, distance, layerMask))
{
var collider = raycastHit.collider;
if (collider.isTrigger) return false;
switch (collider)
{
case MeshCollider meshCollider:
if (meshCollider.convex is false)
return false;
break;
}
vector3 = collider.ClosestPoint(root.position + Vector3.up);
var top = collider.bounds.center + collider.bounds.extents;
if (Mathf.Abs(vector3.y - top.y) > 0.16f) return false;
if (UnityEngine.Physics.Linecast(root.position, vector3, out var raycastHit2, layerMask))
{
if(raycastHit2.collider != collider)
return false;
};
foreach(var hit in UnityEngine.Physics.OverlapSphere(vector3, 0.1f, layerMask))
{
if(hit!= collider)
return false;
}
Collider = collider;
return true;
//return vector3.y >= collider.bounds.center.y + collider.bounds.extents.y;
//return true;
}
return false;
}
}
/// <summary>
/// 获取碰撞点可以翻越后的点
/// </summary>
[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 Collider Collider { get; set; }
private Rigidbody rigidbody;
private bool isInitialized;
public bool TryGetClosePoint(out Vector3 vector3)
{
if (isInitialized is false)
{
rigidbody = groundReference.GetComponent<Rigidbody>();
isInitialized = true;
}
if (rigidbody)
{
vector3 = default;
if (rigidbody.velocity.GetLength() < 0.1f) return false;
}
var reportBuilder = new System.Text.StringBuilder();
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<sourceStartPosition.y)
{
continue;
}
reportBuilder.AppendLine();
reportBuilder.AppendLine($">{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<GetVaultPointFromCollider>(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<GetVaultPointFromCollider>(reportBuilder.ToString());
continue;
}
vector3 = colliderHit.point;
vector3.y = top.y;
vector3 += colliderHit.normal * 0.4f;
reportBuilder.AppendLine();
BIT4Log.Log<GetVaultPointFromCollider>(reportBuilder.ToString());
return true;
}
reportBuilder.AppendLine($"failed");
BIT4Log.Log<GetVaultPointFromCollider>(reportBuilder.ToString());
vector3 = default;
return false;
}
}
}