fix tests

This commit is contained in:
2026-05-25 21:00:15 +02:00
parent 25ff3c56c5
commit 9e36c13635
3 changed files with 28 additions and 8 deletions

View File

@@ -2,8 +2,10 @@
#include "EntityAdmin.h" #include "EntityAdmin.h"
#include "FactionComponent.h" #include "FactionComponent.h"
#include "StationBodyComponent.h"
#include "HealthComponent.h" #include "HealthComponent.h"
#include "PositionComponent.h" #include "PositionComponent.h"
#include "SensorRangeComponent.h"
#include "ShipIdentityComponent.h" #include "ShipIdentityComponent.h"
#include "ThreatResponseBehaviorComponent.h" #include "ThreatResponseBehaviorComponent.h"
#include "WeaponComponent.h" #include "WeaponComponent.h"
@@ -31,10 +33,11 @@ void CombatSystem::tick(Tick currentTick,
resolveWeapon(e, weapon, pos, faction, currentTick, admin, outFireEvents); resolveWeapon(e, weapon, pos, faction, currentTick, admin, outFireEvents);
}); });
// Station weapons. // Station weapons (entities with StationBodyComponent; ships are excluded because
admin.forEach<WeaponComponent, PositionComponent, FactionComponent>( // they lack that component and are already handled by the ship loop above).
admin.forEach<WeaponComponent, PositionComponent, FactionComponent, StationBodyComponent>(
[&](entt::entity e, WeaponComponent& weapon, PositionComponent& pos, [&](entt::entity e, WeaponComponent& weapon, PositionComponent& pos,
FactionComponent& faction) FactionComponent& faction, const StationBodyComponent& /*sb*/)
{ {
resolveWeapon(e, weapon, pos, faction, currentTick, admin, outFireEvents); resolveWeapon(e, weapon, pos, faction, currentTick, admin, outFireEvents);
}); });
@@ -77,10 +80,14 @@ void CombatSystem::resolveWeapon(
} }
} }
// Acquire a new target if needed (nearest opposing-faction ship). // Acquire a new target if needed.
// Ships use their sensor range; stations fall back to weapon range.
if (!weapon.currentTarget) if (!weapon.currentTarget)
{ {
float bestDistanceSquared = weapon.range * weapon.range; const float acquisitionRange = admin.hasAll<SensorRangeComponent>(shipEntity)
? admin.get<SensorRangeComponent>(shipEntity).value
: weapon.range;
float bestDistanceSquared = acquisitionRange * acquisitionRange;
admin.forEach<ShipIdentityComponent, PositionComponent, FactionComponent>( admin.forEach<ShipIdentityComponent, PositionComponent, FactionComponent>(
[&](entt::entity candidate, const ShipIdentityComponent& /*si*/, [&](entt::entity candidate, const ShipIdentityComponent& /*si*/,
const PositionComponent& candidatePos, const PositionComponent& candidatePos,

View File

@@ -91,9 +91,11 @@ void MovementIntentSystem::tick(EntityAdmin& admin)
const float manAccel = body.maneuveringAccelerationPerTick; const float manAccel = body.maneuveringAccelerationPerTick;
const float stoppingDist = (body.maxSpeedPerTick * body.maxSpeedPerTick) const float stoppingDist = (body.maxSpeedPerTick * body.maxSpeedPerTick)
/ (2.0f * manAccel); / (2.0f * manAccel);
const float desiredSpeed = (dist <= stoppingDist) // Cap to dist so the ship never overshoots the target in a single tick.
const float baseDesiredSpeed = (dist <= stoppingDist)
? std::sqrt(2.0f * manAccel * dist) ? std::sqrt(2.0f * manAccel * dist)
: body.maxSpeedPerTick; : body.maxSpeedPerTick;
const float desiredSpeed = std::min(dist, baseDesiredSpeed);
const QVector2D desiredVel = delta.normalized() * desiredSpeed; const QVector2D desiredVel = delta.normalized() * desiredSpeed;
const QVector2D velError = desiredVel - body.velocity; const QVector2D velError = desiredVel - body.velocity;

View File

@@ -115,13 +115,24 @@ TEST_CASE("CombatSystem: cooldown prevents firing before it expires", "[combat]"
f.wireEnemyTarget(enemy, player); f.wireEnemyTarget(enemy, player);
f.admin.get<WeaponComponent>(enemy).cooldownTicks = 3.0f; // override to 3 f.admin.get<WeaponComponent>(enemy).cooldownTicks = 3.0f; // override to 3
auto enemyFiredIn = [&enemy](const std::vector<FireEvent>& evts)
{
for (const FireEvent& evt : evts)
{
if (evt.shooter == enemy) { return true; }
}
return false;
};
std::vector<FireEvent> events; std::vector<FireEvent> events;
f.combat.tick(0, f.admin, f.buildings, events); f.combat.tick(0, f.admin, f.buildings, events);
REQUIRE_FALSE(enemyFiredIn(events));
f.combat.tick(1, f.admin, f.buildings, events); f.combat.tick(1, f.admin, f.buildings, events);
REQUIRE(events.empty()); REQUIRE_FALSE(enemyFiredIn(events));
f.combat.tick(2, f.admin, f.buildings, events); f.combat.tick(2, f.admin, f.buildings, events);
REQUIRE(events.size() == 1); REQUIRE(enemyFiredIn(events));
} }
TEST_CASE("CombatSystem: no fire when target is out of range", "[combat]") TEST_CASE("CombatSystem: no fire when target is out of range", "[combat]")