147 lines
4.5 KiB
C++
147 lines
4.5 KiB
C++
#include "components/PhysicsComponent.hpp"
|
|
|
|
#include "Entity.hpp"
|
|
#include "components/GravityWellComponent.hpp"
|
|
#include "components/MeterComponent.hpp"
|
|
#include "components/NullZoneComponent.hpp"
|
|
#include "components/TransformComponent.hpp"
|
|
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
|
|
void PhysicsComponent::Setup() {}
|
|
|
|
void PhysicsComponent::ClampVelocity(float &vxRef, float &vyRef) const {
|
|
const float speed = std::sqrt(vxRef * vxRef + vyRef * vyRef);
|
|
if (speed > speedCap && speed > 0.0f) {
|
|
const float scale = speedCap / speed;
|
|
vxRef *= scale;
|
|
vyRef *= scale;
|
|
}
|
|
}
|
|
|
|
void PhysicsComponent::ClampVelocity(double &vxRef, double &vyRef) const {
|
|
const double speed = std::sqrt(vxRef * vxRef + vyRef * vyRef);
|
|
if (speed > static_cast<double>(speedCap) && speed > 0.0) {
|
|
const double scale = static_cast<double>(speedCap) / speed;
|
|
vxRef *= scale;
|
|
vyRef *= scale;
|
|
}
|
|
}
|
|
|
|
void PhysicsComponent::IntegratePosition(float &xRef, float &yRef, float vxValue, float vyValue,
|
|
float dt) {
|
|
xRef += vxValue * dt;
|
|
yRef += vyValue * dt;
|
|
}
|
|
|
|
void PhysicsComponent::IntegratePosition(double &xRef, double &yRef, double vxValue, double vyValue,
|
|
double dt) {
|
|
xRef += vxValue * dt;
|
|
yRef += vyValue * dt;
|
|
}
|
|
|
|
bool PhysicsComponent::IsInsideNullZone(double xPos) const {
|
|
if (!context || !context->entities) {
|
|
return false;
|
|
}
|
|
|
|
for (auto &other : *context->entities) {
|
|
if (!other || other.get() == entity) {
|
|
continue;
|
|
}
|
|
|
|
auto zone = other->GetComponent<NullZoneComponent>();
|
|
auto zoneTransform = other->GetComponent<TransformComponent>();
|
|
if (!zone || !zoneTransform) {
|
|
continue;
|
|
}
|
|
|
|
const double left = static_cast<double>(zoneTransform->get().x);
|
|
const double right = left + static_cast<double>(zone->get().width);
|
|
if (xPos >= left && xPos <= right) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool PhysicsComponent::ComputeWellDeltaVelocity(double px, double py, double dt, double &dvx,
|
|
double &dvy, bool ignoreWellActive) const {
|
|
dvx = 0.0;
|
|
dvy = 0.0;
|
|
|
|
if (!context || !context->wellEntity) {
|
|
return false;
|
|
}
|
|
|
|
auto wellTransform = context->wellEntity->GetComponent<TransformComponent>();
|
|
auto wellGravity = context->wellEntity->GetComponent<GravityWellComponent>();
|
|
if (!wellTransform || !wellGravity) {
|
|
return false;
|
|
}
|
|
|
|
if (!ignoreWellActive && !wellGravity->get().active) {
|
|
return false;
|
|
}
|
|
|
|
// Probe cannot receive well acceleration when meter is depleted.
|
|
if (context && entity == context->probeEntity && context->hudEntity) {
|
|
auto meter = context->hudEntity->GetComponent<MeterComponent>();
|
|
if (meter && meter->get().value <= 0.0f) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (IsInsideNullZone(px)) {
|
|
return false;
|
|
}
|
|
|
|
const double dx = static_cast<double>(wellTransform->get().x) - px;
|
|
const double dy = static_cast<double>(wellTransform->get().y) - py;
|
|
const double dist = std::sqrt(dx * dx + dy * dy);
|
|
if (dist <= 0.0001) {
|
|
return false;
|
|
}
|
|
|
|
const double clampedDist = std::max(dist, static_cast<double>(wellGravity->get().minDist));
|
|
const double force = static_cast<double>(wellGravity->get().mass) / (clampedDist * clampedDist);
|
|
dvx = (dx / dist) * force * dt;
|
|
dvy = (dy / dist) * force * dt;
|
|
return true;
|
|
}
|
|
|
|
void PhysicsComponent::SimulateStep(double &xRef, double &yRef, double &vxRef, double &vyRef,
|
|
double dt, bool ignoreWellActive) const {
|
|
double dvx = 0.0;
|
|
double dvy = 0.0;
|
|
ComputeWellDeltaVelocity(xRef, yRef, dt, dvx, dvy, ignoreWellActive);
|
|
vxRef += dvx;
|
|
vyRef += dvy;
|
|
|
|
ClampVelocity(vxRef, vyRef);
|
|
IntegratePosition(xRef, yRef, vxRef, vyRef, dt);
|
|
}
|
|
|
|
void PhysicsComponent::Update(float dt) {
|
|
auto transform = entity->GetComponent<TransformComponent>();
|
|
if (!transform) {
|
|
return;
|
|
}
|
|
|
|
double x = static_cast<double>(transform->get().x);
|
|
double y = static_cast<double>(transform->get().y);
|
|
double vxLocal = static_cast<double>(vx);
|
|
double vyLocal = static_cast<double>(vy);
|
|
|
|
SimulateStep(x, y, vxLocal, vyLocal, static_cast<double>(dt), false);
|
|
|
|
transform->get().x = static_cast<float>(x);
|
|
transform->get().y = static_cast<float>(y);
|
|
vx = static_cast<float>(vxLocal);
|
|
vy = static_cast<float>(vyLocal);
|
|
}
|
|
|
|
void PhysicsComponent::Cleanup() {}
|