split off MovementSystem and AiSystem from ShipSystem
This commit is contained in:
@@ -4,11 +4,13 @@
|
||||
|
||||
#include <QVector2D>
|
||||
|
||||
#include "AiSystem.h"
|
||||
#include "BeltSystem.h"
|
||||
#include "Building.h"
|
||||
#include "BuildingSystem.h"
|
||||
#include "BuildingType.h"
|
||||
#include "ConfigLoader.h"
|
||||
#include "MovementSystem.h"
|
||||
#include "Rotation.h"
|
||||
#include "Scrap.h"
|
||||
#include "ScrapSystem.h"
|
||||
@@ -27,15 +29,17 @@ static GameConfig loadConfig()
|
||||
|
||||
struct Fixture
|
||||
{
|
||||
GameConfig cfg;
|
||||
BeltSystem belts;
|
||||
EntityId nextId;
|
||||
int stock;
|
||||
std::mt19937 rng;
|
||||
GameConfig cfg;
|
||||
BeltSystem belts;
|
||||
EntityId nextId;
|
||||
int stock;
|
||||
std::mt19937 rng;
|
||||
BuildingSystem buildings;
|
||||
ShipSystem ships;
|
||||
ScrapSystem scraps;
|
||||
Tick tick;
|
||||
ShipSystem ships;
|
||||
AiSystem ai;
|
||||
MovementSystem movement;
|
||||
ScrapSystem scraps;
|
||||
Tick tick;
|
||||
|
||||
explicit Fixture()
|
||||
: cfg(loadConfig())
|
||||
@@ -58,11 +62,11 @@ struct Fixture
|
||||
void runBehaviorTick()
|
||||
{
|
||||
ships.clearMovementIntents();
|
||||
ships.tickHomeReturn();
|
||||
ships.tickThreatResponse(buildings);
|
||||
ships.tickRepairBehavior(buildings);
|
||||
ships.tickScrapCollector(scraps, buildings);
|
||||
ships.tickMovement();
|
||||
ai.tickHomeReturn(ships);
|
||||
ai.tickThreatResponse(ships, buildings);
|
||||
ai.tickRepairBehavior(ships, buildings);
|
||||
ai.tickScrapCollector(ships, scraps, buildings);
|
||||
movement.tick(ships);
|
||||
++tick;
|
||||
}
|
||||
};
|
||||
@@ -107,7 +111,7 @@ TEST_CASE("BehaviorSystem: tickMovement advances ship by maxSpeedPerTick toward
|
||||
f.ships.forEach([&target](Ship& s) {
|
||||
s.intent = MovementIntent{1, target};
|
||||
});
|
||||
f.ships.tickMovement();
|
||||
f.movement.tick(f.ships);
|
||||
|
||||
const Ship* s = f.ships.findShip(id);
|
||||
REQUIRE(s->position.x() == Approx(speed));
|
||||
@@ -129,7 +133,7 @@ TEST_CASE("BehaviorSystem: tickMovement stops exactly at target without overshoo
|
||||
f.ships.forEach([&target](Ship& s) {
|
||||
s.intent = MovementIntent{1, target};
|
||||
});
|
||||
f.ships.tickMovement();
|
||||
f.movement.tick(f.ships);
|
||||
|
||||
const Ship* s = f.ships.findShip(id);
|
||||
REQUIRE(s->position.x() == Approx(target.x()));
|
||||
@@ -152,7 +156,7 @@ TEST_CASE("BehaviorSystem: tickHomeReturn does nothing when HP is above threshol
|
||||
});
|
||||
|
||||
f.ships.clearMovementIntents();
|
||||
f.ships.tickHomeReturn();
|
||||
f.ai.tickHomeReturn(f.ships);
|
||||
|
||||
REQUIRE(f.ships.findShip(id)->intent.priority == 0);
|
||||
}
|
||||
@@ -170,7 +174,7 @@ TEST_CASE("BehaviorSystem: tickHomeReturn writes priority-4 intent toward homePo
|
||||
});
|
||||
|
||||
f.ships.clearMovementIntents();
|
||||
f.ships.tickHomeReturn();
|
||||
f.ai.tickHomeReturn(f.ships);
|
||||
|
||||
const Ship* s = f.ships.findShip(id);
|
||||
REQUIRE(s->intent.priority == 4);
|
||||
@@ -195,8 +199,8 @@ TEST_CASE("BehaviorSystem: tickHomeReturn priority-4 beats tickThreatResponse pr
|
||||
});
|
||||
|
||||
f.ships.clearMovementIntents();
|
||||
f.ships.tickHomeReturn();
|
||||
f.ships.tickThreatResponse(f.buildings);
|
||||
f.ai.tickHomeReturn(f.ships);
|
||||
f.ai.tickThreatResponse(f.ships, f.buildings);
|
||||
|
||||
const Ship* s = f.ships.findShip(playerId);
|
||||
REQUIRE(s->intent.priority == 4);
|
||||
@@ -217,7 +221,7 @@ TEST_CASE("BehaviorSystem: player combat ship acquires nearest enemy ship in ran
|
||||
/*isEnemy=*/true);
|
||||
|
||||
f.ships.clearMovementIntents();
|
||||
f.ships.tickThreatResponse(f.buildings);
|
||||
f.ai.tickThreatResponse(f.ships, f.buildings);
|
||||
|
||||
const Ship* player = f.ships.findShip(playerId);
|
||||
REQUIRE(player->threatResponse.has_value());
|
||||
@@ -233,7 +237,7 @@ TEST_CASE("BehaviorSystem: player combat ship does not target friendly ships",
|
||||
f.ships.spawn("interceptor", 1, QVector2D(5.0f, 0.0f)); // also player (isEnemy=false)
|
||||
|
||||
f.ships.clearMovementIntents();
|
||||
f.ships.tickThreatResponse(f.buildings);
|
||||
f.ai.tickThreatResponse(f.ships, f.buildings);
|
||||
|
||||
const Ship* s = f.ships.findShip(id1);
|
||||
REQUIRE(s->threatResponse.has_value());
|
||||
@@ -249,7 +253,7 @@ TEST_CASE("BehaviorSystem: player combat ship ignores enemy beyond engagement ra
|
||||
f.ships.spawn("interceptor", 1, QVector2D(500.0f, 0.0f), /*isEnemy=*/true);
|
||||
|
||||
f.ships.clearMovementIntents();
|
||||
f.ships.tickThreatResponse(f.buildings);
|
||||
f.ai.tickThreatResponse(f.ships, f.buildings);
|
||||
|
||||
const Ship* s = f.ships.findShip(playerId);
|
||||
REQUIRE_FALSE(s->threatResponse->currentTarget.has_value());
|
||||
@@ -268,7 +272,7 @@ TEST_CASE("BehaviorSystem: enemy ship acquires nearest player ship in range",
|
||||
/*isEnemy=*/true);
|
||||
|
||||
f.ships.clearMovementIntents();
|
||||
f.ships.tickThreatResponse(f.buildings);
|
||||
f.ai.tickThreatResponse(f.ships, f.buildings);
|
||||
|
||||
const Ship* enemy = f.ships.findShip(enemyId);
|
||||
REQUIRE(enemy->threatResponse.has_value());
|
||||
@@ -284,7 +288,7 @@ TEST_CASE("BehaviorSystem: enemy ship with no target writes leftward movement in
|
||||
/*isEnemy=*/true);
|
||||
|
||||
f.ships.clearMovementIntents();
|
||||
f.ships.tickThreatResponse(f.buildings);
|
||||
f.ai.tickThreatResponse(f.ships, f.buildings);
|
||||
|
||||
const Ship* enemy = f.ships.findShip(enemyId);
|
||||
REQUIRE(enemy->intent.priority == 3);
|
||||
@@ -311,7 +315,7 @@ TEST_CASE("BehaviorSystem: repair ship writes intent toward damaged friendly shi
|
||||
});
|
||||
|
||||
f.ships.clearMovementIntents();
|
||||
f.ships.tickRepairBehavior(f.buildings);
|
||||
f.ai.tickRepairBehavior(f.ships, f.buildings);
|
||||
|
||||
const Ship* repair = f.ships.findShip(repairId);
|
||||
REQUIRE(repair->intent.priority == 2);
|
||||
@@ -335,7 +339,7 @@ TEST_CASE("BehaviorSystem: repair ship heals damaged ally within repair range",
|
||||
});
|
||||
|
||||
f.ships.clearMovementIntents();
|
||||
f.ships.tickRepairBehavior(f.buildings);
|
||||
f.ai.tickRepairBehavior(f.ships, f.buildings);
|
||||
|
||||
// repair_rate_formula = "5 + x" at x=1 → 6; hp should have increased.
|
||||
const Ship* friendly = f.ships.findShip(friendlyId);
|
||||
@@ -359,7 +363,7 @@ TEST_CASE("BehaviorSystem: repair ship does not heal above maxHp", "[behavior]")
|
||||
for (int i = 0; i < 5; ++i)
|
||||
{
|
||||
f.ships.clearMovementIntents();
|
||||
f.ships.tickRepairBehavior(f.buildings);
|
||||
f.ai.tickRepairBehavior(f.ships, f.buildings);
|
||||
}
|
||||
|
||||
const Ship* friendly = f.ships.findShip(friendlyId);
|
||||
@@ -382,7 +386,7 @@ TEST_CASE("BehaviorSystem: salvage ship writes intent toward nearest scrap", "[b
|
||||
f.scraps.spawn(scrapPos, 1, farFuture);
|
||||
|
||||
f.ships.clearMovementIntents();
|
||||
f.ships.tickScrapCollector(f.scraps, f.buildings);
|
||||
f.ai.tickScrapCollector(f.ships, f.scraps, f.buildings);
|
||||
|
||||
const Ship* s = f.ships.findShip(shipId);
|
||||
REQUIRE(s->intent.priority == 1);
|
||||
@@ -398,7 +402,7 @@ TEST_CASE("BehaviorSystem: salvage ship collects scrap on arrival", "[behavior]"
|
||||
const EntityId scrapId = f.scraps.spawn(QVector2D(0.0f, 0.0f), 1, farFuture);
|
||||
|
||||
f.ships.clearMovementIntents();
|
||||
f.ships.tickScrapCollector(f.scraps, f.buildings);
|
||||
f.ai.tickScrapCollector(f.ships, f.scraps, f.buildings);
|
||||
|
||||
const Ship* s = f.ships.findShip(shipId);
|
||||
REQUIRE(s->cargo->current == 1);
|
||||
@@ -436,7 +440,7 @@ TEST_CASE("BehaviorSystem: full-cargo salvage ship moves toward SalvageBay", "[b
|
||||
});
|
||||
|
||||
f.ships.clearMovementIntents();
|
||||
f.ships.tickScrapCollector(f.scraps, f.buildings);
|
||||
f.ai.tickScrapCollector(f.ships, f.scraps, f.buildings);
|
||||
|
||||
// Intent should point toward the bay (x < 0 area), not rightward.
|
||||
const Ship* s = f.ships.findShip(shipId);
|
||||
@@ -469,7 +473,7 @@ TEST_CASE("SensorRange: player combat ship acquires enemy just inside sensor ran
|
||||
/*isEnemy=*/true);
|
||||
|
||||
f.ships.clearMovementIntents();
|
||||
f.ships.tickThreatResponse(f.buildings);
|
||||
f.ai.tickThreatResponse(f.ships, f.buildings);
|
||||
|
||||
const Ship* player = f.ships.findShip(playerId);
|
||||
REQUIRE(player->threatResponse->currentTarget == enemyId);
|
||||
@@ -483,7 +487,7 @@ TEST_CASE("SensorRange: player combat ship ignores enemy just outside sensor ran
|
||||
f.ships.spawn("interceptor", 1, QVector2D(210.0f, 0.0f), /*isEnemy=*/true);
|
||||
|
||||
f.ships.clearMovementIntents();
|
||||
f.ships.tickThreatResponse(f.buildings);
|
||||
f.ai.tickThreatResponse(f.ships, f.buildings);
|
||||
|
||||
const Ship* player = f.ships.findShip(playerId);
|
||||
REQUIRE_FALSE(player->threatResponse->currentTarget.has_value());
|
||||
@@ -498,7 +502,7 @@ TEST_CASE("SensorRange: enemy ship ignores player just outside sensor range", "[
|
||||
/*isEnemy=*/true);
|
||||
|
||||
f.ships.clearMovementIntents();
|
||||
f.ships.tickThreatResponse(f.buildings);
|
||||
f.ai.tickThreatResponse(f.ships, f.buildings);
|
||||
|
||||
const Ship* enemy = f.ships.findShip(enemyId);
|
||||
REQUIRE_FALSE(enemy->threatResponse->currentTarget.has_value());
|
||||
@@ -516,7 +520,7 @@ TEST_CASE("SensorRange: repair ship retreats from enemy within sensor range", "[
|
||||
f.ships.spawn("interceptor", 1, QVector2D(200.0f, 0.0f), /*isEnemy=*/true);
|
||||
|
||||
f.ships.clearMovementIntents();
|
||||
f.ships.tickRepairBehavior(f.buildings);
|
||||
f.ai.tickRepairBehavior(f.ships, f.buildings);
|
||||
|
||||
const Ship* repair = f.ships.findShip(repairId);
|
||||
REQUIRE(repair->intent.priority == 2);
|
||||
@@ -531,7 +535,7 @@ TEST_CASE("SensorRange: repair ship does not retreat from enemy beyond sensor ra
|
||||
f.ships.spawn("interceptor", 1, QVector2D(300.0f, 0.0f), /*isEnemy=*/true);
|
||||
|
||||
f.ships.clearMovementIntents();
|
||||
f.ships.tickRepairBehavior(f.buildings);
|
||||
f.ai.tickRepairBehavior(f.ships, f.buildings);
|
||||
|
||||
// Enemy outside sensor range → repair ship patrols rightward instead of retreating.
|
||||
const Ship* repair = f.ships.findShip(repairId);
|
||||
@@ -549,7 +553,7 @@ TEST_CASE("SensorRange: repair ship does not acquire damaged ally beyond sensor
|
||||
});
|
||||
|
||||
f.ships.clearMovementIntents();
|
||||
f.ships.tickRepairBehavior(f.buildings);
|
||||
f.ai.tickRepairBehavior(f.ships, f.buildings);
|
||||
|
||||
REQUIRE_FALSE(f.ships.findShip(repairId)->repairBehavior->currentTarget.has_value());
|
||||
}
|
||||
@@ -566,7 +570,7 @@ TEST_CASE("SensorRange: salvage ship ignores scrap beyond sensor range", "[senso
|
||||
f.scraps.spawn(QVector2D(300.0f, 0.0f), 1, 100000);
|
||||
|
||||
f.ships.clearMovementIntents();
|
||||
f.ships.tickScrapCollector(f.scraps, f.buildings);
|
||||
f.ai.tickScrapCollector(f.ships, f.scraps, f.buildings);
|
||||
|
||||
const Ship* s = f.ships.findShip(shipId);
|
||||
REQUIRE(s->scrapCollector->scrapTarget == std::nullopt);
|
||||
|
||||
Reference in New Issue
Block a user