cs381/as6/components/PhysicsComponent.cpp

161 lines
4.9 KiB
C++

#include "components/PhysicsComponent.hpp"
#include "Entity.hpp"
#include "components/GravityWellComponent.hpp"
#include "components/NullZoneComponent.hpp"
#include "components/StatsComponent.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::ComputeGravityDeltaVelocity(double px, double py, double dt, double &dvx,
double &dvy, bool ignoreWellActive) const {
dvx = 0.0;
dvy = 0.0;
if (!context || !context->entities) {
return false;
}
bool probeMeterDepleted = false;
if (context && entity == context->probeEntity && context->statsEntity) {
auto stats = context->statsEntity->GetComponent<StatsComponent>();
if (stats && stats->get().value <= 0.0f) {
probeMeterDepleted = true;
}
}
if (IsInsideNullZone(px)) {
return false;
}
bool applied = false;
for (auto &other : *context->entities) {
if (!other || other.get() == entity) {
continue;
}
auto wellTransform = other->GetComponent<TransformComponent>();
auto wellGravity = other->GetComponent<GravityWellComponent>();
if (!wellTransform || !wellGravity) {
continue;
}
if (probeMeterDepleted && !wellGravity->get().alwaysActive) {
continue;
}
if (!ignoreWellActive && !wellGravity->get().active) {
continue;
}
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) {
continue;
}
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;
applied = true;
}
return applied;
}
void PhysicsComponent::SimulateStep(double &xRef, double &yRef, double &vxRef, double &vyRef,
double dt, bool ignoreWellActive) const {
double dvx = 0.0;
double dvy = 0.0;
ComputeGravityDeltaVelocity(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() {}