move ecs related code to own folder
This commit is contained in:
115
src/lib/ecs/system/MovementIntentSystem.cpp
Normal file
115
src/lib/ecs/system/MovementIntentSystem.cpp
Normal file
@@ -0,0 +1,115 @@
|
||||
#include "MovementIntentSystem.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
#include <QVector2D>
|
||||
|
||||
#include "DynamicBodyComponent.h"
|
||||
#include "EntityAdmin.h"
|
||||
#include "FacingComponent.h"
|
||||
#include "MovementIntentComponent.h"
|
||||
#include "PositionComponent.h"
|
||||
|
||||
static float wrapAngle(float a)
|
||||
{
|
||||
constexpr float kPi = 3.14159265f;
|
||||
a = std::fmod(a, 2.0f * kPi);
|
||||
if (a > kPi) { a -= 2.0f * kPi; }
|
||||
if (a < -kPi) { a += 2.0f * kPi; }
|
||||
return a;
|
||||
}
|
||||
|
||||
void MovementIntentSystem::tick(EntityAdmin& admin)
|
||||
{
|
||||
admin.forEach<PositionComponent, FacingComponent, DynamicBodyComponent,
|
||||
MovementIntentComponent>(
|
||||
[](entt::entity /*e*/, const PositionComponent& pos, const FacingComponent& facing,
|
||||
DynamicBodyComponent& body, const MovementIntentComponent& intent)
|
||||
{
|
||||
if (intent.priority == 0)
|
||||
{
|
||||
// No movement intent: brake using available thrust.
|
||||
const float linearBraking = std::min(body.velocity.length(),
|
||||
body.maneuveringAccelerationPerTick);
|
||||
body.linearAcceleration = (body.velocity.length() > 0.0001f)
|
||||
? -body.velocity.normalized() * linearBraking
|
||||
: QVector2D(0.0f, 0.0f);
|
||||
|
||||
const float angBraking = std::min(std::abs(body.angularVelocity),
|
||||
body.angularAccelerationPerTick);
|
||||
body.angularAcceleration =
|
||||
(body.angularVelocity >= 0.0f) ? -angBraking : angBraking;
|
||||
return;
|
||||
}
|
||||
|
||||
const QVector2D delta = intent.target - pos.value;
|
||||
const float dist = delta.length();
|
||||
|
||||
if (dist < 0.001f)
|
||||
{
|
||||
// Already at target: no new thrust. The ship drifts; it will
|
||||
// re-approach next tick once it has moved away.
|
||||
body.linearAcceleration = QVector2D(0.0f, 0.0f);
|
||||
body.angularAcceleration = 0.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
// --- Angular acceleration ---
|
||||
|
||||
const float desiredAngle = std::atan2(delta.y(), delta.x());
|
||||
const float angleDiff = wrapAngle(desiredAngle - facing.radians);
|
||||
|
||||
const float rotDelta = std::max(-body.angularAccelerationPerTick,
|
||||
std::min(angleDiff,
|
||||
body.angularAccelerationPerTick));
|
||||
|
||||
float newAngVel = body.angularVelocity + rotDelta;
|
||||
|
||||
// Overshoot prevention: if the accumulated angular velocity already
|
||||
// exceeds the remaining angle, snap it to exactly that angle so the
|
||||
// ship doesn't rotate past its heading.
|
||||
const bool sameSign = (newAngVel >= 0.0f) == (angleDiff >= 0.0f);
|
||||
if (sameSign && std::abs(newAngVel) > std::abs(angleDiff))
|
||||
{
|
||||
newAngVel = angleDiff;
|
||||
}
|
||||
|
||||
body.angularAcceleration = newAngVel - body.angularVelocity;
|
||||
// DynamicBodySystem applies the clamp to maxRotationSpeedPerTick after
|
||||
// integrating, so we do not clamp here.
|
||||
|
||||
// --- Linear acceleration ---
|
||||
// Use the projected facing (after this tick's angular integration) so
|
||||
// that the main thruster aligns with where the ship will actually be
|
||||
// pointing when DynamicBodySystem applies the forces.
|
||||
|
||||
const float projectedRadians = wrapAngle(facing.radians + newAngVel);
|
||||
const QVector2D facingVec(std::cos(projectedRadians),
|
||||
std::sin(projectedRadians));
|
||||
|
||||
const float manAccel = body.maneuveringAccelerationPerTick;
|
||||
const float stoppingDist = (body.maxSpeedPerTick * body.maxSpeedPerTick)
|
||||
/ (2.0f * manAccel);
|
||||
const float desiredSpeed = (dist <= stoppingDist)
|
||||
? std::sqrt(2.0f * manAccel * dist)
|
||||
: body.maxSpeedPerTick;
|
||||
|
||||
const QVector2D desiredVel = delta.normalized() * desiredSpeed;
|
||||
const QVector2D velError = desiredVel - body.velocity;
|
||||
|
||||
const float mainAligned = std::max(0.0f,
|
||||
QVector2D::dotProduct(velError, facingVec));
|
||||
const float mainApplied = std::min(mainAligned,
|
||||
body.mainAccelerationPerTick);
|
||||
const QVector2D mainDelta = facingVec * mainApplied;
|
||||
|
||||
const QVector2D remaining = velError - mainDelta;
|
||||
const float remainLen = remaining.length();
|
||||
const QVector2D maneuverDelta = (remainLen > manAccel)
|
||||
? remaining.normalized() * manAccel
|
||||
: remaining;
|
||||
|
||||
body.linearAcceleration = mainDelta + maneuverDelta;
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user