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 --- battles/CMakeLists.txt | 21 ---- battles/include/kurator/battles/Battle.h | 31 ----- battles/include/kurator/battles/Point.h | 26 ----- battles/include/kurator/battles/Scenario.h | 24 ---- battles/include/kurator/battles/ShipConfig.h | 22 ---- battles/include/kurator/battles/components.h | 59 ---------- battles/include/kurator/battles/events.h | 21 ---- battles/include/kurator/battles/scenarios.h | 19 ---- battles/src/BaseBattle.cpp | 162 --------------------------- battles/src/BaseBattle.h | 40 ------- battles/src/Battle.cpp | 24 ---- battles/src/Builder.cpp | 57 ---------- battles/src/Builder.h | 35 ------ battles/src/Point.cpp | 72 ------------ battles/src/RandomSpawner.cpp | 42 ------- battles/src/RandomSpawner.h | 30 ----- battles/src/Scenario.cpp | 23 ---- battles/src/Spawner.h | 21 ---- battles/src/TeamManager.cpp | 62 ---------- battles/src/TeamManager.h | 31 ----- battles/src/scenarios.cpp | 43 ------- sim/CMakeLists.txt | 21 ++++ sim/include/kurator/sim/Battle.h | 31 +++++ sim/include/kurator/sim/Point.h | 26 +++++ sim/include/kurator/sim/Scenario.h | 24 ++++ sim/include/kurator/sim/ShipConfig.h | 22 ++++ sim/include/kurator/sim/components.h | 59 ++++++++++ sim/include/kurator/sim/events.h | 21 ++++ sim/include/kurator/sim/scenarios.h | 19 ++++ sim/src/BaseBattle.cpp | 162 +++++++++++++++++++++++++++ sim/src/BaseBattle.h | 40 +++++++ sim/src/Battle.cpp | 24 ++++ sim/src/Builder.cpp | 57 ++++++++++ sim/src/Builder.h | 35 ++++++ sim/src/Point.cpp | 72 ++++++++++++ sim/src/RandomSpawner.cpp | 42 +++++++ sim/src/RandomSpawner.h | 30 +++++ sim/src/Scenario.cpp | 23 ++++ sim/src/Spawner.h | 21 ++++ sim/src/TeamManager.cpp | 62 ++++++++++ sim/src/TeamManager.h | 31 +++++ sim/src/scenarios.cpp | 43 +++++++ 42 files changed, 865 insertions(+), 865 deletions(-) delete mode 100644 battles/CMakeLists.txt delete mode 100644 battles/include/kurator/battles/Battle.h delete mode 100644 battles/include/kurator/battles/Point.h delete mode 100644 battles/include/kurator/battles/Scenario.h delete mode 100644 battles/include/kurator/battles/ShipConfig.h delete mode 100644 battles/include/kurator/battles/components.h delete mode 100644 battles/include/kurator/battles/events.h delete mode 100644 battles/include/kurator/battles/scenarios.h delete mode 100644 battles/src/BaseBattle.cpp delete mode 100644 battles/src/BaseBattle.h delete mode 100644 battles/src/Battle.cpp delete mode 100644 battles/src/Builder.cpp delete mode 100644 battles/src/Builder.h delete mode 100644 battles/src/Point.cpp delete mode 100644 battles/src/RandomSpawner.cpp delete mode 100644 battles/src/RandomSpawner.h delete mode 100644 battles/src/Scenario.cpp delete mode 100644 battles/src/Spawner.h delete mode 100644 battles/src/TeamManager.cpp delete mode 100644 battles/src/TeamManager.h delete mode 100644 battles/src/scenarios.cpp create mode 100644 sim/CMakeLists.txt create mode 100644 sim/include/kurator/sim/Battle.h create mode 100644 sim/include/kurator/sim/Point.h create mode 100644 sim/include/kurator/sim/Scenario.h create mode 100644 sim/include/kurator/sim/ShipConfig.h create mode 100644 sim/include/kurator/sim/components.h create mode 100644 sim/include/kurator/sim/events.h create mode 100644 sim/include/kurator/sim/scenarios.h create mode 100644 sim/src/BaseBattle.cpp create mode 100644 sim/src/BaseBattle.h create mode 100644 sim/src/Battle.cpp create mode 100644 sim/src/Builder.cpp create mode 100644 sim/src/Builder.h create mode 100644 sim/src/Point.cpp create mode 100644 sim/src/RandomSpawner.cpp create mode 100644 sim/src/RandomSpawner.h create mode 100644 sim/src/Scenario.cpp create mode 100644 sim/src/Spawner.h create mode 100644 sim/src/TeamManager.cpp create mode 100644 sim/src/TeamManager.h create mode 100644 sim/src/scenarios.cpp diff --git a/battles/CMakeLists.txt b/battles/CMakeLists.txt deleted file mode 100644 index f7478e3..0000000 --- a/battles/CMakeLists.txt +++ /dev/null @@ -1,21 +0,0 @@ -project(battles) -add_library( - ${PROJECT_NAME} - src/BaseBattle.cpp - src/Battle.cpp - src/Builder.cpp - src/Point.cpp - src/RandomSpawner.cpp - src/Scenario.cpp - src/scenarios.cpp - src/TeamManager.cpp -) -target_include_directories( - ${PROJECT_NAME} - PUBLIC include -) -target_link_libraries( - ${PROJECT_NAME} - PUBLIC EnTT::EnTT - PUBLIC universe -) diff --git a/battles/include/kurator/battles/Battle.h b/battles/include/kurator/battles/Battle.h deleted file mode 100644 index 1542597..0000000 --- a/battles/include/kurator/battles/Battle.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include - -#include -#include - -#include "Scenario.h" - - -namespace kurator -{ -namespace battles -{ - - -class Battle -{ -public: - virtual ~Battle() = default; - virtual entt::registry& registry() = 0; - virtual entt::dispatcher& dispatcher() = 0; - virtual void update(float dt) = 0; -}; - - -auto prepare(const Scenario& scenario) -> std::unique_ptr; - - -} // namespace battles -} // namespace kurator diff --git a/battles/include/kurator/battles/Point.h b/battles/include/kurator/battles/Point.h deleted file mode 100644 index ba9ab63..0000000 --- a/battles/include/kurator/battles/Point.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - - -namespace kurator -{ -namespace battles -{ - - -struct Point -{ - double x; - double y; - double magnitude() const; - double distance(const Point& other) const; - double angle() const; - Point rotate(double angle) const; - Point scale(double _scale) const; - Point normalized() const; - Point operator-(const Point& other) const; - Point operator+(const Point& other) const; -}; - - -} // namespace battles -} // namespace kurator diff --git a/battles/include/kurator/battles/Scenario.h b/battles/include/kurator/battles/Scenario.h deleted file mode 100644 index afbb74c..0000000 --- a/battles/include/kurator/battles/Scenario.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include -#include - -#include "ShipConfig.h" - - -namespace kurator -{ -namespace battles -{ - - -struct Scenario -{ - std::string name; - std::vector ships; - int total_teams() const; -}; - - -} // namespace battles -} // namespace kurator diff --git a/battles/include/kurator/battles/ShipConfig.h b/battles/include/kurator/battles/ShipConfig.h deleted file mode 100644 index 2066430..0000000 --- a/battles/include/kurator/battles/ShipConfig.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include -#include - - -namespace kurator -{ -namespace battles -{ - - -struct ShipConfig -{ - int team; - std::string type; - std::vector turrets; -}; - - -} // namespace battles -} // namespace kurator diff --git a/battles/include/kurator/battles/components.h b/battles/include/kurator/battles/components.h deleted file mode 100644 index d4363c4..0000000 --- a/battles/include/kurator/battles/components.h +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once - -#include - -#include "Point.h" - - -namespace kurator -{ -namespace battles -{ - - -struct Transform -{ - Point position; - double angle; - entt::entity reference_frame = entt::null; -}; - - -struct Team -{ - int id; -}; - - -struct AIState -{ - Point destination; - entt::entity target = entt::null; -}; - - -struct FloatingMovement -{ - double max_speed; - double acceleration; - double deceleration; - double destination_boundary; - Point speed = {0.0, 0.0}; -}; - - -struct HitPoints -{ - double health; -}; - - -struct TurretControl -{ - double reload; - entt::entity owner; -}; - - -} // namespace battles -} // namespace kurator diff --git a/battles/include/kurator/battles/events.h b/battles/include/kurator/battles/events.h deleted file mode 100644 index 0e4af14..0000000 --- a/battles/include/kurator/battles/events.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include - - -namespace kurator -{ -namespace battles -{ - - -struct Hit -{ - double damage; - entt::entity source; - entt::entity victim; -}; - - -} // namespace battles -} // namespace kurator diff --git a/battles/include/kurator/battles/scenarios.h b/battles/include/kurator/battles/scenarios.h deleted file mode 100644 index 3d7e697..0000000 --- a/battles/include/kurator/battles/scenarios.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include "Scenario.h" - - -namespace kurator -{ -namespace battles -{ -namespace scenarios -{ - - -Scenario example(); - - -} // namespace scenarios -} // namespace battles -} // namespace kurator diff --git a/battles/src/BaseBattle.cpp b/battles/src/BaseBattle.cpp deleted file mode 100644 index 33e0957..0000000 --- a/battles/src/BaseBattle.cpp +++ /dev/null @@ -1,162 +0,0 @@ -#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 diff --git a/battles/src/BaseBattle.h b/battles/src/BaseBattle.h deleted file mode 100644 index 8240fd2..0000000 --- a/battles/src/BaseBattle.h +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -#include -#include - -#include -#include - -#include "RandomSpawner.h" -#include "TeamManager.h" - - -namespace kurator -{ -namespace battles -{ - - -class BaseBattle : public Battle -{ -public: - BaseBattle(const Scenario& scenario); - entt::registry& registry() override; - entt::dispatcher& dispatcher() override; - void update(float dt) override; -private: - entt::registry _registry; - entt::dispatcher _dispatcher; - RandomSpawner spawner; - TeamManager manager; - void pick_random_targets(); - void keep_at_range(); - void floating_movement(float dt); - void turrets(float dt); - void kill_off_dead(); -}; - - -} // namespace battles -} // namespace kurator diff --git a/battles/src/Battle.cpp b/battles/src/Battle.cpp deleted file mode 100644 index f44a88e..0000000 --- a/battles/src/Battle.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include - -#include - -#include - -#include "BaseBattle.h" - - -namespace kurator -{ -namespace battles -{ - - -std::unique_ptr -prepare(const Scenario& scenario) -{ - return std::make_unique(scenario); -} - - -} // namespace battles -} // namespace kurator diff --git a/battles/src/Builder.cpp b/battles/src/Builder.cpp deleted file mode 100644 index d7cc893..0000000 --- a/battles/src/Builder.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "Builder.h" - -#include - -#include -#include -#include -#include - -#include "Spawner.h" - - -namespace kurator -{ -namespace battles -{ - - -Builder::Builder(entt::registry& _registry, Spawner& _spawner) : - registry {_registry}, - spawner {_spawner} -{ -} - - -entt::entity -Builder::operator()(const universe::ShipType& ship_type, const int team) const -{ - const auto entity = registry.create(); - registry.emplace(entity, ship_type); - registry.emplace(entity, team); - registry.emplace(entity, spawner.get(team)); - registry.emplace( - entity, - ship_type.max_speed, - ship_type.max_speed * 2.0, - ship_type.max_speed * 3.0, - 100.0); - registry.emplace(entity, Point{0.0, 0.0}); - registry.emplace(entity, ship_type.base_health_points); - return entity; -} - - -entt::entity -Builder::operator()(const universe::TurretType& turret_type, const entt::entity& owner) const -{ - const auto entity = registry.create(); - registry.emplace(entity, turret_type); - registry.emplace(entity, 0.0, owner); - registry.emplace(entity, Point{0.0, 0.0}, 0.0, owner); - return entity; -} - - -} // namespace battles -} // namespace kurator diff --git a/battles/src/Builder.h b/battles/src/Builder.h deleted file mode 100644 index df50c4e..0000000 --- a/battles/src/Builder.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include - -#include -#include - -#include "Spawner.h" - - -namespace kurator -{ -namespace battles -{ - - -class Builder -{ -public: - Builder(entt::registry& _registry, Spawner& _spawner); - ~Builder() = default; - Builder(Builder&&) = delete; - Builder(const Builder&) = delete; - Builder& operator=(Builder&&) = delete; - Builder& operator=(const Builder&) = delete; - entt::entity operator()(const universe::ShipType& ship_type, int team) const; - entt::entity operator()(const universe::TurretType& turret_type, const entt::entity& owner) const; -private: - entt::registry& registry; - Spawner& spawner; -}; - - -} // namespace battles -} // namespace kurator diff --git a/battles/src/Point.cpp b/battles/src/Point.cpp deleted file mode 100644 index 31aecae..0000000 --- a/battles/src/Point.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include - -#include - - -namespace kurator -{ -namespace battles -{ - - -double -Point::magnitude() const -{ - return std::sqrt(std::pow(x, 2) + std::pow(y, 2)); -} - - -double -Point::distance(const Point& other) const -{ - return std::sqrt(std::pow(other.x - x, 2) + std::pow(other.y - y, 2)); -} - - -double -Point::angle() const -{ - return std::atan2(y, x); // (+x, _) is 0 -} - - -Point -Point::rotate(const double angle) const -{ - return { - x * std::cos(angle) - y * std::sin(angle), - x * std::sin(angle) + y * std::cos(angle), - }; -} - - -Point -Point::scale(const double _scale) const -{ - return {x * _scale, y * _scale}; -} - - -Point -Point::normalized() const -{ - return scale(1.0 / magnitude()); -} - - -Point -Point::operator-(const Point& other) const -{ - return {x - other.x, y - other.y}; -} - - -Point -Point::operator+(const Point& other) const -{ - return {x + other.x, y + other.y}; -} - - -} // namespace battles -} // namespace kurator diff --git a/battles/src/RandomSpawner.cpp b/battles/src/RandomSpawner.cpp deleted file mode 100644 index b85d140..0000000 --- a/battles/src/RandomSpawner.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include "RandomSpawner.h" - -#include - -#include -#include - - -namespace kurator -{ -namespace battles -{ - - -RandomSpawner::RandomSpawner(const int total_teams, const double distance, const double variation) : - angle_step {2.0 * M_PI / total_teams}, - device {}, - distribution_d {distance - distance * variation, distance + distance * variation}, - distribution_a {-variation * M_PI, variation * M_PI} -{ -} - - -Transform -RandomSpawner::get(const int team) -{ - const double distance = distribution_d(device); - const double clean_angle = angle_step * team; - const double angle = clean_angle + distribution_a(device); - double facing = clean_angle + M_PI; - if (facing > 2 * M_PI) - facing -= 2 * M_PI; - const Point position { - distance * std::cos(angle), - distance * std::sin(angle), - }; - return {position, facing}; -} - - -} // namespace battles -} // namespace kurator diff --git a/battles/src/RandomSpawner.h b/battles/src/RandomSpawner.h deleted file mode 100644 index 1ef2f20..0000000 --- a/battles/src/RandomSpawner.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include - -#include - -#include "Spawner.h" - - -namespace kurator -{ -namespace battles -{ - - -class RandomSpawner : public Spawner -{ -public: - RandomSpawner(int total_teams, double distance, double variation); - Transform get(int team) override; -private: - const double angle_step; - std::random_device device; - std::uniform_real_distribution distribution_d; - std::uniform_real_distribution distribution_a; -}; - - -} // namespace battles -} // namespace kurator diff --git a/battles/src/Scenario.cpp b/battles/src/Scenario.cpp deleted file mode 100644 index 49a9c7c..0000000 --- a/battles/src/Scenario.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include - - -namespace kurator -{ -namespace battles -{ - - -int -Scenario::total_teams() const -{ - int last_team = 0; - for (const auto& ship : ships) { - if (ship.team > last_team) - last_team = ship.team; - } - return last_team + 1; -} - - -} // namespace battles -} // namespace kurator diff --git a/battles/src/Spawner.h b/battles/src/Spawner.h deleted file mode 100644 index ebae699..0000000 --- a/battles/src/Spawner.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include - - -namespace kurator -{ -namespace battles -{ - - -class Spawner -{ -public: - virtual ~Spawner() = default; - virtual Transform get(int team) = 0; -}; - - -} // namespace battles -} // namespace kurator diff --git a/battles/src/TeamManager.cpp b/battles/src/TeamManager.cpp deleted file mode 100644 index 9dc90e3..0000000 --- a/battles/src/TeamManager.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "TeamManager.h" - -#include -#include -#include -#include - -#include - - -namespace kurator -{ -namespace battles -{ - - -TeamManager::TeamManager() : - teams {}, - generator {std::random_device{}()} -{ -} - - -void -TeamManager::add(int team, entt::entity entity) -{ - for (int i = teams.size(); i < team + 1; ++i) - teams.emplace_back(); - teams.at(team).push_back(std::move(entity)); -} - - -TeamManager::Team -TeamManager::get(int team) const -{ - return teams.at(team); -} - - -entt::entity -TeamManager::random(int team) -{ - auto& members = teams.at(team); - if (members.size() == 0) - return entt::null; - std::uniform_int_distribution uniform{0, members.size() - 1}; - return members.at(uniform(generator)); -} - - -void -TeamManager::clear(entt::registry& registry) -{ - for (auto& members : teams) { - auto is_valid = [®istry](entt::entity entity){ return !registry.valid(entity); }; - members.erase(std::remove_if(members.begin(), members.end(), is_valid), members.end()); - } -} - - -} // namespace battles -} // namespace kurator diff --git a/battles/src/TeamManager.h b/battles/src/TeamManager.h deleted file mode 100644 index 384d9ee..0000000 --- a/battles/src/TeamManager.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include -#include - -#include - - -namespace kurator -{ -namespace battles -{ - - -class TeamManager -{ -public: - using Team = std::vector; - TeamManager(); - void add(int team, entt::entity entity); - Team get(int team) const; - entt::entity random(int team); - void clear(entt::registry& registry); -private: - std::vector teams; - std::mt19937 generator; -}; - - -} // namespace battles -} // namespace kurator diff --git a/battles/src/scenarios.cpp b/battles/src/scenarios.cpp deleted file mode 100644 index 34b4a24..0000000 --- a/battles/src/scenarios.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include - -#include - - -namespace kurator -{ -namespace battles -{ -namespace scenarios -{ - - -Scenario -example() -{ - return { - "Example", - { - {0, "Anvil", {"ChargeLaser", "ChargeLaser"}}, - {0, "Anvil", {"ChargeLaser", "ChargeLaser"}}, - {0, "Anvil", {"ChargeLaser", "ChargeLaser"}}, - {0, "Warbringer", {"ChargeLaser"}}, - {0, "Warbringer", {"ChargeLaser"}}, - {0, "Eclipse", {"ChargeLaser"}}, - {0, "Eclipse", {"ChargeLaser"}}, - {0, "Eclipse", {"ChargeLaser"}}, - {1, "Anvil", {"ChargeLaser", "ChargeLaser"}}, - {1, "Anvil", {"ChargeLaser", "ChargeLaser"}}, - {1, "Anvil", {"ChargeLaser", "ChargeLaser"}}, - {1, "Warbringer", {"ChargeLaser"}}, - {1, "Warbringer", {"ChargeLaser"}}, - {1, "Eclipse", {"ChargeLaser"}}, - {1, "Eclipse", {"ChargeLaser"}}, - {1, "Eclipse", {"ChargeLaser"}}, - }, - }; -} - - -} // namespace scenarios -} // namespace battles -} // namespace kurator diff --git a/sim/CMakeLists.txt b/sim/CMakeLists.txt new file mode 100644 index 0000000..f7478e3 --- /dev/null +++ b/sim/CMakeLists.txt @@ -0,0 +1,21 @@ +project(battles) +add_library( + ${PROJECT_NAME} + src/BaseBattle.cpp + src/Battle.cpp + src/Builder.cpp + src/Point.cpp + src/RandomSpawner.cpp + src/Scenario.cpp + src/scenarios.cpp + src/TeamManager.cpp +) +target_include_directories( + ${PROJECT_NAME} + PUBLIC include +) +target_link_libraries( + ${PROJECT_NAME} + PUBLIC EnTT::EnTT + PUBLIC universe +) diff --git a/sim/include/kurator/sim/Battle.h b/sim/include/kurator/sim/Battle.h new file mode 100644 index 0000000..1542597 --- /dev/null +++ b/sim/include/kurator/sim/Battle.h @@ -0,0 +1,31 @@ +#pragma once + +#include + +#include +#include + +#include "Scenario.h" + + +namespace kurator +{ +namespace battles +{ + + +class Battle +{ +public: + virtual ~Battle() = default; + virtual entt::registry& registry() = 0; + virtual entt::dispatcher& dispatcher() = 0; + virtual void update(float dt) = 0; +}; + + +auto prepare(const Scenario& scenario) -> std::unique_ptr; + + +} // namespace battles +} // namespace kurator diff --git a/sim/include/kurator/sim/Point.h b/sim/include/kurator/sim/Point.h new file mode 100644 index 0000000..ba9ab63 --- /dev/null +++ b/sim/include/kurator/sim/Point.h @@ -0,0 +1,26 @@ +#pragma once + + +namespace kurator +{ +namespace battles +{ + + +struct Point +{ + double x; + double y; + double magnitude() const; + double distance(const Point& other) const; + double angle() const; + Point rotate(double angle) const; + Point scale(double _scale) const; + Point normalized() const; + Point operator-(const Point& other) const; + Point operator+(const Point& other) const; +}; + + +} // namespace battles +} // namespace kurator diff --git a/sim/include/kurator/sim/Scenario.h b/sim/include/kurator/sim/Scenario.h new file mode 100644 index 0000000..afbb74c --- /dev/null +++ b/sim/include/kurator/sim/Scenario.h @@ -0,0 +1,24 @@ +#pragma once + +#include +#include + +#include "ShipConfig.h" + + +namespace kurator +{ +namespace battles +{ + + +struct Scenario +{ + std::string name; + std::vector ships; + int total_teams() const; +}; + + +} // namespace battles +} // namespace kurator diff --git a/sim/include/kurator/sim/ShipConfig.h b/sim/include/kurator/sim/ShipConfig.h new file mode 100644 index 0000000..2066430 --- /dev/null +++ b/sim/include/kurator/sim/ShipConfig.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include + + +namespace kurator +{ +namespace battles +{ + + +struct ShipConfig +{ + int team; + std::string type; + std::vector turrets; +}; + + +} // namespace battles +} // namespace kurator diff --git a/sim/include/kurator/sim/components.h b/sim/include/kurator/sim/components.h new file mode 100644 index 0000000..d4363c4 --- /dev/null +++ b/sim/include/kurator/sim/components.h @@ -0,0 +1,59 @@ +#pragma once + +#include + +#include "Point.h" + + +namespace kurator +{ +namespace battles +{ + + +struct Transform +{ + Point position; + double angle; + entt::entity reference_frame = entt::null; +}; + + +struct Team +{ + int id; +}; + + +struct AIState +{ + Point destination; + entt::entity target = entt::null; +}; + + +struct FloatingMovement +{ + double max_speed; + double acceleration; + double deceleration; + double destination_boundary; + Point speed = {0.0, 0.0}; +}; + + +struct HitPoints +{ + double health; +}; + + +struct TurretControl +{ + double reload; + entt::entity owner; +}; + + +} // namespace battles +} // namespace kurator diff --git a/sim/include/kurator/sim/events.h b/sim/include/kurator/sim/events.h new file mode 100644 index 0000000..0e4af14 --- /dev/null +++ b/sim/include/kurator/sim/events.h @@ -0,0 +1,21 @@ +#pragma once + +#include + + +namespace kurator +{ +namespace battles +{ + + +struct Hit +{ + double damage; + entt::entity source; + entt::entity victim; +}; + + +} // namespace battles +} // namespace kurator diff --git a/sim/include/kurator/sim/scenarios.h b/sim/include/kurator/sim/scenarios.h new file mode 100644 index 0000000..3d7e697 --- /dev/null +++ b/sim/include/kurator/sim/scenarios.h @@ -0,0 +1,19 @@ +#pragma once + +#include "Scenario.h" + + +namespace kurator +{ +namespace battles +{ +namespace scenarios +{ + + +Scenario example(); + + +} // namespace scenarios +} // namespace battles +} // namespace kurator 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 diff --git a/sim/src/BaseBattle.h b/sim/src/BaseBattle.h new file mode 100644 index 0000000..8240fd2 --- /dev/null +++ b/sim/src/BaseBattle.h @@ -0,0 +1,40 @@ +#pragma once + +#include +#include + +#include +#include + +#include "RandomSpawner.h" +#include "TeamManager.h" + + +namespace kurator +{ +namespace battles +{ + + +class BaseBattle : public Battle +{ +public: + BaseBattle(const Scenario& scenario); + entt::registry& registry() override; + entt::dispatcher& dispatcher() override; + void update(float dt) override; +private: + entt::registry _registry; + entt::dispatcher _dispatcher; + RandomSpawner spawner; + TeamManager manager; + void pick_random_targets(); + void keep_at_range(); + void floating_movement(float dt); + void turrets(float dt); + void kill_off_dead(); +}; + + +} // namespace battles +} // namespace kurator diff --git a/sim/src/Battle.cpp b/sim/src/Battle.cpp new file mode 100644 index 0000000..f44a88e --- /dev/null +++ b/sim/src/Battle.cpp @@ -0,0 +1,24 @@ +#include + +#include + +#include + +#include "BaseBattle.h" + + +namespace kurator +{ +namespace battles +{ + + +std::unique_ptr +prepare(const Scenario& scenario) +{ + return std::make_unique(scenario); +} + + +} // namespace battles +} // namespace kurator diff --git a/sim/src/Builder.cpp b/sim/src/Builder.cpp new file mode 100644 index 0000000..d7cc893 --- /dev/null +++ b/sim/src/Builder.cpp @@ -0,0 +1,57 @@ +#include "Builder.h" + +#include + +#include +#include +#include +#include + +#include "Spawner.h" + + +namespace kurator +{ +namespace battles +{ + + +Builder::Builder(entt::registry& _registry, Spawner& _spawner) : + registry {_registry}, + spawner {_spawner} +{ +} + + +entt::entity +Builder::operator()(const universe::ShipType& ship_type, const int team) const +{ + const auto entity = registry.create(); + registry.emplace(entity, ship_type); + registry.emplace(entity, team); + registry.emplace(entity, spawner.get(team)); + registry.emplace( + entity, + ship_type.max_speed, + ship_type.max_speed * 2.0, + ship_type.max_speed * 3.0, + 100.0); + registry.emplace(entity, Point{0.0, 0.0}); + registry.emplace(entity, ship_type.base_health_points); + return entity; +} + + +entt::entity +Builder::operator()(const universe::TurretType& turret_type, const entt::entity& owner) const +{ + const auto entity = registry.create(); + registry.emplace(entity, turret_type); + registry.emplace(entity, 0.0, owner); + registry.emplace(entity, Point{0.0, 0.0}, 0.0, owner); + return entity; +} + + +} // namespace battles +} // namespace kurator diff --git a/sim/src/Builder.h b/sim/src/Builder.h new file mode 100644 index 0000000..df50c4e --- /dev/null +++ b/sim/src/Builder.h @@ -0,0 +1,35 @@ +#pragma once + +#include + +#include +#include + +#include "Spawner.h" + + +namespace kurator +{ +namespace battles +{ + + +class Builder +{ +public: + Builder(entt::registry& _registry, Spawner& _spawner); + ~Builder() = default; + Builder(Builder&&) = delete; + Builder(const Builder&) = delete; + Builder& operator=(Builder&&) = delete; + Builder& operator=(const Builder&) = delete; + entt::entity operator()(const universe::ShipType& ship_type, int team) const; + entt::entity operator()(const universe::TurretType& turret_type, const entt::entity& owner) const; +private: + entt::registry& registry; + Spawner& spawner; +}; + + +} // namespace battles +} // namespace kurator diff --git a/sim/src/Point.cpp b/sim/src/Point.cpp new file mode 100644 index 0000000..31aecae --- /dev/null +++ b/sim/src/Point.cpp @@ -0,0 +1,72 @@ +#include + +#include + + +namespace kurator +{ +namespace battles +{ + + +double +Point::magnitude() const +{ + return std::sqrt(std::pow(x, 2) + std::pow(y, 2)); +} + + +double +Point::distance(const Point& other) const +{ + return std::sqrt(std::pow(other.x - x, 2) + std::pow(other.y - y, 2)); +} + + +double +Point::angle() const +{ + return std::atan2(y, x); // (+x, _) is 0 +} + + +Point +Point::rotate(const double angle) const +{ + return { + x * std::cos(angle) - y * std::sin(angle), + x * std::sin(angle) + y * std::cos(angle), + }; +} + + +Point +Point::scale(const double _scale) const +{ + return {x * _scale, y * _scale}; +} + + +Point +Point::normalized() const +{ + return scale(1.0 / magnitude()); +} + + +Point +Point::operator-(const Point& other) const +{ + return {x - other.x, y - other.y}; +} + + +Point +Point::operator+(const Point& other) const +{ + return {x + other.x, y + other.y}; +} + + +} // namespace battles +} // namespace kurator diff --git a/sim/src/RandomSpawner.cpp b/sim/src/RandomSpawner.cpp new file mode 100644 index 0000000..b85d140 --- /dev/null +++ b/sim/src/RandomSpawner.cpp @@ -0,0 +1,42 @@ +#include "RandomSpawner.h" + +#include + +#include +#include + + +namespace kurator +{ +namespace battles +{ + + +RandomSpawner::RandomSpawner(const int total_teams, const double distance, const double variation) : + angle_step {2.0 * M_PI / total_teams}, + device {}, + distribution_d {distance - distance * variation, distance + distance * variation}, + distribution_a {-variation * M_PI, variation * M_PI} +{ +} + + +Transform +RandomSpawner::get(const int team) +{ + const double distance = distribution_d(device); + const double clean_angle = angle_step * team; + const double angle = clean_angle + distribution_a(device); + double facing = clean_angle + M_PI; + if (facing > 2 * M_PI) + facing -= 2 * M_PI; + const Point position { + distance * std::cos(angle), + distance * std::sin(angle), + }; + return {position, facing}; +} + + +} // namespace battles +} // namespace kurator diff --git a/sim/src/RandomSpawner.h b/sim/src/RandomSpawner.h new file mode 100644 index 0000000..1ef2f20 --- /dev/null +++ b/sim/src/RandomSpawner.h @@ -0,0 +1,30 @@ +#pragma once + +#include + +#include + +#include "Spawner.h" + + +namespace kurator +{ +namespace battles +{ + + +class RandomSpawner : public Spawner +{ +public: + RandomSpawner(int total_teams, double distance, double variation); + Transform get(int team) override; +private: + const double angle_step; + std::random_device device; + std::uniform_real_distribution distribution_d; + std::uniform_real_distribution distribution_a; +}; + + +} // namespace battles +} // namespace kurator diff --git a/sim/src/Scenario.cpp b/sim/src/Scenario.cpp new file mode 100644 index 0000000..49a9c7c --- /dev/null +++ b/sim/src/Scenario.cpp @@ -0,0 +1,23 @@ +#include + + +namespace kurator +{ +namespace battles +{ + + +int +Scenario::total_teams() const +{ + int last_team = 0; + for (const auto& ship : ships) { + if (ship.team > last_team) + last_team = ship.team; + } + return last_team + 1; +} + + +} // namespace battles +} // namespace kurator diff --git a/sim/src/Spawner.h b/sim/src/Spawner.h new file mode 100644 index 0000000..ebae699 --- /dev/null +++ b/sim/src/Spawner.h @@ -0,0 +1,21 @@ +#pragma once + +#include + + +namespace kurator +{ +namespace battles +{ + + +class Spawner +{ +public: + virtual ~Spawner() = default; + virtual Transform get(int team) = 0; +}; + + +} // namespace battles +} // namespace kurator diff --git a/sim/src/TeamManager.cpp b/sim/src/TeamManager.cpp new file mode 100644 index 0000000..9dc90e3 --- /dev/null +++ b/sim/src/TeamManager.cpp @@ -0,0 +1,62 @@ +#include "TeamManager.h" + +#include +#include +#include +#include + +#include + + +namespace kurator +{ +namespace battles +{ + + +TeamManager::TeamManager() : + teams {}, + generator {std::random_device{}()} +{ +} + + +void +TeamManager::add(int team, entt::entity entity) +{ + for (int i = teams.size(); i < team + 1; ++i) + teams.emplace_back(); + teams.at(team).push_back(std::move(entity)); +} + + +TeamManager::Team +TeamManager::get(int team) const +{ + return teams.at(team); +} + + +entt::entity +TeamManager::random(int team) +{ + auto& members = teams.at(team); + if (members.size() == 0) + return entt::null; + std::uniform_int_distribution uniform{0, members.size() - 1}; + return members.at(uniform(generator)); +} + + +void +TeamManager::clear(entt::registry& registry) +{ + for (auto& members : teams) { + auto is_valid = [®istry](entt::entity entity){ return !registry.valid(entity); }; + members.erase(std::remove_if(members.begin(), members.end(), is_valid), members.end()); + } +} + + +} // namespace battles +} // namespace kurator diff --git a/sim/src/TeamManager.h b/sim/src/TeamManager.h new file mode 100644 index 0000000..384d9ee --- /dev/null +++ b/sim/src/TeamManager.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include + +#include + + +namespace kurator +{ +namespace battles +{ + + +class TeamManager +{ +public: + using Team = std::vector; + TeamManager(); + void add(int team, entt::entity entity); + Team get(int team) const; + entt::entity random(int team); + void clear(entt::registry& registry); +private: + std::vector teams; + std::mt19937 generator; +}; + + +} // namespace battles +} // namespace kurator diff --git a/sim/src/scenarios.cpp b/sim/src/scenarios.cpp new file mode 100644 index 0000000..34b4a24 --- /dev/null +++ b/sim/src/scenarios.cpp @@ -0,0 +1,43 @@ +#include + +#include + + +namespace kurator +{ +namespace battles +{ +namespace scenarios +{ + + +Scenario +example() +{ + return { + "Example", + { + {0, "Anvil", {"ChargeLaser", "ChargeLaser"}}, + {0, "Anvil", {"ChargeLaser", "ChargeLaser"}}, + {0, "Anvil", {"ChargeLaser", "ChargeLaser"}}, + {0, "Warbringer", {"ChargeLaser"}}, + {0, "Warbringer", {"ChargeLaser"}}, + {0, "Eclipse", {"ChargeLaser"}}, + {0, "Eclipse", {"ChargeLaser"}}, + {0, "Eclipse", {"ChargeLaser"}}, + {1, "Anvil", {"ChargeLaser", "ChargeLaser"}}, + {1, "Anvil", {"ChargeLaser", "ChargeLaser"}}, + {1, "Anvil", {"ChargeLaser", "ChargeLaser"}}, + {1, "Warbringer", {"ChargeLaser"}}, + {1, "Warbringer", {"ChargeLaser"}}, + {1, "Eclipse", {"ChargeLaser"}}, + {1, "Eclipse", {"ChargeLaser"}}, + {1, "Eclipse", {"ChargeLaser"}}, + }, + }; +} + + +} // namespace scenarios +} // namespace battles +} // namespace kurator -- cgit v1.1