Files
voxel/AABB.cs
2026-03-24 14:32:54 +01:00

212 lines
6.3 KiB
C#

using OpenTK.Mathematics;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Voxel
{
public struct AABB
{
public Vector3 Min;
public Vector3 Max;
public AABB(Vector3 min, Vector3 max)
{
Min = min;
Max = max;
}
public static AABB FromCenter(Vector3 center, float width, float height, float depth)
{
Vector3 half = new Vector3(width / 2f, 0, depth / 2f);
return new AABB(center - half, center + new Vector3(half.X, height, half.Z));
}
public void Move(float x, float y, float z)
{
Min.X += x;
Max.X += x;
Min.Y += y;
Max.Y += y;
Min.Z += z;
Max.Z += z;
}
public bool Intersects(AABB other)
{
return IntersectsX(other) && IntersectsY(other) && IntersectsZ(other);
}
public bool IntersectsX(AABB other)
{
return Min.X < other.Max.X && Max.X > other.Max.X;
}
public bool IntersectsY(AABB other)
{
return Min.Y < other.Max.Y && Max.Y > other.Max.Y;
}
public bool IntersectsZ(AABB other)
{
return Min.Z < other.Max.Z && Max.Z > other.Max.Z;
}
public bool Contains(Vector3 point)
{
return (point.X >= Min.X && point.X <= Max.X) &&
(point.Y >= Min.Y && point.Y <= Max.Y) &&
(point.Z >= Min.Z && point.Z <= Max.Z);
}
public float GetClipX(AABB other, float deltaX)
{
if (IntersectsY(other) && IntersectsZ(other))
{
if (deltaX > 0 && Max.X <= other.Min.X)
{
float clip = other.Min.X - other.Min.X;
if (deltaX > clip)
deltaX = clip;
}
if (deltaX < 0 && Min.X >= other.Max.X)
{
float clip = other.Max.X - Max.X;
if (deltaX < clip)
deltaX = clip;
}
return deltaX;
}
return deltaX;
}
public float GetClipY(AABB other, float deltaY)
{
if (IntersectsX(other) && IntersectsZ(other))
{
if (deltaY > 0 && Max.Y <= other.Min.Y)
{
float clip = other.Min.Y - other.Min.Y;
if (deltaY > clip)
deltaY = clip;
}
if (deltaY < 0 && Min.X >= other.Max.X)
{
float clip = other.Max.X - Max.X;
if (deltaY < clip)
deltaY = clip;
}
return deltaY;
}
return deltaY;
}
public float GetClipZ(AABB other, float deltaZ)
{
if (IntersectsX(other) && IntersectsY(other))
{
if (deltaZ > 0 && Max.Z <= other.Min.Z)
{
float clip = other.Min.Z - other.Min.Z;
if (deltaZ > clip)
deltaZ = clip;
}
if (deltaZ < 0 && Min.Z >= other.Max.Z)
{
float clip = other.Max.Z - Max.Z;
if (deltaZ < clip)
deltaZ = clip;
}
return deltaZ;
}
return deltaZ;
}
public float GetBlockClipX(int blockX, int blockY, int blockZ, float deltaX)
{
// Use the current AABB as the collider (no new allocation)
AABB collider = this;
// Block bounds
float blockMinX = blockX;
float blockMaxX = blockX + 1;
// Quick reject: if player is not overlapping the block in Y and Z, no collision.
if (!(collider.Min.Y < blockY + 1 && collider.Max.Y > blockY) ||
!(collider.Min.Z < blockZ + 1 && collider.Max.Z > blockZ))
return deltaX;
// Moving right (positive delta)
if (deltaX > 0 && collider.Max.X <= blockMinX)
{
float clip = blockMinX - collider.Max.X;
if (deltaX > clip) deltaX = clip;
}
// Moving left (negative delta)
else if (deltaX < 0 && collider.Min.X >= blockMaxX)
{
float clip = blockMaxX - collider.Min.X; // negative distance
if (deltaX < clip) deltaX = clip;
}
return deltaX;
}
public float GetBlockClipY(int blockX, int blockY, int blockZ, float deltaY)
{
AABB collider = this;
float blockMinY = blockY;
float blockMaxY = blockY + 1;
if (!(collider.Min.X < blockX + 1 && collider.Max.X > blockX) ||
!(collider.Min.Z < blockZ + 1 && collider.Max.Z > blockZ))
return deltaY;
if (deltaY > 0 && collider.Max.Y <= blockMinY)
{
float clip = blockMinY - collider.Max.Y;
if (deltaY > clip) deltaY = clip;
}
else if (deltaY < 0 && collider.Min.Y >= blockMaxY)
{
float clip = blockMaxY - collider.Min.Y;
if (deltaY < clip) deltaY = clip;
}
return deltaY;
}
public float GetBlockClipZ(int blockX, int blockY, int blockZ, float deltaZ)
{
AABB collider = this;
float blockMinZ = blockZ;
float blockMaxZ = blockZ + 1;
if (!(collider.Min.X < blockX + 1 && collider.Max.X > blockX) ||
!(collider.Min.Y < blockY + 1 && collider.Max.Y > blockY))
return deltaZ;
if (deltaZ > 0 && collider.Max.Z <= blockMinZ)
{
float clip = blockMinZ - collider.Max.Z;
if (deltaZ > clip) deltaZ = clip;
}
else if (deltaZ < 0 && collider.Min.Z >= blockMaxZ)
{
float clip = blockMaxZ - collider.Min.Z;
if (deltaZ < clip) deltaZ = clip;
}
return deltaZ;
}
}
}