diff options
-rw-r--r-- | kurator/src/inspect.cpp | 57 | ||||
-rw-r--r-- | sim/CMakeLists.txt | 3 | ||||
-rw-r--r-- | sim/include/kurator/sim/TurretControl.h | 25 | ||||
-rw-r--r-- | sim/include/kurator/sim/ai.h | 23 | ||||
-rw-r--r-- | sim/include/kurator/sim/components.h | 8 | ||||
-rw-r--r-- | sim/include/kurator/sim/weapons.h | 31 | ||||
-rw-r--r-- | sim/src/BaseSimulation.cpp | 7 | ||||
-rw-r--r-- | sim/src/Builder.cpp | 8 | ||||
-rw-r--r-- | sim/src/FloatingMovement.cpp | 3 | ||||
-rw-r--r-- | sim/src/TurretControl.cpp | 72 | ||||
-rw-r--r-- | sim/src/ai.cpp | 60 | ||||
-rw-r--r-- | sim/src/ai.h | 21 | ||||
-rw-r--r-- | sim/src/sim.cpp | 4 | ||||
-rw-r--r-- | sim/src/systems.cpp | 25 | ||||
-rw-r--r-- | sim/src/systems.h | 2 | ||||
-rw-r--r-- | sim/src/weapons.cpp | 81 |
16 files changed, 261 insertions, 169 deletions
diff --git a/kurator/src/inspect.cpp b/kurator/src/inspect.cpp index ea70baf..38f5394 100644 --- a/kurator/src/inspect.cpp +++ b/kurator/src/inspect.cpp @@ -6,12 +6,12 @@ #include <imgui.h> #include <raylib.h> +#include <kurator/sim/ai.h> #include <kurator/sim/components.h> #include <kurator/sim/FloatingMovement.h> #include <kurator/sim/HitPoints.h> -#include <kurator/sim/TurretControl.h> +#include <kurator/sim/weapons.h> #include <kurator/universe/ShipType.h> -#include <kurator/universe/TurretType.h> #include <kurator/universe/UniqueIdentifier.h> #include "Controller.h" @@ -51,10 +51,10 @@ InspectionWindow::show() ImGui::PushID(it - selected.begin()); inspect<universe::UniqueIdentifier>(*it); inspect<universe::ShipType>(*it); - inspect<universe::TurretType>(*it); inspect<sim::FloatingMovement>(*it); inspect<sim::HitPoints>(*it); - inspect<sim::AIState>(*it); + inspect<sim::AIShip>(*it); + inspect<sim::Turret>(*it); inspect<TurretVisuals>(*it); inspect<AIVisuals>(*it); it = std::next(it); @@ -76,7 +76,7 @@ InspectionWindow::select(entt::handle entity) return; entity.get<Selectable>().active = true; auto* registry = entity.registry(); - auto turrets = registry->view<sim::TurretControl>(); + auto turrets = registry->view<sim::Turret>(); entity.emplace<AIVisuals>(); selected.push_back(std::move(entity)); for (auto&& [entity_, turret] : turrets.each()) { @@ -131,21 +131,26 @@ slider_double(const char* label, double* value, double minimum, double maximum, template <> void -inspect(entt::handle&, universe::TurretType& type) -{ - ImGui::Text("Turret: %s", type.name.c_str()); - ImGui::Text("DPS: %.1f", type.damage_per_second()); - ImGui::Text("Eff. Range: %.1f", type.effective_range()); - ImGui::SliderInt("Rounds", &type.rounds, 0, 50); - slider_double("Base Damage", &type.base_damage, 0, 1000.0, "%.1f"); - slider_double("Rate of Fire", &type.rate_of_fire, 0, 60.0, "%.3f"); - slider_double("Reload", &type.reload, 0, 60.0, "%.3f"); - slider_double("Optimal Range", &type.optimal_range, 0, 30000.0, "%.1f"); - slider_double("Falloff Modifier", &type.falloff_modifier, 0, 5.0, "%.3f"); - slider_double("Falloff Intensity", &type.falloff_intensity, 0, 1.0, "%.3f"); - slider_double("Tracking", &type.tracking, 0, 1000.0, "%.1f"); - slider_double("Tracking Factor", &type.tracking_factor, 0, 10.0, "%.3f"); - slider_double("Tracking Exponent", &type.tracking_exponent, 0, 2.0, "%.3f"); +inspect(entt::handle&, sim::Turret& turret) +{ + ImGui::Text("Turret: %s", turret.type.name.c_str()); + ImGui::Text("DPS: %.1f", turret.type.damage_per_second()); + ImGui::Text("Eff. Range: %.1f", turret.type.effective_range()); + ImGui::Text("Current"); + ImGui::SliderInt("Rounds##current", &turret.rounds, 0, turret.type.rounds); + slider_double("Delay", &turret.delay, 0, turret.type.rate_of_fire, "%.3f"); + slider_double("Reload##current", &turret.reload, 0, turret.type.reload, "%.3f"); + ImGui::Text("Base"); + ImGui::SliderInt("Rounds##base", &turret.type.rounds, 0, 50); + slider_double("Base Damage", &turret.type.base_damage, 0, 1000.0, "%.1f"); + slider_double("Rate of Fire", &turret.type.rate_of_fire, 0, 60.0, "%.3f"); + slider_double("Reload##base", &turret.type.reload, 0, 60.0, "%.3f"); + slider_double("Optimal Range", &turret.type.optimal_range, 0, 30000.0, "%.1f"); + slider_double("Falloff Modifier", &turret.type.falloff_modifier, 0, 5.0, "%.3f"); + slider_double("Falloff Intensity", &turret.type.falloff_intensity, 0, 1.0, "%.3f"); + slider_double("Tracking", &turret.type.tracking, 0, 1000.0, "%.1f"); + slider_double("Tracking Factor", &turret.type.tracking_factor, 0, 10.0, "%.3f"); + slider_double("Tracking Exponent", &turret.type.tracking_exponent, 0, 2.0, "%.3f"); } @@ -171,7 +176,7 @@ inspect(entt::handle&, sim::HitPoints& points) template <> void -inspect(entt::handle&, sim::AIState& ai) +inspect(entt::handle&, sim::AIShip& ai) { ImGui::InputDouble("Keep At Range", &ai.keep_at_range, 0, 0, "%.1f"); } @@ -201,14 +206,14 @@ static constexpr Color EFFECTIVE {0x77, 0x50, 0x22, 0xff}; void draw_turret_visuals(const sim::State& ctx) { - const auto helpers = ctx.registry.view<TurretVisuals, universe::TurretType, sim::TurretControl>(); - for (const auto& [entity, visuals, type, turret] : helpers.each()) { + const auto helpers = ctx.registry.view<TurretVisuals, sim::Turret>(); + for (const auto& [entity, visuals, turret] : helpers.each()) { if (!visuals.visible || !ctx.registry.valid(turret.owner)) continue; const auto& transform = ctx.registry.get<sim::Transform>(turret.owner); const auto center = ctx.camera.to_screen(transform.position); - const auto optimal = type.optimal_range * ctx.camera.scale; - const auto effective = type.effective_range() * ctx.camera.scale; + const auto optimal = turret.type.optimal_range * ctx.camera.scale; + const auto effective = turret.type.effective_range() * ctx.camera.scale; DrawCircleLines(center.x, center.y, optimal, OPTIMAL); DrawCircleLines(center.x, center.y, effective, EFFECTIVE); } @@ -222,7 +227,7 @@ static constexpr Color TARGET {0x44, 0x22, 0x66, 0xff}; void draw_ai_visuals(const sim::State& ctx) { - const auto visuals = ctx.registry.view<AIVisuals, sim::AIState, sim::Transform>(); + const auto visuals = ctx.registry.view<AIVisuals, sim::AIShip, sim::Transform>(); for (const auto& [entity, visuals, ai, transform] : visuals.each()) { const auto start = ctx.camera.to_screen(transform.position); if (visuals.show_target && ctx.registry.valid(ai.target)) { diff --git a/sim/CMakeLists.txt b/sim/CMakeLists.txt index 9713d96..f5af416 100644 --- a/sim/CMakeLists.txt +++ b/sim/CMakeLists.txt @@ -1,6 +1,7 @@ project(sim) add_library( ${PROJECT_NAME} STATIC + src/ai.cpp src/BaseSimulation.cpp src/Builder.cpp src/FloatingMovement.cpp @@ -9,7 +10,7 @@ add_library( src/sim.cpp src/systems.cpp src/TeamManager.cpp - src/TurretControl.cpp + src/weapons.cpp ) target_include_directories( ${PROJECT_NAME} diff --git a/sim/include/kurator/sim/TurretControl.h b/sim/include/kurator/sim/TurretControl.h deleted file mode 100644 index ecafb90..0000000 --- a/sim/include/kurator/sim/TurretControl.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include <entt/entt.hpp> - -#include "State.h" - - -namespace kurator -{ -namespace sim -{ - - -struct TurretControl -{ - double delay; - double reload; - int rounds; - entt::entity owner; - static void update(State& ctx); -}; - - -} // namespace sim -} // namespace kurator diff --git a/sim/include/kurator/sim/ai.h b/sim/include/kurator/sim/ai.h new file mode 100644 index 0000000..f9899d6 --- /dev/null +++ b/sim/include/kurator/sim/ai.h @@ -0,0 +1,23 @@ +#pragma once + +#include <entt/entt.hpp> + +#include <kurator/engine/Point.h> + + +namespace kurator +{ +namespace sim +{ + + +struct AIShip +{ + double keep_at_range; + engine::Point destination; + entt::entity target = entt::null; +}; + + +} // namespace sim +} // namespace kurator diff --git a/sim/include/kurator/sim/components.h b/sim/include/kurator/sim/components.h index f329c0e..c4d8abc 100644 --- a/sim/include/kurator/sim/components.h +++ b/sim/include/kurator/sim/components.h @@ -25,13 +25,5 @@ struct Team }; -struct AIState -{ - double keep_at_range; - engine::Point destination; - entt::entity target = entt::null; -}; - - } // namespace sim } // namespace kurator diff --git a/sim/include/kurator/sim/weapons.h b/sim/include/kurator/sim/weapons.h new file mode 100644 index 0000000..7dd5b3b --- /dev/null +++ b/sim/include/kurator/sim/weapons.h @@ -0,0 +1,31 @@ +#pragma once + +#include <entt/entt.hpp> + +#include <kurator/universe/TurretType.h> + +#include "State.h" + + +namespace kurator +{ +namespace sim +{ + + +struct Turret +{ + entt::entity owner; + universe::TurretType type; + double delay = 0.0; + double reload = 0.0; + int rounds = type.rounds; + void shoot_at(State& ctx, const entt::entity& target, double distance); +}; + + +void update_turrets(State& ctx); + + +} // namespace sim +} // namespace kurator diff --git a/sim/src/BaseSimulation.cpp b/sim/src/BaseSimulation.cpp index 545e9ce..b1add54 100644 --- a/sim/src/BaseSimulation.cpp +++ b/sim/src/BaseSimulation.cpp @@ -2,10 +2,10 @@ #include <kurator/sim/State.h> #include <kurator/sim/FloatingMovement.h> -#include <kurator/sim/TurretControl.h> +#include <kurator/sim/weapons.h> +#include "ai.h" #include "systems.h" -#include "TeamManager.h" namespace kurator @@ -26,7 +26,8 @@ BaseSimulation::operator()(State& ctx) pick_random_targets(ctx, manager); keep_at_range(ctx); FloatingMovement::update(ctx); - TurretControl::update(ctx); + update_turrets(ctx); + shoot_at_targets(ctx); kill_off_dead(ctx); manager.update(ctx); } diff --git a/sim/src/Builder.cpp b/sim/src/Builder.cpp index af19974..4cf0bc6 100644 --- a/sim/src/Builder.cpp +++ b/sim/src/Builder.cpp @@ -3,10 +3,11 @@ #include <entt/entt.hpp> #include <kurator/engine/Point.h> +#include <kurator/sim/ai.h> #include <kurator/sim/components.h> #include <kurator/sim/FloatingMovement.h> #include <kurator/sim/HitPoints.h> -#include <kurator/sim/TurretControl.h> +#include <kurator/sim/weapons.h> #include <kurator/universe/ShipType.h> #include <kurator/universe/TurretType.h> @@ -41,7 +42,7 @@ Builder::operator()(const universe::ShipType& ship_type, const int team) const ship_type.max_speed, ship_type.max_speed * 2.0, ship_type.max_speed * 3.0); - registry.emplace<AIState>(entity, 15000.0, Point{0.0, 0.0}); + registry.emplace<AIShip>(entity, 15000.0, Point{0.0, 0.0}); registry.emplace<HitPoints>(entity, ship_type); return entity; } @@ -51,8 +52,7 @@ entt::entity Builder::operator()(const universe::TurretType& turret_type, const entt::entity& owner) const { const auto entity = registry.create(); - registry.emplace<universe::TurretType>(entity, turret_type); - registry.emplace<TurretControl>(entity, 0.0, 0.0, turret_type.rounds, owner); + registry.emplace<Turret>(entity, owner, turret_type); registry.emplace<Transform>(entity, Point{0.0, 0.0}, 0.0, owner); return entity; } diff --git a/sim/src/FloatingMovement.cpp b/sim/src/FloatingMovement.cpp index 39ec17c..4aebb9b 100644 --- a/sim/src/FloatingMovement.cpp +++ b/sim/src/FloatingMovement.cpp @@ -1,5 +1,6 @@ #include <kurator/sim/FloatingMovement.h> +#include <kurator/sim/ai.h> #include <kurator/sim/components.h> #include <kurator/sim/State.h> @@ -13,7 +14,7 @@ namespace sim void FloatingMovement::update(State& ctx) { - auto view = ctx.registry.view<Transform, FloatingMovement, AIState>(); + auto view = ctx.registry.view<Transform, FloatingMovement, AIShip>(); for (auto&& [entity, transform, movement, ai] : view.each()) { const auto offset = ai.destination - transform.position; const auto at_destination = offset.magnitude() > movement.destination_boundary; diff --git a/sim/src/TurretControl.cpp b/sim/src/TurretControl.cpp deleted file mode 100644 index 51f2a46..0000000 --- a/sim/src/TurretControl.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include <kurator/sim/TurretControl.h> - -#include <kurator/sim/components.h> -#include <kurator/sim/FloatingMovement.h> -#include <kurator/sim/HitPoints.h> -#include <kurator/sim/events.h> -#include <kurator/sim/State.h> -#include <kurator/universe/TurretType.h> - - -namespace kurator -{ -namespace sim -{ - - -bool consume(float& dt, double& target); - - -void -TurretControl::update(State& ctx) -{ - auto view = ctx.registry.view<TurretControl, universe::TurretType>(); - for (auto&& [entity, control, def] : view.each()) { - if (!ctx.registry.valid(control.owner)) { - ctx.registry.destroy(entity); - continue; - } - if (!ctx.registry.all_of<AIState, Transform>(control.owner)) - continue; - const auto& [state, transform] = ctx.registry.get<AIState, Transform>(control.owner); - if (!ctx.registry.valid(state.target)) - continue; - const auto& target = ctx.registry.get<Transform>(state.target); - const auto distance = transform.position.distance(target.position); - if (distance > def.effective_range()) - continue; - auto remaining_dt = ctx.clock.dt; - while (remaining_dt > 0.0) { - if (control.rounds < 1 && consume(remaining_dt, control.reload)) - control.rounds = def.rounds; - if (control.rounds > 0 && consume(remaining_dt, control.delay)) { - auto& target_points = ctx.registry.get<HitPoints>(state.target); - const auto& movement = ctx.registry.get<FloatingMovement>(state.target); - auto damage = def.effective_damage(distance, movement.speed.magnitude()); - if (damage > 0.0) { - damage = target_points.deal(damage); - ctx.dispatcher.trigger(Hit{damage, control.owner, state.target}); - } - control.delay = def.rate_of_fire; - if (--control.rounds < 1) - control.reload = def.reload; - } - } - } -} - - -bool -consume(float& dt, double& target) -{ - if (target <= 0.0) - return true; - const auto _dt = dt; - dt -= target; - target -= _dt; - return target <= 0.0; -} - - -} // namespace sim -} // namespace kurator diff --git a/sim/src/ai.cpp b/sim/src/ai.cpp new file mode 100644 index 0000000..1f2a4ec --- /dev/null +++ b/sim/src/ai.cpp @@ -0,0 +1,60 @@ +#include "ai.h" + +#include <kurator/sim/components.h> +#include <kurator/sim/State.h> +#include <kurator/sim/weapons.h> + +#include "TeamManager.h" + + +namespace kurator +{ +namespace sim +{ + + +void +pick_random_targets(State& ctx, TeamManager& manager) +{ + auto view = ctx.registry.view<Team, AIShip>(); + for (auto&& [entity, team, ai] : view.each()) { + if (!ctx.registry.valid(ai.target)) + ai.target = manager.random(team.id); + } +} + + +void +keep_at_range(State& ctx) +{ + auto view = ctx.registry.view<Transform, AIShip>(); + for (auto&& [entity, self, ai] : view.each()) { + if (!ctx.registry.valid(ai.target)) + continue; + const auto target = ctx.registry.get<Transform>(ai.target); + const auto offset = target.position - self.position; + ai.destination = target.position - offset.normalized().scale(ai.keep_at_range); + } +} + + +void +shoot_at_targets(State& ctx) +{ + auto view = ctx.registry.view<Turret>(); + for (auto&& [entity, turret] : view.each()) { + if (!ctx.registry.all_of<AIShip, Transform>(turret.owner)) + continue; + const auto& [state, transform] = ctx.registry.get<AIShip, Transform>(turret.owner); + if (!ctx.registry.valid(state.target)) + continue; + const auto& target = ctx.registry.get<Transform>(state.target); + const auto distance = transform.position.distance(target.position); + if (distance <= turret.type.effective_range()) + turret.shoot_at(ctx, state.target, distance); // passing distance here is wrong + } +} + + +} // namespace sim +} // namespace kurator diff --git a/sim/src/ai.h b/sim/src/ai.h new file mode 100644 index 0000000..9173891 --- /dev/null +++ b/sim/src/ai.h @@ -0,0 +1,21 @@ +#pragma once + +#include <kurator/sim/ai.h> // Propagate public header to users since both are sim/ai.h +#include <kurator/sim/State.h> + +#include "TeamManager.h" + + +namespace kurator +{ +namespace sim +{ + + +void pick_random_targets(State& ctx, TeamManager& manager); +void keep_at_range(State& ctx); +void shoot_at_targets(State& ctx); + + +} // namespace sim +} // namespace kurator diff --git a/sim/src/sim.cpp b/sim/src/sim.cpp index 4cb7467..740e6af 100644 --- a/sim/src/sim.cpp +++ b/sim/src/sim.cpp @@ -1,7 +1,7 @@ #include <kurator/sim.h> #include <kurator/campaign/Scenario.h> -#include <kurator/sim/components.h> +#include <kurator/sim/ai.h> #include <kurator/sim/State.h> #include <kurator/sim/System.h> #include <kurator/universe/UniqueIdentifier.h> @@ -26,7 +26,7 @@ load_scenario(const campaign::Scenario& scenario) for (const auto& ship : scenario.ships) { const auto entity = build(ship.loadout.type, ship.team); ctx.registry.emplace<universe::UniqueIdentifier>(entity, ship.identifier); - auto& state = ctx.registry.get<AIState>(entity); + auto& state = ctx.registry.get<AIShip>(entity); for (const auto& turret_type : ship.loadout.turrets) { build(turret_type, entity); state.keep_at_range = std::min(state.keep_at_range, turret_type.optimal_range); diff --git a/sim/src/systems.cpp b/sim/src/systems.cpp index c6f997a..ce4a6b4 100644 --- a/sim/src/systems.cpp +++ b/sim/src/systems.cpp @@ -15,31 +15,6 @@ namespace sim void -pick_random_targets(State& ctx, TeamManager& manager) -{ - auto view = ctx.registry.view<Team, AIState>(); - for (auto&& [entity, team, ai] : view.each()) { - if (!ctx.registry.valid(ai.target)) - ai.target = manager.random(team.id); - } -} - - -void -keep_at_range(State& ctx) -{ - auto view = ctx.registry.view<Transform, AIState>(); - for (auto&& [entity, self, ai] : view.each()) { - if (!ctx.registry.valid(ai.target)) - continue; - const auto target = ctx.registry.get<Transform>(ai.target); - const auto offset = target.position - self.position; - ai.destination = target.position - offset.normalized().scale(ai.keep_at_range); - } -} - - -void kill_off_dead(State& ctx) { auto view = ctx.registry.view<HitPoints>(); diff --git a/sim/src/systems.h b/sim/src/systems.h index 396ebb2..2ec9ba4 100644 --- a/sim/src/systems.h +++ b/sim/src/systems.h @@ -11,8 +11,6 @@ namespace sim { -void pick_random_targets(State& ctx, TeamManager& manager); -void keep_at_range(State& ctx); void kill_off_dead(State& ctx); diff --git a/sim/src/weapons.cpp b/sim/src/weapons.cpp new file mode 100644 index 0000000..bd130dc --- /dev/null +++ b/sim/src/weapons.cpp @@ -0,0 +1,81 @@ +#include <kurator/sim/weapons.h> + +#include <entt/entt.hpp> + +#include <kurator/sim/events.h> +#include <kurator/sim/FloatingMovement.h> +#include <kurator/sim/HitPoints.h> +#include <kurator/sim/State.h> +#include <kurator/universe/TurretType.h> + + +namespace kurator +{ +namespace sim +{ + + +static bool consume(float& dt, double& target); +static bool reload_(float& dt, Turret& turret); + + +void +Turret::shoot_at(State& ctx, const entt::entity& target, const double distance) +{ + float remaining_dt = ctx.clock.dt; + while (reload_(remaining_dt, *this)) { + auto& target_points = ctx.registry.get<HitPoints>(target); + const auto& movement = ctx.registry.get<FloatingMovement>(target); + auto damage = type.effective_damage(distance, movement.speed.magnitude()); + if (damage > 0.0) { + damage = target_points.deal(damage); + ctx.dispatcher.trigger(Hit{damage, owner, target}); + } + delay = type.rate_of_fire; + if (--rounds < 1) + reload = type.reload; + } +} + + +void +update_turrets(State& ctx) +{ + auto turrets = ctx.registry.view<Turret>(); + for (auto&& [entity, turret] : turrets.each()) { + if (!ctx.registry.valid(turret.owner)) { + ctx.registry.destroy(entity); + continue; + } + float remaining_dt = ctx.clock.dt; + while (remaining_dt > 0.0) { + if (reload_(remaining_dt, turret)) + break; + } + } +} + + +bool +consume(float& dt, double& target) +{ + if (target <= 0.0) + return true; + const auto _dt = dt; + dt -= target; + target -= _dt; + return target <= 0.0; +} + + +bool +reload_(float& dt, Turret& turret) // at this point move it to the class? +{ + if (turret.rounds < 1 && consume(dt, turret.reload)) + turret.rounds = turret.type.rounds; + return turret.rounds > 0 && consume(dt, turret.delay); +} + + +} // namespace sim +} // namespace kurator |