move ecs related code to own folder

This commit is contained in:
2026-05-25 08:46:58 +02:00
parent 8ad7530740
commit 25ff3c56c5
54 changed files with 877 additions and 680 deletions

View 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;
});
}