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