#include "EntityHitTest.h" #include #include #include "EntityAdmin.h" #include "SelectionBox.h" #include "PositionComponent.h" #include "DebrisComponent.h" #include "ShipIdentityComponent.h" #include "StationBodyComponent.h" #include "HealthComponent.h" entt::entity entityAtWorldPos(EntityAdmin& admin, QVector2D worldPos) { const QPoint tile(static_cast(std::floor(worldPos.x())), static_cast(std::floor(worldPos.y()))); entt::entity stationHit = entt::null; admin.forEach( [&](entt::entity entity, const StationBodyComponent& sb, const HealthComponent& h) { if (stationHit != entt::null) { return; } if (h.hp <= 0.0f) { return; } for (const QPoint& cell : sb.bodyCells) { if (cell == tile) { stationHit = entity; return; } } }); if (stationHit != entt::null) { return stationHit; } constexpr float kShipHitRadiusSquared = 0.5f * 0.5f; entt::entity bestShip = entt::null; float bestDistSquared = kShipHitRadiusSquared; admin.forEach( [&](entt::entity entity, const PositionComponent& pos, const HealthComponent& h) { if (h.hp <= 0.0f) { return; } if (admin.hasAll(entity)) { return; } const float dx = pos.value.x() - worldPos.x(); const float dy = pos.value.y() - worldPos.y(); const float distSquared = dx * dx + dy * dy; if (distSquared < bestDistSquared) { bestDistSquared = distSquared; bestShip = entity; } }); return bestShip; } entt::entity debrisAtWorldPos(EntityAdmin& admin, QVector2D worldPos) { // Slightly larger than the debris's rendered radius (0.2 tiles) so small pieces // remain easy to click; tunable. constexpr float kDebrisHitRadiusSquared = 0.35f * 0.35f; entt::entity bestDebris = entt::null; float bestDistSquared = kDebrisHitRadiusSquared; admin.forEach( [&](entt::entity entity, const DebrisComponent& /*sd*/, const PositionComponent& pos) { const float dx = pos.value.x() - worldPos.x(); const float dy = pos.value.y() - worldPos.y(); const float distSquared = dx * dx + dy * dy; if (distSquared < bestDistSquared) { bestDistSquared = distSquared; bestDebris = entity; } }); return bestDebris; } std::vector debrisInBox(EntityAdmin& admin, const QRectF& worldBox) { std::vector result; admin.forEach( [&](entt::entity entity, const DebrisComponent& /*sd*/, const PositionComponent& pos) { if (boxCoversPoint(worldBox, pos.value)) { result.push_back(entity); } }); return result; } std::vector actorsInBox(EntityAdmin& admin, const QRectF& worldBox) { std::vector result; // Stations occupy whole tiles: included when the box overlaps any occupied cell. admin.forEach( [&](entt::entity entity, const StationBodyComponent& sb, const HealthComponent& h) { if (h.hp <= 0.0f) { return; } for (const QPoint& cell : sb.bodyCells) { if (boxCoversTile(worldBox, cell)) { result.push_back(entity); return; } } }); // Ships have a position rather than a footprint: included when the box contains // that position. Requiring ShipIdentityComponent excludes the HQ proxy and any // station bodies. admin.forEach( [&](entt::entity entity, const ShipIdentityComponent& /*id*/, const PositionComponent& pos, const HealthComponent& h) { if (h.hp <= 0.0f) { return; } if (boxCoversPoint(worldBox, pos.value)) { result.push_back(entity); } }); return result; }