Files
doom-dm/DoomDeathmatch/src/Script/Collision/AABBCollider.cs
2025-01-07 20:29:20 +03:00

83 lines
2.6 KiB
C#

using OpenTK.Mathematics;
namespace DoomDeathmatch.Script.Collision;
/// <summary>
/// Represents an Axis-Aligned Bounding Box (AABB) collider for 3D collision detection.
/// </summary>
public class AABBCollider
{
/// <summary>
/// The position of the collider's center in 3D space.
/// </summary>
public Vector3 Position { get; set; }
/// <summary>
/// The size (width, height, depth) of the collider.
/// </summary>
public Vector3 Size { get; set; }
/// <summary>
/// The minimum point (corner) of the collider in 3D space.
/// </summary>
public Vector3 Min => Position - (Size / 2);
/// <summary>
/// The maximum point (corner) of the collider in 3D space.
/// </summary>
public Vector3 Max => Position + (Size / 2);
/// <summary>
/// Checks if this collider intersects with another AABB collider.
/// </summary>
/// <param name="parCollider">The other collider to check for intersection.</param>
/// <returns><see langword="true"/> if the colliders intersect; otherwise, <see langword="false"/>.</returns>
public bool Intersects(AABBCollider parCollider)
{
var max = Max;
var min = Min;
var otherMax = parCollider.Max;
var otherMin = parCollider.Min;
return max.X >= otherMin.X && min.X <= otherMax.X && max.Y >= otherMin.Y && min.Y <= otherMax.Y &&
max.Z >= otherMin.Z && min.Z <= otherMax.Z;
}
/// <summary>
/// Calculates the collision normal between this collider and another collider.
/// </summary>
/// <param name="parOther">The other collider involved in the collision.</param>
/// <returns>
/// A <see cref="Vector3"/> representing the normal of the collision surface.
/// This indicates the direction of the collision resolution.
/// </returns>
public Vector3 GetCollisionNormal(AABBCollider parOther)
{
var normal = Vector3.Zero;
var diff = parOther.Position - Position;
// Calculate penetration depths for each axis
var penX = (Size.X / 2) + (parOther.Size.X / 2) - Math.Abs(diff.X);
var penY = (Size.Y / 2) + (parOther.Size.Y / 2) - Math.Abs(diff.Y);
var penZ = (Size.Z / 2) + (parOther.Size.Z / 2) - Math.Abs(diff.Z);
// Use the axis with the smallest penetration
if (penX < penY && penX < penZ)
{
var sign = Math.Sign(diff.X);
normal.X = sign == 0 ? 1 : sign;
}
else if (penY < penX && penY < penZ)
{
var sign = Math.Sign(diff.Y);
normal.Y = sign == 0 ? 1 : sign;
}
else if (penZ < penX && penZ < penY)
{
var sign = Math.Sign(diff.Z);
normal.Z = sign == 0 ? 1 : sign;
}
return normal;
}
}