feat: add component and setComponent
This commit is contained in:
1 parent
e722d2249b
commit
500fcaffd3
1 file changed
+156
@@ -0,0 +1,156 @@
|
|||||||
|
#include "vf/Collide.h"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
namespace vf {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr float gatherPadding = 1.0e-3f;
|
||||||
|
constexpr float parallelMotion = 1.0e-12f;
|
||||||
|
|
||||||
|
float component(const Vec3& v, int a) { return (&v.x)[a]; }
|
||||||
|
void setComponent(Vec3& v, int a, float value) { (&v.x)[a] = value; }
|
||||||
|
|
||||||
|
int axisIndex(ContactAxis axis) {
|
||||||
|
switch (axis) {
|
||||||
|
case ContactAxis::X: return 0;
|
||||||
|
case ContactAxis::Y: return 1;
|
||||||
|
case ContactAxis::Z: return 2;
|
||||||
|
default: return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ContactAxis axisFromIndex(int a) {
|
||||||
|
switch (a) {
|
||||||
|
case 0: return ContactAxis::X;
|
||||||
|
case 1: return ContactAxis::Y;
|
||||||
|
default: return ContactAxis::Z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int floorToCell(float value) { return static_cast<int>(std::floor(value)); }
|
||||||
|
|
||||||
|
bool motionIsIdle(const Vec3& motion) {
|
||||||
|
return std::fabs(motion.x) < parallelMotion && std::fabs(motion.y) < parallelMotion &&
|
||||||
|
std::fabs(motion.z) < parallelMotion;
|
||||||
|
}
|
||||||
|
|
||||||
|
SweptBox unitCellBox(const Vec3i& cell, float loY, float hiY, float inset) {
|
||||||
|
float x = static_cast<float>(cell.x);
|
||||||
|
float y = static_cast<float>(cell.y);
|
||||||
|
float z = static_cast<float>(cell.z);
|
||||||
|
return SweptBox{{x + inset, y + loY, z + inset}, {x + 1.0f - inset, y + hiY, z + 1.0f - inset}};
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
SweptBox makeBoxAtFeet(const Vec3& feetCentre, float width, float height) {
|
||||||
|
float half = width * 0.5f;
|
||||||
|
return SweptBox{{feetCentre.x - half, feetCentre.y, feetCentre.z - half},
|
||||||
|
{feetCentre.x + half, feetCentre.y + height, feetCentre.z + half}};
|
||||||
|
}
|
||||||
|
|
||||||
|
SweptBox translatedBox(const SweptBox& box, const Vec3& delta) {
|
||||||
|
return SweptBox{box.min + delta, box.max + delta};
|
||||||
|
}
|
||||||
|
|
||||||
|
SweptBox inflatedBox(const SweptBox& box, float amount) {
|
||||||
|
Vec3 pad{amount, amount, amount};
|
||||||
|
return SweptBox{box.min - pad, box.max + pad};
|
||||||
|
}
|
||||||
|
|
||||||
|
SweptBox motionEnvelope(const SweptBox& box, const Vec3& motion) {
|
||||||
|
SweptBox moved = translatedBox(box, motion);
|
||||||
|
SweptBox out;
|
||||||
|
for (int a = 0; a < 3; ++a) {
|
||||||
|
setComponent(out.min, a, std::fmin(component(box.min, a), component(moved.min, a)));
|
||||||
|
setComponent(out.max, a, std::fmax(component(box.max, a), component(moved.max, a)));
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool boxesOverlap(const SweptBox& a, const SweptBox& b) {
|
||||||
|
return a.min.x < b.max.x && a.max.x > b.min.x && a.min.y < b.max.y && a.max.y > b.min.y &&
|
||||||
|
a.min.z < b.max.z && a.max.z > b.min.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool boxesTouchOrOverlap(const SweptBox& a, const SweptBox& b, float tolerance) {
|
||||||
|
return boxesOverlap(inflatedBox(a, tolerance), b);
|
||||||
|
}
|
||||||
|
|
||||||
|
SweptBox aabbToSweptBox(const Aabb& box) { return SweptBox{box.min, box.max}; }
|
||||||
|
|
||||||
|
Aabb sweptBoxToAabb(const SweptBox& box) { return Aabb{box.min, box.max}; }
|
||||||
|
|
||||||
|
CollisionShape collisionShapeOf(Block block) {
|
||||||
|
switch (block) {
|
||||||
|
case Block::Slab: return CollisionShape::SlabBottom;
|
||||||
|
case Block::Stairs: return CollisionShape::Stairs;
|
||||||
|
case Block::Fence: return CollisionShape::Fence;
|
||||||
|
case Block::Ladder: return CollisionShape::Ladder;
|
||||||
|
case Block::Vine: return CollisionShape::Vine;
|
||||||
|
case Block::SnowLayer: return CollisionShape::Carpet;
|
||||||
|
default: return isSolid(block) ? CollisionShape::Full : CollisionShape::None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isClimbableShape(CollisionShape shape) {
|
||||||
|
return shape == CollisionShape::Ladder || shape == CollisionShape::Vine;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool shapeBlocksMovement(CollisionShape shape) {
|
||||||
|
switch (shape) {
|
||||||
|
case CollisionShape::None:
|
||||||
|
case CollisionShape::Ladder:
|
||||||
|
case CollisionShape::Vine:
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ShapeBoxes shapeBoxesAt(CollisionShape shape, const Vec3i& cell) {
|
||||||
|
ShapeBoxes out;
|
||||||
|
switch (shape) {
|
||||||
|
case CollisionShape::Full:
|
||||||
|
out.boxes[out.count++] = unitCellBox(cell, 0.0f, 1.0f, 0.0f);
|
||||||
|
break;
|
||||||
|
case CollisionShape::SlabBottom:
|
||||||
|
out.boxes[out.count++] = unitCellBox(cell, 0.0f, 0.5f, 0.0f);
|
||||||
|
break;
|
||||||
|
case CollisionShape::SlabTop:
|
||||||
|
out.boxes[out.count++] = unitCellBox(cell, 0.5f, 1.0f, 0.0f);
|
||||||
|
break;
|
||||||
|
case CollisionShape::Stairs:
|
||||||
|
// Lower slab plus the upper step over the +X half of the cell.
|
||||||
|
out.boxes[out.count++] = unitCellBox(cell, 0.0f, 0.5f, 0.0f);
|
||||||
|
{
|
||||||
|
SweptBox upper = unitCellBox(cell, 0.5f, 1.0f, 0.0f);
|
||||||
|
upper.min.x = static_cast<float>(cell.x) + 0.5f;
|
||||||
|
out.boxes[out.count++] = upper;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CollisionShape::Fence:
|
||||||
|
// The post reaches above its own cell, which is why a body cannot
|
||||||
|
// hop a fence the way it hops a full block.
|
||||||
|
out.boxes[out.count++] = unitCellBox(cell, 0.0f, fencePostHeight, 0.375f);
|
||||||
|
break;
|
||||||
|
case CollisionShape::Carpet:
|
||||||
|
out.boxes[out.count++] = unitCellBox(cell, 0.0f, carpetHeight, 0.0f);
|
||||||
|
break;
|
||||||
|
case CollisionShape::None:
|
||||||
|
case CollisionShape::Ladder:
|
||||||
|
case CollisionShape::Vine:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
SweepHit sweepBoxAgainstBox(const SweptBox& mover, const Vec3& motion, const SweptBox& obstacle) {
|
||||||
|
SweepHit hit;
|
||||||
|
Vec3 moverSize = mover.size();
|
||||||
|
SweptBox expanded{obstacle.min - moverSize, obstacle.max};
|
||||||
|
Vec3 point = mover.min;
|
||||||
|
|
||||||
Reference in new issue
Block a user