BITKit/Packages/Runtime/PathProvider/LineObstacleProvider.cs

105 lines
4.1 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace BITKit
{
public class LineObstacleProvider : PathProvider
{
public LayerMask layerMask;
public int distance;
public float tolerance = 0.32f;
public int accuracy;
protected Vector3 startPos;
protected Vector3 endPos;
protected Vector3 currentPos;
public override bool IsValid(ref Vector3 startPos)
{
if (TryGetObstacle(out var raycastHit))
{
if (TryGetCrossLocation(out var location))
{
this.startPos = startPos;
endPos = location;
return true;
}
}
return false;
}
void OnDrawGizmos()
{
Gizmos.DrawWireSphere(currentPos, 0.1f);
Gizmos.DrawWireSphere(endPos, 0.1f);
}
public override Vector3 Evaluate(float time)
{
currentPos = Vector3.Lerp(startPos, endPos, time);
return currentPos;
}
public bool TryGetObstacle(out RaycastHit raycastHit)
{
var originPos = transform.position;
var endPos = originPos + distance * transform.forward;
raycastHit = default;
for (int i = 0; i < accuracy; i++)
{
var weight = i / (float)accuracy;
var tolerance = this.tolerance * Vector3.up;
var vectorUp = Vector3.Lerp(-tolerance, tolerance, weight);
if (Physics.Linecast(originPos, endPos + vectorUp, out raycastHit, layerMask))
{
Debug.DrawLine(originPos, endPos, Color.yellow, 2);
return true;
}
}
return false;
}
public bool TryGetCrossLocation(out Location location, float radius = 0.2f, float height = 1f)
{
location = default;
if (TryGetObstacle(out var raycastHit))
{
var rotation = Quaternion.LookRotation(-raycastHit.normal, Vector3.up);
var edgePoint = raycastHit.point;
for (int i = 0; i < accuracy; i++)
{
var weight = i / (float)accuracy;
var vectorUp = Vector3.Lerp(Vector3.zero, Vector3.up * 0.32f, weight);
var originPos = raycastHit.point + vectorUp - transform.forward * 0.1f;
var endPos = originPos + transform.forward;
if (Physics.Linecast(originPos, endPos, out var raycast, layerMask))
{
edgePoint = raycast.point;
Debug.DrawLine(originPos, edgePoint, Color.red, i);
}
else
{
Debug.DrawLine(originPos, endPos, Color.green, i);
edgePoint.y = originPos.y;
var startPos = edgePoint + transform.forward * radius;
if (Physics.Raycast(startPos, Vector3.down, out raycast, layerMask))
{
var point0 = raycast.point;
point0.y += radius + 0.01f;
var point1 = point0 + Vector3.up * height;
point1.y -= radius;
var colliders = Physics.OverlapCapsule(point0, point1, radius, layerMask);
if (colliders.Length is 0)
{
location = new Location()
{
position = raycast.point,
rotation = rotation
};
return true;
}
Debug.DrawLine(startPos, raycast.point, Color.cyan, 2);
}
}
}
}
return false;
}
}
}