From 18a763bcb19c5ece4b7b7d079dab07a1d915deb6 Mon Sep 17 00:00:00 2001 From: Aki Date: Sat, 3 Dec 2022 00:44:07 +0100 Subject: Moved battles module files to sim --- sim/src/BaseBattle.cpp | 162 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 sim/src/BaseBattle.cpp (limited to 'sim/src/BaseBattle.cpp') diff --git a/sim/src/BaseBattle.cpp b/sim/src/BaseBattle.cpp new file mode 100644 index 0000000..33e0957 --- /dev/null +++ b/sim/src/BaseBattle.cpp @@ -0,0 +1,162 @@ +#include "BaseBattle.h" + +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include "Builder.h" + + +namespace kurator +{ +namespace battles +{ + + +BaseBattle::BaseBattle(const Scenario& scenario) : + _registry {}, + spawner {scenario.total_teams(), 12000, 0.1} +{ + const auto repo = universe::load_sample(); + Builder build {_registry, spawner}; + for (const auto& ship : scenario.ships) { + const auto entity = build(repo->ship_type(ship.type), ship.team); + for (const auto& turret_type : ship.turrets) + build(repo->turret_type(turret_type), entity); + manager.add(ship.team, entity); // registry supports on construction events + } +} + + +entt::registry& +BaseBattle::registry() +{ + return _registry; +} + + +entt::dispatcher& +BaseBattle::dispatcher() +{ + return _dispatcher; +} + + +void +BaseBattle::update(const float dt) +{ + pick_random_targets(); + keep_at_range(); + floating_movement(dt); + turrets(dt); + kill_off_dead(); + manager.clear(_registry); // registry supports on destructions events +} + + +void +BaseBattle::pick_random_targets() +{ + auto view = _registry.view(); + for (auto&& [entity, team, ai] : view.each()) { + if (!_registry.valid(ai.target)) + ai.target = manager.random((team.id + 1) % 2); // FIXME + } +} + + +void +BaseBattle::keep_at_range() +{ + auto view = _registry.view(); + for (auto&& [entity, self, ai] : view.each()) { + if (!_registry.valid(ai.target)) + continue; + const auto target = _registry.get(ai.target); + const Point offset = target.position - self.position; + ai.destination = target.position - offset.normalized().scale(6000.0); + } +} + + +void +BaseBattle::floating_movement(const float dt) +{ + auto view = _registry.view(); + for (auto&& [entity, transform, movement, ai] : view.each()) { + const auto offset = ai.destination - transform.position; + const auto at_destination = offset.magnitude() > movement.destination_boundary; + const auto acceleration = + at_destination ? + offset.normalized().scale(movement.acceleration * dt) : + offset.normalized().scale(-1 * movement.deceleration * dt); + movement.speed.x += acceleration.x; + movement.speed.y += acceleration.y; + if (movement.speed.magnitude() > movement.max_speed) + movement.speed = movement.speed.normalized().scale(movement.max_speed); + const auto speed = movement.speed.scale(dt); + transform.position.x += speed.x; + transform.position.y += speed.y; + transform.angle = speed.angle(); + } +} + + +double +effective_damage(const universe::TurretType& def, const double distance) +{ + const auto overflow = distance - def.optimal_range; + const auto falloff = std::max(0.0, overflow / def.optimal_range / def.falloff_modifier); + return def.base_damage * std::round(std::pow(def.falloff_intensity, std::pow(falloff, 2)) * 1000) / 1000; +} + + +void +BaseBattle::turrets(const float dt) +{ + auto view = _registry.view(); + for (auto&& [entity, control, def] : view.each()) { + if (!_registry.valid(control.owner)) { + _registry.destroy(entity); + continue; + } + const auto& [state, transform] = _registry.get(control.owner); // no checks + if (!_registry.valid(state.target)) + continue; + if (control.reload > 0.0) + control.reload -= dt; + if (control.reload <= 0.0) { + auto& target_points = _registry.get(state.target); + const auto& target = _registry.get(state.target); + const auto distance = transform.position - target.position; + const auto damage = effective_damage(def, distance.magnitude()); + if (damage > 0.0) { + target_points.health -= damage; + _dispatcher.trigger(Hit{damage, entity, state.target}); + } + control.reload = def.rate_of_fire; + } + } +} + + +void +BaseBattle::kill_off_dead() +{ + auto view = _registry.view(); + for (auto&& [entity, points] : view.each()) { + if (points.health <= 0.0) + _registry.destroy(entity); + } +} + + +} // namespace battles +} // namespace kurator -- cgit v1.1