DarkflameServer/dPhysics/dpCollisionChecks.cpp
2021-12-05 18:54:36 +01:00

118 lines
3.7 KiB
C++

#include "dpCollisionChecks.h"
#include "dpEntity.h"
#include "dpShapeBase.h"
#include "dpShapeSphere.h"
#include "dpShapeBox.h"
#include <iostream>
#include <algorithm>
using namespace dpCollisionChecks;
bool dpCollisionChecks::AreColliding(dpEntity* a, dpEntity* b) {
auto shapeA = a->GetShape();
auto shapeB = b->GetShape();
//Sphere to sphere collision
if (shapeA->GetShapeType() == dpShapeType::Sphere && shapeB->GetShapeType() == dpShapeType::Sphere) {
return CheckSpheres(a, b);
}
return false;
}
bool dpCollisionChecks::CheckSpheres(dpEntity* a, dpEntity* b) {
if (!a || !b) return false;
auto posA = a->GetPosition();
auto distance = Vector3::DistanceSquared(posA, b->GetPosition());
auto sphereA = static_cast<dpShapeSphere*>(a->GetShape());
auto sphereB = static_cast<dpShapeSphere*>(b->GetShape());
const auto radius = sphereA->GetRadius() + sphereB->GetRadius();
if (distance <= radius * radius)
return true;
return false;
}
bool dpCollisionChecks::CheckBoxes(dpEntity* a, dpEntity* b) {
if (!a || !b) return false;
auto boxA = static_cast<dpShapeBox*>(a->GetShape());
auto boxB = static_cast<dpShapeBox*>(b->GetShape());
const auto& posA = a->GetPosition();
const auto& posB = b->GetPosition();
for (const auto& vert : boxA->GetVertices()) {
if (boxB->IsVertInBox(vert))
return true;
}
/*//Check if we're overlapping on X/Z:
if ((boxA->GetMaxWidth() >= boxB->GetMinWidth()) && //If our max width is greater than starting X of b
(boxA->GetMinWidth() <= boxB->GetMaxWidth()) && //If our start x is less than b's max width
(boxA->GetMaxDepth() >= boxB->GetMinDepth()) &&
(boxA->GetMinDepth() <= boxB->GetMaxDepth())) {
//Check if we're in the right height
if (boxA->GetTop() <= boxB->GetTop() && boxA->GetTop() >= boxB->GetBottom() || //If our top Y is within their minY/maxY bounds
boxA->GetBottom() <= boxB->GetTop() && boxA->GetBottom() >= boxB->GetBottom()) //Or our bottom Y
return true; //We definitely are colliding.
}*/
/*//Check if we're overlapping on X/Z:
if ((boxA->GetMaxWidth() >= posB.x) && //If our max width is greater than starting X of b
(posA.x <= boxB->GetMaxWidth()) && //If our start x is less than b's max width
(boxA->GetMaxDepth() >= posB.z) &&
(posA.z <= boxB->GetMaxDepth())) {
//Check if we're in the right height
if (boxA->GetTop() <= boxB->GetTop() && boxA->GetTop() >= posB.y || //If our top Y is within their minY/maxY bounds
posA.y <= boxB->GetTop() && posA.y >= posB.y) //Or our bottom Y
return true; //We definitely are colliding.
}*/
return false;
}
bool dpCollisionChecks::CheckSphereBox(dpEntity* a, dpEntity* b) {
if (!a || !b) return false;
NiPoint3 boxPos;
dpShapeBox* box;
NiPoint3 spherePos;
dpShapeSphere* sphere;
//Figure out which is the box and which is the sphere
if (a->GetShape()->GetShapeType() == dpShapeType::Box) {
box = static_cast<dpShapeBox*>(a->GetShape());
sphere = static_cast<dpShapeSphere*>(b->GetShape());
boxPos = a->GetPosition();
spherePos = b->GetPosition();
}
else {
box = static_cast<dpShapeBox*>(b->GetShape());
sphere = static_cast<dpShapeSphere*>(a->GetShape());
boxPos = b->GetPosition();
spherePos = a->GetPosition();
}
//Get closest point from the box to the sphere center by clamping
float x = std::max(box->m_MinX, std::min(spherePos.x, box->m_MaxX));
float y = std::max(box->m_MinY, std::min(spherePos.y, box->m_MaxY));
float z = std::max(box->m_MinZ, std::min(spherePos.z, box->m_MaxZ));
//Check the distance between that point & our sphere
float dX = x - spherePos.x;
float dY = y - spherePos.y;
float dZ = z - spherePos.z;
float distanceSquared = (dX * dX) + (dY * dY) + (dZ * dZ);
const float radius = sphere->GetRadius();
return distanceSquared < radius * radius;
}