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; } } }