Files
Fishing2/Assets/ECM2/Source/Utils/CollisionDetection.cs
2025-05-16 23:31:59 +08:00

171 lines
5.6 KiB
C#

using System;
using UnityEngine;
namespace ECM2
{
/// <summary>
/// General purpose collision detection functions.
/// Lets you filter results implementing the IColliderFilter interface.
/// </summary>
public static class CollisionDetection
{
#region CONSTANTS
private const int kMaxHits = 8;
#endregion
#region FIELDS
private static readonly RaycastHit[] HitsBuffer = new RaycastHit[kMaxHits];
#endregion
#region METHODS
public static int Raycast(Vector3 origin, Vector3 direction, float distance, int layerMask,
QueryTriggerInteraction queryTriggerInteraction, out RaycastHit closestHit, RaycastHit[] hits,
IColliderFilter colliderFilter)
{
closestHit = default;
int rawHitCount = Physics.RaycastNonAlloc(origin, direction, HitsBuffer, distance, layerMask,
queryTriggerInteraction);
if (rawHitCount == 0)
return 0;
int filteredHitCount = 0;
float closestDistance = Mathf.Infinity;
Array.Clear(hits, 0, hits.Length);
for (int i = 0; i < rawHitCount; i++)
{
if (HitsBuffer[i].distance <= 0.0f ||
colliderFilter != null && colliderFilter.Filter(HitsBuffer[i].collider))
continue;
if (HitsBuffer[i].distance < closestDistance)
{
closestHit = HitsBuffer[i];
closestDistance = closestHit.distance;
}
hits[filteredHitCount++] = HitsBuffer[i];
}
return filteredHitCount;
}
public static int SphereCast(Vector3 origin, float radius, Vector3 direction, float distance, int layerMask,
QueryTriggerInteraction queryTriggerInteraction, out RaycastHit closestHit, RaycastHit[] hits,
IColliderFilter colliderFilter, float backStepDistance)
{
closestHit = default;
Vector3 optOrigin = origin - direction * backStepDistance;
float optDistance = distance + backStepDistance;
int rawHitCount = Physics.SphereCastNonAlloc(optOrigin, radius, direction, HitsBuffer, optDistance,
layerMask, queryTriggerInteraction);
if (rawHitCount == 0)
return 0;
int filteredHitCount = 0;
float closestDistance = Mathf.Infinity;
Array.Clear(hits, 0, hits.Length);
for (int i = 0; i < rawHitCount; i++)
{
if (HitsBuffer[i].distance <= 0.0f ||
colliderFilter != null && colliderFilter.Filter(HitsBuffer[i].collider))
continue;
HitsBuffer[i].distance -= backStepDistance;
if (HitsBuffer[i].distance < closestDistance)
{
closestHit = HitsBuffer[i];
closestDistance = closestHit.distance;
}
hits[filteredHitCount++] = HitsBuffer[i];
}
return filteredHitCount;
}
public static int CapsuleCast(Vector3 point1, Vector3 point2, float radius, Vector3 direction, float distance,
int layerMask, QueryTriggerInteraction queryTriggerInteraction, out RaycastHit closestHit,
RaycastHit[] hits, IColliderFilter colliderFilter, float backStepDistance)
{
closestHit = default;
Vector3 optPoint1 = point1 - direction * backStepDistance;
Vector3 optPoint2 = point2 - direction * backStepDistance;
float optDistance = distance + backStepDistance;
int rawHitCount = Physics.CapsuleCastNonAlloc(optPoint1, optPoint2, radius, direction, HitsBuffer,
optDistance, layerMask, queryTriggerInteraction);
if (rawHitCount == 0)
return 0;
int filteredHitCount = 0;
float closestDistance = Mathf.Infinity;
Array.Clear(hits, 0, hits.Length);
for (int i = 0; i < rawHitCount; i++)
{
if (HitsBuffer[i].distance <= 0.0f ||
colliderFilter != null && colliderFilter.Filter(HitsBuffer[i].collider))
continue;
HitsBuffer[i].distance -= backStepDistance;
if (HitsBuffer[i].distance < closestDistance)
{
closestHit = HitsBuffer[i];
closestDistance = closestHit.distance;
}
hits[filteredHitCount++] = HitsBuffer[i];
}
return filteredHitCount;
}
public static int OverlapCapsule(Vector3 point1, Vector3 point2, float radius, int layerMask,
QueryTriggerInteraction queryTriggerInteraction, Collider[] results, IColliderFilter colliderFilter)
{
int rawOverlapCount =
Physics.OverlapCapsuleNonAlloc(point1, point2, radius, results, layerMask, queryTriggerInteraction);
if (rawOverlapCount == 0)
return 0;
int filteredOverlapCount = rawOverlapCount;
for (int i = 0; i < rawOverlapCount; i++)
{
Collider overlappedCollider = results[i];
if (colliderFilter != null && !colliderFilter.Filter(overlappedCollider))
continue;
if (i < --filteredOverlapCount)
results[i] = results[filteredOverlapCount];
}
return filteredOverlapCount;
}
#endregion
}
}