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