83 lines
2.6 KiB
C#
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;
|
|
}
|
|
} |