From f6111b6df65047557239c827100454c188979c43 Mon Sep 17 00:00:00 2001 From: max-001 Date: Wed, 4 Dec 2024 11:45:50 +0100 Subject: Setup test for AI --- src/example/AITest.cpp | 32 ++++++++++++++++++++++++++++++++ src/example/CMakeLists.txt | 2 +- 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 src/example/AITest.cpp diff --git a/src/example/AITest.cpp b/src/example/AITest.cpp new file mode 100644 index 0000000..ccf5a85 --- /dev/null +++ b/src/example/AITest.cpp @@ -0,0 +1,32 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace crepe; + +int main() { + ComponentManager mgr; + GameObject game_object1 = mgr.new_object("", "", vec2{0, 0}, 0, 1); + GameObject game_object2 = mgr.new_object("", "", vec2{0, 0}, 0, 1); + + Texture img = Texture("asset/texture/test_ap43.png"); + game_object1.add_component(img, Color::MAGENTA, Sprite::FlipSettings{false, false}, 1, 1, 195); + + game_object2.add_component(Color::WHITE, ivec2{1080, 720}, vec2{1036, 780}, 1.0f); + + RenderSystem sys{mgr}; + + auto start = std::chrono::steady_clock::now(); + while (std::chrono::steady_clock::now() - start < std::chrono::seconds(5)) { + sys.update(); + SDL_Delay(10); + } + + return 0; +} diff --git a/src/example/CMakeLists.txt b/src/example/CMakeLists.txt index 560e2bc..ef770ae 100644 --- a/src/example/CMakeLists.txt +++ b/src/example/CMakeLists.txt @@ -20,4 +20,4 @@ add_example(asset_manager) add_example(savemgr) add_example(rendering_particle) add_example(gameloop) - +add_example(AITest) -- cgit v1.2.3 From 16444f19ae2c7c71a2be53ce6fd2e4d671aa8765 Mon Sep 17 00:00:00 2001 From: max-001 Date: Wed, 4 Dec 2024 12:15:05 +0100 Subject: Modified test and setup of AISystem --- src/crepe/api/LoopManager.cpp | 14 ++++++++++++- src/crepe/system/AISystem.cpp | 6 ++++++ src/crepe/system/AISystem.h | 14 +++++++++++++ src/crepe/system/CMakeLists.txt | 2 ++ src/example/AITest.cpp | 45 ++++++++++++++++++++++++----------------- 5 files changed, 62 insertions(+), 19 deletions(-) create mode 100644 src/crepe/system/AISystem.cpp create mode 100644 src/crepe/system/AISystem.h diff --git a/src/crepe/api/LoopManager.cpp b/src/crepe/api/LoopManager.cpp index 7edf4d1..cd602d8 100644 --- a/src/crepe/api/LoopManager.cpp +++ b/src/crepe/api/LoopManager.cpp @@ -1,5 +1,6 @@ #include "../facade/SDLContext.h" +#include "../system/AISystem.h" #include "../system/AnimatorSystem.h" #include "../system/CollisionSystem.h" #include "../system/ParticleSystem.h" @@ -20,6 +21,7 @@ LoopManager::LoopManager() { this->load_system(); this->load_system(); this->load_system(); + this->load_system(); } void LoopManager::process_input() { @@ -51,6 +53,11 @@ void LoopManager::loop() { this->render(); timer.enforce_frame_rate(); + + // Stop the game after 5 seconds, for testing purposes + if (timer.get_current_time() > 5) { + this->game_running = false; + } } } @@ -58,6 +65,7 @@ void LoopManager::setup() { this->game_running = true; LoopTimer::get_instance().start(); LoopTimer::get_instance().set_fps(200); + this->scene_manager.load_next_scene(); } void LoopManager::render() { @@ -66,4 +74,8 @@ void LoopManager::render() { } } -void LoopManager::update() { LoopTimer & timer = LoopTimer::get_instance(); } +void LoopManager::update() { + LoopTimer & timer = LoopTimer::get_instance(); + this->get_system().update(); + this->get_system().update(); +} diff --git a/src/crepe/system/AISystem.cpp b/src/crepe/system/AISystem.cpp new file mode 100644 index 0000000..012f4fa --- /dev/null +++ b/src/crepe/system/AISystem.cpp @@ -0,0 +1,6 @@ +#include "AISystem.h" +#include + +using namespace crepe; + +void AISystem::update() { std::cout << "AI System update" << std::endl; } diff --git a/src/crepe/system/AISystem.h b/src/crepe/system/AISystem.h new file mode 100644 index 0000000..4138e01 --- /dev/null +++ b/src/crepe/system/AISystem.h @@ -0,0 +1,14 @@ +#pragma once + +#include "System.h" + +namespace crepe { + +class AISystem : public System { +public: + using System::System; + + void update() override; +}; + +} // namespace crepe diff --git a/src/crepe/system/CMakeLists.txt b/src/crepe/system/CMakeLists.txt index d658b25..ca89d4d 100644 --- a/src/crepe/system/CMakeLists.txt +++ b/src/crepe/system/CMakeLists.txt @@ -6,6 +6,7 @@ target_sources(crepe PUBLIC CollisionSystem.cpp RenderSystem.cpp AnimatorSystem.cpp + AISystem.cpp ) target_sources(crepe PUBLIC FILE_SET HEADERS FILES @@ -15,4 +16,5 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES CollisionSystem.h RenderSystem.h AnimatorSystem.h + AISystem.h ) diff --git a/src/example/AITest.cpp b/src/example/AITest.cpp index ccf5a85..3998ff4 100644 --- a/src/example/AITest.cpp +++ b/src/example/AITest.cpp @@ -1,32 +1,41 @@ +#include +#include +#include #include #include -#include -#include -#include #include +#include +#include +#include +#include #include -#include -#include using namespace crepe; +using namespace std; -int main() { - ComponentManager mgr; - GameObject game_object1 = mgr.new_object("", "", vec2{0, 0}, 0, 1); - GameObject game_object2 = mgr.new_object("", "", vec2{0, 0}, 0, 1); - - Texture img = Texture("asset/texture/test_ap43.png"); - game_object1.add_component(img, Color::MAGENTA, Sprite::FlipSettings{false, false}, 1, 1, 195); +class Scene1 : public Scene { +public: + void load_scene() override { + ComponentManager & mgr = this->component_manager; - game_object2.add_component(Color::WHITE, ivec2{1080, 720}, vec2{1036, 780}, 1.0f); + GameObject game_object1 = mgr.new_object("", "", vec2{0, 0}, 0, 1); + GameObject game_object2 = mgr.new_object("", "", vec2{0, 0}, 0, 1); - RenderSystem sys{mgr}; + Texture img = Texture("asset/texture/test_ap43.png"); + game_object1.add_component(img, Color::MAGENTA, + Sprite::FlipSettings{false, false}, 1, 1, 195); - auto start = std::chrono::steady_clock::now(); - while (std::chrono::steady_clock::now() - start < std::chrono::seconds(5)) { - sys.update(); - SDL_Delay(10); + game_object2.add_component(Color::WHITE, ivec2{1080, 720}, vec2{1036, 780}, + 1.0f); } + string get_name() const override { return "Scene1"; } +}; + +int main() { + LoopManager engine; + engine.add_scene(); + engine.start(); + return 0; } -- cgit v1.2.3 From ac87bfad20e1bcf1fd066a4eda231608fe12f504 Mon Sep 17 00:00:00 2001 From: max-001 Date: Wed, 4 Dec 2024 13:17:08 +0100 Subject: Added AI component --- src/crepe/api/AI.cpp | 11 +++++++++++ src/crepe/api/AI.h | 18 ++++++++++++++++++ src/crepe/api/CMakeLists.txt | 2 ++ src/example/AITest.cpp | 3 ++- 4 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 src/crepe/api/AI.cpp create mode 100644 src/crepe/api/AI.h diff --git a/src/crepe/api/AI.cpp b/src/crepe/api/AI.cpp new file mode 100644 index 0000000..6b63216 --- /dev/null +++ b/src/crepe/api/AI.cpp @@ -0,0 +1,11 @@ +#include "AI.h" + +namespace crepe { + +AI::AI(game_object_id_t id, double mass, double max_speed, double max_force) + : Component(id), + mass(mass), + max_speed(max_speed), + max_force(max_force) {} + +} // namespace crepe diff --git a/src/crepe/api/AI.h b/src/crepe/api/AI.h new file mode 100644 index 0000000..b755439 --- /dev/null +++ b/src/crepe/api/AI.h @@ -0,0 +1,18 @@ +#pragma once + +#include "Component.h" +#include "types.h" + +namespace crepe { + +class AI : public Component { +public: + AI(game_object_id_t id, double mass, double max_speed, double max_force); + +public: + double mass; + double max_speed; + double max_force; +}; + +} // namespace crepe diff --git a/src/crepe/api/CMakeLists.txt b/src/crepe/api/CMakeLists.txt index 50c51ed..d42b459 100644 --- a/src/crepe/api/CMakeLists.txt +++ b/src/crepe/api/CMakeLists.txt @@ -23,6 +23,7 @@ target_sources(crepe PUBLIC Asset.cpp EventHandler.cpp Script.cpp + AI.cpp ) target_sources(crepe PUBLIC FILE_SET HEADERS FILES @@ -58,4 +59,5 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES LoopManager.h LoopTimer.h Asset.h + AI.h ) diff --git a/src/example/AITest.cpp b/src/example/AITest.cpp index 3998ff4..1c4633f 100644 --- a/src/example/AITest.cpp +++ b/src/example/AITest.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -8,7 +9,6 @@ #include #include #include -#include using namespace crepe; using namespace std; @@ -24,6 +24,7 @@ public: Texture img = Texture("asset/texture/test_ap43.png"); game_object1.add_component(img, Color::MAGENTA, Sprite::FlipSettings{false, false}, 1, 1, 195); + game_object1.add_component(1, 1, 1); game_object2.add_component(Color::WHITE, ivec2{1080, 720}, vec2{1036, 780}, 1.0f); -- cgit v1.2.3 From f9f5600b60d6944dc9a7dd502988703d59d0cd62 Mon Sep 17 00:00:00 2001 From: max-001 Date: Wed, 4 Dec 2024 13:46:41 +0100 Subject: Setup some behaviors --- src/crepe/api/AI.cpp | 2 +- src/crepe/api/AI.h | 47 +++++++++++++++++++++++++++++++++++++++---- src/crepe/system/AISystem.cpp | 32 +++++++++++++++++++++++++++-- src/crepe/system/AISystem.h | 6 ++++++ 4 files changed, 80 insertions(+), 7 deletions(-) diff --git a/src/crepe/api/AI.cpp b/src/crepe/api/AI.cpp index 6b63216..7f820a8 100644 --- a/src/crepe/api/AI.cpp +++ b/src/crepe/api/AI.cpp @@ -2,7 +2,7 @@ namespace crepe { -AI::AI(game_object_id_t id, double mass, double max_speed, double max_force) +AI::AI(game_object_id_t id, float mass, float max_speed, float max_force) : Component(id), mass(mass), max_speed(max_speed), diff --git a/src/crepe/api/AI.h b/src/crepe/api/AI.h index b755439..faeeba5 100644 --- a/src/crepe/api/AI.h +++ b/src/crepe/api/AI.h @@ -7,12 +7,51 @@ namespace crepe { class AI : public Component { public: - AI(game_object_id_t id, double mass, double max_speed, double max_force); + enum BehaviorType { + NONE = 0x00000, + SEEK = 0x00002, + FLEE = 0x00004, + ARRIVE = 0x00008, + PATH_FOLLOW = 0x00010, + }; public: - double mass; - double max_speed; - double max_force; + AI(game_object_id_t id, float mass, float max_speed, float max_force); + + bool on(BehaviorType behavior) const { return (flags & behavior) == behavior; } + void seek_on() { flags |= SEEK; } + void seek_off() { + if (on(SEEK)) flags ^= SEEK; + } + void flee_on() { flags |= FLEE; } + void flee_off() { + if (on(FLEE)) flags ^= FLEE; + } + void arrive_on() { flags |= ARRIVE; } + void arrive_off() { + if (on(ARRIVE)) flags ^= ARRIVE; + } + void path_follow_on() { flags |= PATH_FOLLOW; } + void path_follow_off() { + if (on(PATH_FOLLOW)) flags ^= PATH_FOLLOW; + } + +public: + float mass; + float max_speed; + float max_force; + + // The target to seek or arrive at + vec2 seek_target; + // The target to flee from + vec2 flee_target; + // The distance at which the entity will start to flee from the target + float square_flee_panic_distance = 100.0f * 100.0f; + // The deceleration rate for the arrive behavior (higher values will make the entity decelerate faster (less overshoot)) + float arrive_deceleration = 2.0f; + +private: + int flags = 0; }; } // namespace crepe diff --git a/src/crepe/system/AISystem.cpp b/src/crepe/system/AISystem.cpp index 012f4fa..12da3d9 100644 --- a/src/crepe/system/AISystem.cpp +++ b/src/crepe/system/AISystem.cpp @@ -1,6 +1,34 @@ +#include "../ComponentManager.h" + #include "AISystem.h" -#include using namespace crepe; -void AISystem::update() { std::cout << "AI System update" << std::endl; } +void AISystem::update() { + ComponentManager & mgr = this->component_manager; + RefVector ai_components = mgr.get_components_by_type(); + + for (AI & ai : ai_components) { + vec2 force = this->calculate(ai); + //... + } +} + +vec2 AISystem::calculate(AI & ai) { + vec2 force; + + if (ai.on(AI::BehaviorType::SEEK)) { + // Seek the target + } + if (ai.on(AI::BehaviorType::FLEE)) { + // Flee from the target + } + if (ai.on(AI::BehaviorType::ARRIVE)) { + // Arrive at the target + } + if (ai.on(AI::BehaviorType::PATH_FOLLOW)) { + // Follow the path + } + + return force; +} diff --git a/src/crepe/system/AISystem.h b/src/crepe/system/AISystem.h index 4138e01..eb8d08c 100644 --- a/src/crepe/system/AISystem.h +++ b/src/crepe/system/AISystem.h @@ -1,6 +1,9 @@ #pragma once +#include "api/AI.h" + #include "System.h" +#include "types.h" namespace crepe { @@ -9,6 +12,9 @@ public: using System::System; void update() override; + +private: + vec2 calculate(AI & ai); }; } // namespace crepe -- cgit v1.2.3 From 94d95cb13e76d6cd3ec892a7f0b2bab938a9ba6a Mon Sep 17 00:00:00 2001 From: max-001 Date: Wed, 4 Dec 2024 16:50:23 +0100 Subject: Extended Vector2 --- src/crepe/api/Vector2.h | 24 ++++++++ src/crepe/api/Vector2.hpp | 48 +++++++++++++++ src/test/Vector2Test.cpp | 148 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 220 insertions(+) diff --git a/src/crepe/api/Vector2.h b/src/crepe/api/Vector2.h index c278c87..bbcb932 100644 --- a/src/crepe/api/Vector2.h +++ b/src/crepe/api/Vector2.h @@ -66,6 +66,30 @@ struct Vector2 { //! Checks if this vector is not equal to another vector. bool operator!=(const Vector2 & other) const; + + //! Truncates the vector to a maximum length. + void truncate(T max); + + //! Normalizes the vector. + void normalize(); + + //! Returns the length of the vector. + T length() const; + + //! Returns the squared length of the vector. + T length_squared() const; + + //! Returns the dot product of this vector and another vector. + T dot(const Vector2 & other) const; + + //! Returns the distance between this vector and another vector. + T distance(const Vector2 & other) const; + + //! Returns the squared distance between this vector and another vector. + T distance_squared(const Vector2 & other) const; + + //! Returns the perpendicular vector to this vector. + Vector2 perpendicular() const; }; } // namespace crepe diff --git a/src/crepe/api/Vector2.hpp b/src/crepe/api/Vector2.hpp index cad15f8..ff53cb0 100644 --- a/src/crepe/api/Vector2.hpp +++ b/src/crepe/api/Vector2.hpp @@ -1,5 +1,7 @@ #pragma once +#include + #include "Vector2.h" namespace crepe { @@ -115,4 +117,50 @@ bool Vector2::operator!=(const Vector2 & other) const { return !(*this == other); } +template +void Vector2::truncate(T max) { + if (length() > max) { + normalize(); + *this *= max; + } +} + +template +void Vector2::normalize() { + T len = length(); + if (len > 0) { + *this /= len; + } +} + +template +T Vector2::length() const { + return std::sqrt(x * x + y * y); +} + +template +T Vector2::length_squared() const { + return x * x + y * y; +} + +template +T Vector2::dot(const Vector2 & other) const { + return x * other.x + y * other.y; +} + +template +T Vector2::distance(const Vector2 & other) const { + return (*this - other).length(); +} + +template +T Vector2::distance_squared(const Vector2 & other) const { + return (*this - other).length_squared(); +} + +template +Vector2 Vector2::perpendicular() const { + return {-y, x}; +} + } // namespace crepe diff --git a/src/test/Vector2Test.cpp b/src/test/Vector2Test.cpp index 17bca41..1e21af9 100644 --- a/src/test/Vector2Test.cpp +++ b/src/test/Vector2Test.cpp @@ -382,3 +382,151 @@ TEST_F(Vector2Test, NotEquals) { EXPECT_FALSE(long_vec1 != long_vec1); EXPECT_TRUE(long_vec1 != long_vec2); } + +TEST_F(Vector2Test, Truncate) { + Vector2 vec = {3, 4}; + vec.truncate(3); + EXPECT_EQ(vec.x, 0); + EXPECT_EQ(vec.y, 0); + + Vector2 vec2 = {3.0, 4.0}; + vec2.truncate(3.0); + EXPECT_FLOAT_EQ(vec2.x, 1.8); + EXPECT_FLOAT_EQ(vec2.y, 2.4); + + Vector2 vec3 = {3, 4}; + vec3.truncate(3); + EXPECT_EQ(vec3.x, 0); + EXPECT_EQ(vec3.y, 0); + + Vector2 vec4 = {3.0f, 4.0f}; + vec4.truncate(3.0f); + EXPECT_FLOAT_EQ(vec4.x, 1.8f); + EXPECT_FLOAT_EQ(vec4.y, 2.4f); +} + +TEST_F(Vector2Test, Normalize) { + Vector2 vec = {3, 4}; + vec.normalize(); + EXPECT_EQ(vec.x, 0); + EXPECT_EQ(vec.y, 0); + + Vector2 vec2 = {3.0, 4.0}; + vec2.normalize(); + EXPECT_FLOAT_EQ(vec2.x, 0.6); + EXPECT_FLOAT_EQ(vec2.y, 0.8); + + Vector2 vec3 = {3, 4}; + vec3.normalize(); + EXPECT_EQ(vec3.x, 0); + EXPECT_EQ(vec3.y, 0); + + Vector2 vec4 = {3.0f, 4.0f}; + vec4.normalize(); + EXPECT_FLOAT_EQ(vec4.x, 0.6f); + EXPECT_FLOAT_EQ(vec4.y, 0.8f); +} + +TEST_F(Vector2Test, Length) { + Vector2 vec = {3, 4}; + EXPECT_EQ(vec.length(), 5); + + Vector2 vec2 = {3.0, 4.0}; + EXPECT_FLOAT_EQ(vec2.length(), 5.0); + + Vector2 vec3 = {3, 4}; + EXPECT_EQ(vec3.length(), 5); + + Vector2 vec4 = {3.0f, 4.0f}; + EXPECT_FLOAT_EQ(vec4.length(), 5.0f); +} + +TEST_F(Vector2Test, LengthSquared) { + Vector2 vec = {3, 4}; + EXPECT_EQ(vec.length_squared(), 25); + + Vector2 vec2 = {3.0, 4.0}; + EXPECT_FLOAT_EQ(vec2.length_squared(), 25.0); + + Vector2 vec3 = {3, 4}; + EXPECT_EQ(vec3.length_squared(), 25); + + Vector2 vec4 = {3.0f, 4.0f}; + EXPECT_FLOAT_EQ(vec4.length_squared(), 25.0f); +} + +TEST_F(Vector2Test, Dot) { + Vector2 vec1 = {3, 4}; + Vector2 vec2 = {5, 6}; + EXPECT_EQ(vec1.dot(vec2), 39); + + Vector2 vec3 = {3.0, 4.0}; + Vector2 vec4 = {5.0, 6.0}; + EXPECT_FLOAT_EQ(vec3.dot(vec4), 39.0); + + Vector2 vec5 = {3, 4}; + Vector2 vec6 = {5, 6}; + EXPECT_EQ(vec5.dot(vec6), 39); + + Vector2 vec7 = {3.0f, 4.0f}; + Vector2 vec8 = {5.0f, 6.0f}; + EXPECT_FLOAT_EQ(vec7.dot(vec8), 39.0f); +} + +TEST_F(Vector2Test, Distance) { + Vector2 vec1 = {1, 1}; + Vector2 vec2 = {4, 5}; + EXPECT_EQ(vec1.distance(vec2), 5); + + Vector2 vec3 = {1.0, 1.0}; + Vector2 vec4 = {4.0, 5.0}; + EXPECT_FLOAT_EQ(vec3.distance(vec4), 5.0); + + Vector2 vec5 = {1, 1}; + Vector2 vec6 = {4, 5}; + EXPECT_EQ(vec5.distance(vec6), 5); + + Vector2 vec7 = {1.0f, 1.0f}; + Vector2 vec8 = {4.0f, 5.0f}; + EXPECT_FLOAT_EQ(vec7.distance(vec8), 5.0f); +} + +TEST_F(Vector2Test, DistanceSquared) { + Vector2 vec1 = {3, 4}; + Vector2 vec2 = {5, 6}; + EXPECT_EQ(vec1.distance_squared(vec2), 8); + + Vector2 vec3 = {3.0, 4.0}; + Vector2 vec4 = {5.0, 6.0}; + EXPECT_FLOAT_EQ(vec3.distance_squared(vec4), 8.0); + + Vector2 vec5 = {3, 4}; + Vector2 vec6 = {5, 6}; + EXPECT_EQ(vec5.distance_squared(vec6), 8); + + Vector2 vec7 = {3.0f, 4.0f}; + Vector2 vec8 = {5.0f, 6.0f}; + EXPECT_FLOAT_EQ(vec7.distance_squared(vec8), 8.0f); +} + +TEST_F(Vector2Test, Perpendicular) { + Vector2 vec = {3, 4}; + Vector2 result = vec.perpendicular(); + EXPECT_EQ(result.x, -4); + EXPECT_EQ(result.y, 3); + + Vector2 vec2 = {3.0, 4.0}; + Vector2 result2 = vec2.perpendicular(); + EXPECT_FLOAT_EQ(result2.x, -4.0); + EXPECT_FLOAT_EQ(result2.y, 3.0); + + Vector2 vec3 = {3, 4}; + Vector2 result3 = vec3.perpendicular(); + EXPECT_EQ(result3.x, -4); + EXPECT_EQ(result3.y, 3); + + Vector2 vec4 = {3.0f, 4.0f}; + Vector2 result4 = vec4.perpendicular(); + EXPECT_FLOAT_EQ(result4.x, -4.0f); + EXPECT_FLOAT_EQ(result4.y, 3.0f); +} -- cgit v1.2.3 From e303bd4c54b0edbcd1819a47a5d8aaef88211a09 Mon Sep 17 00:00:00 2001 From: max-001 Date: Wed, 4 Dec 2024 17:27:30 +0100 Subject: Increased gameloop time --- src/crepe/api/LoopManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/crepe/api/LoopManager.cpp b/src/crepe/api/LoopManager.cpp index cd602d8..46831e8 100644 --- a/src/crepe/api/LoopManager.cpp +++ b/src/crepe/api/LoopManager.cpp @@ -54,8 +54,8 @@ void LoopManager::loop() { timer.enforce_frame_rate(); - // Stop the game after 5 seconds, for testing purposes - if (timer.get_current_time() > 5) { + // Stop the game after 10 seconds, for testing purposes + if (timer.get_current_time() > 10) { this->game_running = false; } } -- cgit v1.2.3 From 121387ba92a23d6f17b36331d25757abc899f7d2 Mon Sep 17 00:00:00 2001 From: max-001 Date: Wed, 4 Dec 2024 17:27:51 +0100 Subject: Implemeted seek behavior --- src/crepe/api/AI.h | 3 +++ src/crepe/system/AISystem.cpp | 45 +++++++++++++++++++++++++++++++++++++++++-- src/crepe/system/AISystem.h | 3 +++ src/example/AITest.cpp | 4 ++-- 4 files changed, 51 insertions(+), 4 deletions(-) diff --git a/src/crepe/api/AI.h b/src/crepe/api/AI.h index faeeba5..242ff89 100644 --- a/src/crepe/api/AI.h +++ b/src/crepe/api/AI.h @@ -51,6 +51,9 @@ public: float arrive_deceleration = 2.0f; private: + vec2 velocity; + friend class AISystem; + int flags = 0; }; diff --git a/src/crepe/system/AISystem.cpp b/src/crepe/system/AISystem.cpp index 12da3d9..9029f32 100644 --- a/src/crepe/system/AISystem.cpp +++ b/src/crepe/system/AISystem.cpp @@ -1,4 +1,7 @@ #include "../ComponentManager.h" +#include "api/LoopTimer.h" +#include "api/Transform.h" +#include "types.h" #include "AISystem.h" @@ -8,9 +11,19 @@ void AISystem::update() { ComponentManager & mgr = this->component_manager; RefVector ai_components = mgr.get_components_by_type(); + double dt = LoopTimer::get_instance().get_delta_time(); + for (AI & ai : ai_components) { vec2 force = this->calculate(ai); - //... + vec2 acceleration = force / ai.mass; + ai.velocity += acceleration * dt; + ai.velocity.truncate(ai.max_speed); + + // Update the position + RefVector transforms + = mgr.get_components_by_id(ai.game_object_id); + Transform & transform = transforms.front().get(); + transform.position += ai.velocity * dt; } } @@ -18,7 +31,11 @@ vec2 AISystem::calculate(AI & ai) { vec2 force; if (ai.on(AI::BehaviorType::SEEK)) { - // Seek the target + vec2 force_to_add = this->seek(ai); + + if (!this->accumulate_force(force, force_to_add)) { + return force; + } } if (ai.on(AI::BehaviorType::FLEE)) { // Flee from the target @@ -32,3 +49,27 @@ vec2 AISystem::calculate(AI & ai) { return force; } + +bool AISystem::accumulate_force(vec2 & running_total, vec2 force_to_add) { + double magnitude_remaining = running_total.length(); + double magnitude_to_add = force_to_add.length(); + + if (magnitude_remaining + magnitude_to_add > 0) { + running_total += force_to_add; + return true; + } + + return false; +} + +vec2 AISystem::seek(const AI & ai) { + ComponentManager & mgr = this->component_manager; + RefVector transforms = mgr.get_components_by_id(ai.game_object_id); + Transform & transform = transforms.front().get(); + + vec2 desired_velocity = ai.seek_target - transform.position; + desired_velocity.normalize(); + desired_velocity *= ai.max_speed; + + return desired_velocity - ai.velocity; +} diff --git a/src/crepe/system/AISystem.h b/src/crepe/system/AISystem.h index eb8d08c..5e94ccb 100644 --- a/src/crepe/system/AISystem.h +++ b/src/crepe/system/AISystem.h @@ -15,6 +15,9 @@ public: private: vec2 calculate(AI & ai); + bool accumulate_force(vec2 & running_total, vec2 force_to_add); + + vec2 seek(const AI & ai); }; } // namespace crepe diff --git a/src/example/AITest.cpp b/src/example/AITest.cpp index 1c4633f..341e1de 100644 --- a/src/example/AITest.cpp +++ b/src/example/AITest.cpp @@ -18,13 +18,13 @@ public: void load_scene() override { ComponentManager & mgr = this->component_manager; - GameObject game_object1 = mgr.new_object("", "", vec2{0, 0}, 0, 1); + GameObject game_object1 = mgr.new_object("", "", vec2{250, 250}, 0, 1); GameObject game_object2 = mgr.new_object("", "", vec2{0, 0}, 0, 1); Texture img = Texture("asset/texture/test_ap43.png"); game_object1.add_component(img, Color::MAGENTA, Sprite::FlipSettings{false, false}, 1, 1, 195); - game_object1.add_component(1, 1, 1); + game_object1.add_component(1, 200, 200).seek_on(); game_object2.add_component(Color::WHITE, ivec2{1080, 720}, vec2{1036, 780}, 1.0f); -- cgit v1.2.3 From 84c5900445cc0ce8ab2fe8befc5050ff99def01e Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Wed, 4 Dec 2024 21:47:42 +0100 Subject: remove copy/move constructor/operator from base Resource --- src/crepe/Resource.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/crepe/Resource.h b/src/crepe/Resource.h index a2d65df..eceb15b 100644 --- a/src/crepe/Resource.h +++ b/src/crepe/Resource.h @@ -19,6 +19,11 @@ class Resource { public: Resource(const Asset & src); virtual ~Resource() = default; + + Resource(const Resource &) = delete; + Resource(Resource &&) = delete; + Resource & operator=(const Resource &) = delete; + Resource & operator=(Resource &&) = delete; }; } // namespace crepe -- cgit v1.2.3 From 803771dfc4fb5b9144d551a91b77a5a4ec8f21b6 Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Thu, 5 Dec 2024 09:51:36 +0100 Subject: add unit test --- src/test/ResourceManagerTest.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/test/ResourceManagerTest.cpp b/src/test/ResourceManagerTest.cpp index b6be3c0..0789ef0 100644 --- a/src/test/ResourceManagerTest.cpp +++ b/src/test/ResourceManagerTest.cpp @@ -17,6 +17,10 @@ class ResourceManagerTest : public Test { public: ResourceManager resource_manager{mediator}; + class Unrelated : public Resource { + using Resource::Resource; + }; + Asset asset_a{"asset/texture/img.png"}; Asset asset_b{"asset/texture/ERROR.png"}; @@ -69,3 +73,14 @@ TEST_F(ResourceManagerTest, Persistent) { resource_manager.clear_all(); EXPECT_EQ(TestResource::instances, 0); } + +TEST_F(ResourceManagerTest, UnmatchedType) { + EXPECT_NO_THROW({ + resource_manager.get(asset_a); + }); + + EXPECT_THROW({ + resource_manager.get(asset_a); + }, runtime_error); +} + -- cgit v1.2.3 From 1e9e564f3806d07c7b0dc445c4ae2e738350fc83 Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Thu, 5 Dec 2024 17:12:56 +0100 Subject: `make format` --- src/crepe/api/AudioSource.h | 3 +-- src/crepe/facade/SoundContext.cpp | 1 - src/crepe/facade/SoundContext.h | 3 +-- src/crepe/facade/SoundHandle.h | 3 +-- src/crepe/system/AudioSystem.cpp | 4 +--- src/test/ResourceManagerTest.cpp | 9 ++------- 6 files changed, 6 insertions(+), 17 deletions(-) diff --git a/src/crepe/api/AudioSource.h b/src/crepe/api/AudioSource.h index 7c1f161..b20e490 100644 --- a/src/crepe/api/AudioSource.h +++ b/src/crepe/api/AudioSource.h @@ -1,8 +1,8 @@ #pragma once #include "../Component.h" -#include "../types.h" #include "../facade/SoundHandle.h" +#include "../types.h" #include "Asset.h" #include "GameObject.h" @@ -69,7 +69,6 @@ private: //! \} //! This source's voice handle SoundHandle voice{}; - }; } // namespace crepe diff --git a/src/crepe/facade/SoundContext.cpp b/src/crepe/facade/SoundContext.cpp index d18afc6..b1f8cb3 100644 --- a/src/crepe/facade/SoundContext.cpp +++ b/src/crepe/facade/SoundContext.cpp @@ -34,4 +34,3 @@ void SoundContext::set_volume(const SoundHandle & handle, float volume) { void SoundContext::set_loop(const SoundHandle & handle, bool loop) { this->engine.setLooping(this->registry[handle], loop); } - diff --git a/src/crepe/facade/SoundContext.h b/src/crepe/facade/SoundContext.h index 102f928..d986c59 100644 --- a/src/crepe/facade/SoundContext.h +++ b/src/crepe/facade/SoundContext.h @@ -4,8 +4,8 @@ #include "../api/Config.h" -#include "SoundHandle.h" #include "Sound.h" +#include "SoundHandle.h" namespace crepe { @@ -76,7 +76,6 @@ private: std::unordered_map registry; //! Unique handle counter SoundHandle next_handle = 0; - }; } // namespace crepe diff --git a/src/crepe/facade/SoundHandle.h b/src/crepe/facade/SoundHandle.h index 131d28c..b7925fc 100644 --- a/src/crepe/facade/SoundHandle.h +++ b/src/crepe/facade/SoundHandle.h @@ -9,5 +9,4 @@ namespace crepe { */ typedef size_t SoundHandle; -} - +} // namespace crepe diff --git a/src/crepe/system/AudioSystem.cpp b/src/crepe/system/AudioSystem.cpp index c1cde8b..b2c1dc6 100644 --- a/src/crepe/system/AudioSystem.cpp +++ b/src/crepe/system/AudioSystem.cpp @@ -58,8 +58,6 @@ void AudioSystem::update_last(AudioSource & component) { } SoundContext & AudioSystem::get_context() { - if (this->context == nullptr) - this->context = make_unique(); + if (this->context == nullptr) this->context = make_unique(); return *this->context.get(); } - diff --git a/src/test/ResourceManagerTest.cpp b/src/test/ResourceManagerTest.cpp index 0789ef0..44a5921 100644 --- a/src/test/ResourceManagerTest.cpp +++ b/src/test/ResourceManagerTest.cpp @@ -75,12 +75,7 @@ TEST_F(ResourceManagerTest, Persistent) { } TEST_F(ResourceManagerTest, UnmatchedType) { - EXPECT_NO_THROW({ - resource_manager.get(asset_a); - }); + EXPECT_NO_THROW({ resource_manager.get(asset_a); }); - EXPECT_THROW({ - resource_manager.get(asset_a); - }, runtime_error); + EXPECT_THROW({ resource_manager.get(asset_a); }, runtime_error); } - -- cgit v1.2.3 From e617b4f002638e37dbe4d2ce13849728e7e82c78 Mon Sep 17 00:00:00 2001 From: max-001 Date: Thu, 5 Dec 2024 17:26:41 +0100 Subject: Used Mediator --- src/crepe/system/AISystem.cpp | 9 ++++++--- src/example/AITest.cpp | 6 ++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/crepe/system/AISystem.cpp b/src/crepe/system/AISystem.cpp index 9029f32..c67d5ea 100644 --- a/src/crepe/system/AISystem.cpp +++ b/src/crepe/system/AISystem.cpp @@ -1,6 +1,7 @@ -#include "../ComponentManager.h" +#include "manager/ComponentManager.h" #include "api/LoopTimer.h" #include "api/Transform.h" +#include "manager/Mediator.h" #include "types.h" #include "AISystem.h" @@ -8,7 +9,8 @@ using namespace crepe; void AISystem::update() { - ComponentManager & mgr = this->component_manager; + const Mediator & mediator = this->mediator; + ComponentManager & mgr = mediator.component_manager; RefVector ai_components = mgr.get_components_by_type(); double dt = LoopTimer::get_instance().get_delta_time(); @@ -63,7 +65,8 @@ bool AISystem::accumulate_force(vec2 & running_total, vec2 force_to_add) { } vec2 AISystem::seek(const AI & ai) { - ComponentManager & mgr = this->component_manager; + const Mediator & mediator = this->mediator; + ComponentManager & mgr = mediator.component_manager; RefVector transforms = mgr.get_components_by_id(ai.game_object_id); Transform & transform = transforms.front().get(); diff --git a/src/example/AITest.cpp b/src/example/AITest.cpp index 341e1de..71aacb2 100644 --- a/src/example/AITest.cpp +++ b/src/example/AITest.cpp @@ -1,6 +1,7 @@ +#include #include #include -#include +#include #include #include #include @@ -16,7 +17,8 @@ using namespace std; class Scene1 : public Scene { public: void load_scene() override { - ComponentManager & mgr = this->component_manager; + Mediator & mediator = this->mediator; + ComponentManager & mgr = mediator.component_manager; GameObject game_object1 = mgr.new_object("", "", vec2{250, 250}, 0, 1); GameObject game_object2 = mgr.new_object("", "", vec2{0, 0}, 0, 1); -- cgit v1.2.3 From 6b45759e570bcaafc167e74ac46c8ffe05efa66e Mon Sep 17 00:00:00 2001 From: max-001 Date: Thu, 5 Dec 2024 18:28:15 +0100 Subject: Make format --- src/crepe/system/AISystem.cpp | 2 +- src/example/AITest.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/crepe/system/AISystem.cpp b/src/crepe/system/AISystem.cpp index c67d5ea..3c61c78 100644 --- a/src/crepe/system/AISystem.cpp +++ b/src/crepe/system/AISystem.cpp @@ -1,6 +1,6 @@ -#include "manager/ComponentManager.h" #include "api/LoopTimer.h" #include "api/Transform.h" +#include "manager/ComponentManager.h" #include "manager/Mediator.h" #include "types.h" diff --git a/src/example/AITest.cpp b/src/example/AITest.cpp index 71aacb2..841b195 100644 --- a/src/example/AITest.cpp +++ b/src/example/AITest.cpp @@ -1,7 +1,5 @@ -#include #include #include -#include #include #include #include @@ -10,6 +8,8 @@ #include #include #include +#include +#include using namespace crepe; using namespace std; -- cgit v1.2.3 From 9cd9e3674d8b1c326c81b7896b9254408fb19972 Mon Sep 17 00:00:00 2001 From: max-001 Date: Fri, 6 Dec 2024 08:42:49 +0100 Subject: Added some explanation to Vector2 --- src/crepe/api/Vector2.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/crepe/api/Vector2.h b/src/crepe/api/Vector2.h index bbcb932..bf9d124 100644 --- a/src/crepe/api/Vector2.h +++ b/src/crepe/api/Vector2.h @@ -70,7 +70,7 @@ struct Vector2 { //! Truncates the vector to a maximum length. void truncate(T max); - //! Normalizes the vector. + //! Normalizes the vector (resulting in vector with a length of 1). void normalize(); //! Returns the length of the vector. @@ -79,7 +79,7 @@ struct Vector2 { //! Returns the squared length of the vector. T length_squared() const; - //! Returns the dot product of this vector and another vector. + //! Returns the dot product (inwendig product) of this vector and another vector. T dot(const Vector2 & other) const; //! Returns the distance between this vector and another vector. -- cgit v1.2.3 From cbd7663b7f9cf7bf2b498f54b5d86c2ca37a5188 Mon Sep 17 00:00:00 2001 From: max-001 Date: Fri, 6 Dec 2024 09:56:54 +0100 Subject: Modified game loop --- src/crepe/api/LoopManager.cpp | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/crepe/api/LoopManager.cpp b/src/crepe/api/LoopManager.cpp index 2f8a0a7..90308a7 100644 --- a/src/crepe/api/LoopManager.cpp +++ b/src/crepe/api/LoopManager.cpp @@ -40,6 +40,7 @@ void LoopManager::fixed_update() { EventManager & ev = this->mediator.event_manager; ev.dispatch_events(); this->get_system().update(); + this->get_system().update(); this->get_system().update(); this->get_system().update(); } @@ -50,22 +51,17 @@ void LoopManager::loop() { while (game_running) { timer.update(); - + while (timer.get_lag() >= timer.get_fixed_delta_time()) { this->process_input(); this->fixed_update(); timer.advance_fixed_update(); } - + this->update(); this->render(); timer.enforce_frame_rate(); - - // Stop the game after 10 seconds, for testing purposes - if (timer.get_current_time() > 10) { - this->game_running = false; - } } } @@ -75,7 +71,6 @@ void LoopManager::setup() { this->scene_manager.load_next_scene(); timer.start(); timer.set_fps(200); - this->scene_manager.load_next_scene(); } void LoopManager::render() { @@ -84,7 +79,4 @@ void LoopManager::render() { this->get_system().update(); } -void LoopManager::update() { - this->get_system().update(); - this->get_system().update(); -} +void LoopManager::update() { this->get_system().update(); } -- cgit v1.2.3 From 93893dbe710d864d5865f361f9a8a8f8f85b94f6 Mon Sep 17 00:00:00 2001 From: max-001 Date: Fri, 6 Dec 2024 09:57:30 +0100 Subject: Make format --- mwe/events/include/event.h | 2 +- src/crepe/api/Rigidbody.h | 1 - src/crepe/api/Script.h | 2 +- src/crepe/system/CollisionSystem.cpp | 40 +++++++-------- src/crepe/system/CollisionSystem.h | 6 +-- src/example/game.cpp | 98 +++++++++++++++++------------------- src/test/CollisionTest.cpp | 6 +-- src/test/Profiling.cpp | 6 +-- 8 files changed, 76 insertions(+), 85 deletions(-) diff --git a/mwe/events/include/event.h b/mwe/events/include/event.h index ee1bf52..e1b220b 100644 --- a/mwe/events/include/event.h +++ b/mwe/events/include/event.h @@ -148,7 +148,7 @@ private: }; class ShutDownEvent : public Event { public: - ShutDownEvent() : Event("ShutDownEvent") {}; + ShutDownEvent() : Event("ShutDownEvent"){}; REGISTER_EVENT_TYPE(ShutDownEvent) diff --git a/src/crepe/api/Rigidbody.h b/src/crepe/api/Rigidbody.h index b0a24f7..722a665 100644 --- a/src/crepe/api/Rigidbody.h +++ b/src/crepe/api/Rigidbody.h @@ -7,7 +7,6 @@ #include "types.h" - namespace crepe { /** diff --git a/src/crepe/api/Script.h b/src/crepe/api/Script.h index 1474a09..fa83152 100644 --- a/src/crepe/api/Script.h +++ b/src/crepe/api/Script.h @@ -3,10 +3,10 @@ #include #include "../manager/EventManager.h" -#include "system/CollisionSystem.h" #include "../manager/Mediator.h" #include "../types.h" #include "../util/OptionalRef.h" +#include "system/CollisionSystem.h" namespace crepe { diff --git a/src/crepe/system/CollisionSystem.cpp b/src/crepe/system/CollisionSystem.cpp index f75d0ad..da9e3af 100644 --- a/src/crepe/system/CollisionSystem.cpp +++ b/src/crepe/system/CollisionSystem.cpp @@ -6,6 +6,8 @@ #include #include +#include "../manager/ComponentManager.h" +#include "../manager/EventManager.h" #include "api/BoxCollider.h" #include "api/CircleCollider.h" #include "api/Event.h" @@ -13,8 +15,6 @@ #include "api/Rigidbody.h" #include "api/Transform.h" #include "api/Vector2.h" -#include "../manager/ComponentManager.h" -#include "../manager/EventManager.h" #include "Collider.h" #include "CollisionSystem.h" @@ -27,17 +27,14 @@ void CollisionSystem::update() { std::vector all_colliders; game_object_id_t id = 0; ComponentManager & mgr = this->mediator.component_manager; - RefVector rigidbodies - = mgr.get_components_by_type(); + RefVector rigidbodies = mgr.get_components_by_type(); // Collisions can only happen on object with a rigidbody for (Rigidbody & rigidbody : rigidbodies) { if (!rigidbody.active) continue; id = rigidbody.game_object_id; - Transform & transform - = mgr.get_components_by_id(id).front().get(); + Transform & transform = mgr.get_components_by_id(id).front().get(); // Check if the boxcollider is active and has the same id as the rigidbody. - RefVector boxcolliders - = mgr.get_components_by_type(); + RefVector boxcolliders = mgr.get_components_by_type(); for (BoxCollider & boxcollider : boxcolliders) { if (boxcollider.game_object_id != id) continue; if (!boxcollider.active) continue; @@ -159,7 +156,7 @@ CollisionSystem::collision_handler(CollisionInternal & data1, CollisionInternal vec2 collider_pos2 = this->get_current_position(collider2.offset, data2.transform, data2.rigidbody); resolution = this->get_circle_box_resolution(collider2, collider1, collider_pos2, - collider_pos1,true); + collider_pos1, true); break; } case CollisionInternalType::CIRCLE_CIRCLE: { @@ -185,7 +182,7 @@ CollisionSystem::collision_handler(CollisionInternal & data1, CollisionInternal vec2 collider_pos2 = this->get_current_position(collider2.offset, data2.transform, data2.rigidbody); resolution = this->get_circle_box_resolution(collider1, collider2, collider_pos1, - collider_pos2,false); + collider_pos2, false); break; } } @@ -261,7 +258,6 @@ vec2 CollisionSystem::get_circle_circle_resolution(const CircleCollider & circle // Normalize the delta vector to get the collision direction vec2 collision_normal = delta / distance; - // Compute the resolution vector vec2 resolution = -collision_normal * penetration_depth; @@ -272,7 +268,8 @@ vec2 CollisionSystem::get_circle_circle_resolution(const CircleCollider & circle vec2 CollisionSystem::get_circle_box_resolution(const CircleCollider & circle_collider, const BoxCollider & box_collider, const vec2 & circle_position, - const vec2 & box_position,bool inverse) const { + const vec2 & box_position, + bool inverse) const { vec2 delta = circle_position - box_position; // Compute half-dimensions of the box @@ -294,7 +291,7 @@ vec2 CollisionSystem::get_circle_box_resolution(const CircleCollider & circle_co // Compute penetration depth float penetration_depth = circle_collider.radius - distance; - if(inverse) collision_normal = -collision_normal; + if (inverse) collision_normal = -collision_normal; // Compute the resolution vector vec2 resolution = collision_normal * penetration_depth; @@ -311,8 +308,7 @@ void CollisionSystem::determine_collision_handler(CollisionInfo & info) { // Call collision event for user CollisionEvent data(info); EventManager & emgr = this->mediator.event_manager; - emgr.trigger_event( - data, info.this_collider.game_object_id); + emgr.trigger_event(data, info.this_collider.game_object_id); } void CollisionSystem::static_collision_handler(CollisionInfo & info) { @@ -389,14 +385,14 @@ CollisionSystem::gather_collisions(std::vector & colliders) { bool CollisionSystem::have_common_layer(const std::set & layers1, const std::set & layers2) { - + // Check if any number is equal in the layers for (int num : layers1) { - if (layers2.contains(num)) { - // Common layer found - return true; - break; - } + if (layers2.contains(num)) { + // Common layer found + return true; + break; + } } // No common layer found return false; @@ -512,7 +508,7 @@ bool CollisionSystem::get_box_circle_collision(const BoxCollider & box1, float distance_squared = distance_x * distance_x + distance_y * distance_y; // Compare distance squared with the square of the circle's radius - return distance_squared <= circle2.radius * circle2.radius-1; + return distance_squared <= circle2.radius * circle2.radius - 1; } bool CollisionSystem::get_circle_circle_collision(const CircleCollider & circle1, diff --git a/src/crepe/system/CollisionSystem.h b/src/crepe/system/CollisionSystem.h index b978dbb..eee582b 100644 --- a/src/crepe/system/CollisionSystem.h +++ b/src/crepe/system/CollisionSystem.h @@ -6,11 +6,11 @@ #include "api/BoxCollider.h" #include "api/CircleCollider.h" +#include "api/Event.h" #include "api/Metadata.h" #include "api/Rigidbody.h" #include "api/Transform.h" #include "api/Vector2.h" -#include "api/Event.h" #include "Collider.h" #include "System.h" @@ -183,8 +183,8 @@ private: */ vec2 get_circle_box_resolution(const CircleCollider & circle_collider, const BoxCollider & box_collider, - const vec2 & circle_position, - const vec2 & box_position,bool inverse) const; + const vec2 & circle_position, const vec2 & box_position, + bool inverse) const; /** * \brief Determines the appropriate collision handler for a collision. diff --git a/src/example/game.cpp b/src/example/game.cpp index be756bd..2b4e46f 100644 --- a/src/example/game.cpp +++ b/src/example/game.cpp @@ -1,6 +1,6 @@ #include "api/CircleCollider.h" -#include "manager/ComponentManager.h" #include "api/Scene.h" +#include "manager/ComponentManager.h" #include "manager/Mediator.h" #include #include @@ -28,66 +28,64 @@ class MyScript1 : public Script { bool keypressed(const KeyPressEvent & test) { Log::logf("Box script keypressed()"); switch (test.key) { - case Keycode::A: - { + case Keycode::A: { Transform & tf = this->get_component(); tf.position.x -= 1; break; } - case Keycode::W: - { + case Keycode::W: { Transform & tf = this->get_component(); tf.position.y -= 1; break; } - case Keycode::S: - { + case Keycode::S: { Transform & tf = this->get_component(); tf.position.y += 1; break; } - case Keycode::D: - { + case Keycode::D: { Transform & tf = this->get_component(); tf.position.x += 1; break; } - case Keycode::E: - { - if(flip){ + case Keycode::E: { + if (flip) { flip = false; this->get_component().active = true; this->get_components()[0].get().active = true; this->get_component().active = false; this->get_components()[1].get().active = false; - } - else { + } else { flip = true; this->get_component().active = false; this->get_components()[0].get().active = false; this->get_component().active = true; this->get_components()[1].get().active = true; } - - + //add collider switch break; } + case Keycode::Q: { + throw "Test"; + break; + } default: - break; + break; } return false; - } + } void init() { Log::logf("init"); - subscribe([this](const CollisionEvent & ev) -> bool { return this->oncollision(ev); }); - subscribe([this](const KeyPressEvent & ev) -> bool { return this->keypressed(ev); }); + subscribe( + [this](const CollisionEvent & ev) -> bool { return this->oncollision(ev); }); + subscribe( + [this](const KeyPressEvent & ev) -> bool { return this->keypressed(ev); }); } void update() { // Retrieve component from the same GameObject this script is on } - }; class MyScript2 : public Script { @@ -99,74 +97,68 @@ class MyScript2 : public Script { bool keypressed(const KeyPressEvent & test) { Log::logf("Box script keypressed()"); switch (test.key) { - case Keycode::LEFT: - { + case Keycode::LEFT: { Transform & tf = this->get_component(); tf.position.x -= 1; break; } - case Keycode::UP: - { + case Keycode::UP: { Transform & tf = this->get_component(); tf.position.y -= 1; break; } - case Keycode::DOWN: - { + case Keycode::DOWN: { Transform & tf = this->get_component(); tf.position.y += 1; break; } - case Keycode::RIGHT: - { + case Keycode::RIGHT: { Transform & tf = this->get_component(); tf.position.x += 1; break; } - case Keycode::PAUSE: - { - if(flip){ + case Keycode::PAUSE: { + if (flip) { flip = false; this->get_component().active = true; this->get_components()[0].get().active = true; this->get_component().active = false; this->get_components()[1].get().active = false; - } - else { + } else { flip = true; this->get_component().active = false; this->get_components()[0].get().active = false; this->get_component().active = true; this->get_components()[1].get().active = true; } - - + //add collider switch break; } default: - break; + break; } return false; - } + } void init() { Log::logf("init"); - subscribe([this](const CollisionEvent & ev) -> bool { return this->oncollision(ev); }); - subscribe([this](const KeyPressEvent & ev) -> bool { return this->keypressed(ev); }); + subscribe( + [this](const CollisionEvent & ev) -> bool { return this->oncollision(ev); }); + subscribe( + [this](const KeyPressEvent & ev) -> bool { return this->keypressed(ev); }); } void update() { // Retrieve component from the same GameObject this script is on } - }; class ConcreteScene1 : public Scene { public: using Scene::Scene; - + void load_scene() { - + Mediator & m = this->mediator; ComponentManager & mgr = m.component_manager; Color color(0, 0, 0, 255); @@ -195,7 +187,10 @@ public: vec2{world_collider, world_collider}); // Left world.add_component(vec2{screen_size_width / 2 + world_collider / 2, 0}, vec2{world_collider, world_collider}); // right - world.add_component(Color::WHITE, ivec2{static_cast(screen_size_width), static_cast(screen_size_height)}, vec2{screen_size_width, screen_size_height}, 1.0f); + world.add_component( + Color::WHITE, + ivec2{static_cast(screen_size_width), static_cast(screen_size_height)}, + vec2{screen_size_width, screen_size_height}, 1.0f); GameObject game_object1 = mgr.new_object( "Name", "Tag", vec2{screen_size_width / 2, screen_size_height / 2}, 0, 1); @@ -219,10 +214,10 @@ public: //add circle with cirlcecollider deactiveated game_object1.add_component(vec2{0, 0}, 10).active = false; auto img2 = Texture("asset/texture/circle.png"); - game_object1.add_component(img2, color, Sprite::FlipSettings{false, false}, 1, - 1, 20).active = false; - - + game_object1 + .add_component(img2, color, Sprite::FlipSettings{false, false}, 1, 1, 20) + .active + = false; GameObject game_object2 = mgr.new_object( "Name", "Tag", vec2{screen_size_width / 2, screen_size_height / 2}, 0, 1); @@ -246,9 +241,10 @@ public: //add circle with cirlcecollider deactiveated game_object2.add_component(vec2{0, 0}, 10).active = false; auto img4 = Texture("asset/texture/circle.png"); - game_object2.add_component(img4, color, Sprite::FlipSettings{false, false}, 1, - 1, 20).active = false; - + game_object2 + .add_component(img4, color, Sprite::FlipSettings{false, false}, 1, 1, 20) + .active + = false; } string get_name() const { return "scene1"; } diff --git a/src/test/CollisionTest.cpp b/src/test/CollisionTest.cpp index a683b1f..dd45eb6 100644 --- a/src/test/CollisionTest.cpp +++ b/src/test/CollisionTest.cpp @@ -7,14 +7,14 @@ #define private public #define protected public -#include -#include #include -#include #include #include #include #include +#include +#include +#include #include #include #include diff --git a/src/test/Profiling.cpp b/src/test/Profiling.cpp index 91be769..f091d9d 100644 --- a/src/test/Profiling.cpp +++ b/src/test/Profiling.cpp @@ -9,14 +9,14 @@ #define private public #define protected public -#include #include -#include #include #include #include #include #include +#include +#include #include #include #include @@ -162,7 +162,7 @@ TEST_F(Profiling, Profiling_2) { .body_type = Rigidbody::BodyType::STATIC, }); gameobject.add_component(vec2{0, 0}, vec2{1, 1}); - + gameobject.add_component().set_script(); Color color(0, 0, 0, 0); auto img = Texture("asset/texture/green_square.png"); -- cgit v1.2.3 From 42ecf9c1d0e3ed1f37f99a24f31241b68f978b28 Mon Sep 17 00:00:00 2001 From: max-001 Date: Fri, 6 Dec 2024 10:14:33 +0100 Subject: Added script to shutdown game (by throwing an exception and not catching it) --- src/example/AITest.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/example/AITest.cpp b/src/example/AITest.cpp index 841b195..91a529c 100644 --- a/src/example/AITest.cpp +++ b/src/example/AITest.cpp @@ -1,19 +1,33 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include -#include #include using namespace crepe; using namespace std; +class Script1 : public Script { + bool shutdown(const ShutDownEvent & event) { + // Very dirty way of shutting down the game + throw "ShutDownEvent"; + return true; + } + + void init() { + subscribe( + [this](const ShutDownEvent & ev) -> bool { return this->shutdown(ev); }); + } +}; + class Scene1 : public Scene { public: void load_scene() override { @@ -30,6 +44,7 @@ public: game_object2.add_component(Color::WHITE, ivec2{1080, 720}, vec2{1036, 780}, 1.0f); + game_object2.add_component().set_script(); } string get_name() const override { return "Scene1"; } -- cgit v1.2.3 From 9c2cafd85ed7aa9a860ba25fbe2bd3ccc2439f29 Mon Sep 17 00:00:00 2001 From: max-001 Date: Fri, 6 Dec 2024 10:39:18 +0100 Subject: Using Rigidbody from now on --- src/crepe/api/AI.cpp | 6 +----- src/crepe/api/AI.h | 7 +------ src/crepe/system/AISystem.cpp | 22 +++++++++++----------- src/example/AITest.cpp | 6 +++++- 4 files changed, 18 insertions(+), 23 deletions(-) diff --git a/src/crepe/api/AI.cpp b/src/crepe/api/AI.cpp index 7f820a8..d785bb5 100644 --- a/src/crepe/api/AI.cpp +++ b/src/crepe/api/AI.cpp @@ -2,10 +2,6 @@ namespace crepe { -AI::AI(game_object_id_t id, float mass, float max_speed, float max_force) - : Component(id), - mass(mass), - max_speed(max_speed), - max_force(max_force) {} +AI::AI(game_object_id_t id, float max_force) : Component(id), max_force(max_force) {} } // namespace crepe diff --git a/src/crepe/api/AI.h b/src/crepe/api/AI.h index 242ff89..046426d 100644 --- a/src/crepe/api/AI.h +++ b/src/crepe/api/AI.h @@ -16,7 +16,7 @@ public: }; public: - AI(game_object_id_t id, float mass, float max_speed, float max_force); + AI(game_object_id_t id, float max_force); bool on(BehaviorType behavior) const { return (flags & behavior) == behavior; } void seek_on() { flags |= SEEK; } @@ -37,8 +37,6 @@ public: } public: - float mass; - float max_speed; float max_force; // The target to seek or arrive at @@ -51,9 +49,6 @@ public: float arrive_deceleration = 2.0f; private: - vec2 velocity; - friend class AISystem; - int flags = 0; }; diff --git a/src/crepe/system/AISystem.cpp b/src/crepe/system/AISystem.cpp index 3c61c78..d496e12 100644 --- a/src/crepe/system/AISystem.cpp +++ b/src/crepe/system/AISystem.cpp @@ -1,4 +1,5 @@ #include "api/LoopTimer.h" +#include "api/Rigidbody.h" #include "api/Transform.h" #include "manager/ComponentManager.h" #include "manager/Mediator.h" @@ -16,16 +17,13 @@ void AISystem::update() { double dt = LoopTimer::get_instance().get_delta_time(); for (AI & ai : ai_components) { + RefVector rigidbodies + = mgr.get_components_by_id(ai.game_object_id); + Rigidbody & rigidbody = rigidbodies.front().get(); + vec2 force = this->calculate(ai); - vec2 acceleration = force / ai.mass; - ai.velocity += acceleration * dt; - ai.velocity.truncate(ai.max_speed); - - // Update the position - RefVector transforms - = mgr.get_components_by_id(ai.game_object_id); - Transform & transform = transforms.front().get(); - transform.position += ai.velocity * dt; + vec2 acceleration = force / rigidbody.data.mass; + rigidbody.data.linear_velocity += acceleration * dt; } } @@ -69,10 +67,12 @@ vec2 AISystem::seek(const AI & ai) { ComponentManager & mgr = mediator.component_manager; RefVector transforms = mgr.get_components_by_id(ai.game_object_id); Transform & transform = transforms.front().get(); + RefVector rigidbodies = mgr.get_components_by_id(ai.game_object_id); + Rigidbody & rigidbody = rigidbodies.front().get(); vec2 desired_velocity = ai.seek_target - transform.position; desired_velocity.normalize(); - desired_velocity *= ai.max_speed; + desired_velocity *= rigidbody.data.max_linear_velocity; - return desired_velocity - ai.velocity; + return desired_velocity - rigidbody.data.linear_velocity; } diff --git a/src/example/AITest.cpp b/src/example/AITest.cpp index 91a529c..2b6a4d6 100644 --- a/src/example/AITest.cpp +++ b/src/example/AITest.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -40,7 +41,10 @@ public: Texture img = Texture("asset/texture/test_ap43.png"); game_object1.add_component(img, Color::MAGENTA, Sprite::FlipSettings{false, false}, 1, 1, 195); - game_object1.add_component(1, 200, 200).seek_on(); + game_object1.add_component(200).seek_on(); + game_object1.add_component(Rigidbody::Data{ + .mass = 1.0f, .max_linear_velocity = {21, 21}, // sqrt(21^2 + 21^2) = 30 + }); game_object2.add_component(Color::WHITE, ivec2{1080, 720}, vec2{1036, 780}, 1.0f); -- cgit v1.2.3 From 82863204048d65073bc5598dcb62f31e32b51430 Mon Sep 17 00:00:00 2001 From: max-001 Date: Fri, 6 Dec 2024 10:46:16 +0100 Subject: Corrected accumulate_force() --- src/crepe/system/AISystem.cpp | 21 ++++++++++++++------- src/crepe/system/AISystem.h | 5 ++++- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/crepe/system/AISystem.cpp b/src/crepe/system/AISystem.cpp index d496e12..4858000 100644 --- a/src/crepe/system/AISystem.cpp +++ b/src/crepe/system/AISystem.cpp @@ -33,7 +33,7 @@ vec2 AISystem::calculate(AI & ai) { if (ai.on(AI::BehaviorType::SEEK)) { vec2 force_to_add = this->seek(ai); - if (!this->accumulate_force(force, force_to_add)) { + if (!this->accumulate_force(ai, force, force_to_add)) { return force; } } @@ -50,16 +50,23 @@ vec2 AISystem::calculate(AI & ai) { return force; } -bool AISystem::accumulate_force(vec2 & running_total, vec2 force_to_add) { - double magnitude_remaining = running_total.length(); - double magnitude_to_add = force_to_add.length(); +bool AISystem::accumulate_force(AI & ai, vec2 & running_total, vec2 force_to_add) { + float magnitude = running_total.length(); + float magnitude_remaining = ai.max_force - magnitude; - if (magnitude_remaining + magnitude_to_add > 0) { + if (magnitude_remaining <= 0.0f) { + return false; + } + + float magnitude_to_add = force_to_add.length(); + if (magnitude_to_add < magnitude_remaining) { running_total += force_to_add; - return true; + } else { + force_to_add.normalize(); + running_total += force_to_add * magnitude_remaining; } - return false; + return true; } vec2 AISystem::seek(const AI & ai) { diff --git a/src/crepe/system/AISystem.h b/src/crepe/system/AISystem.h index 5e94ccb..18f1c61 100644 --- a/src/crepe/system/AISystem.h +++ b/src/crepe/system/AISystem.h @@ -15,9 +15,12 @@ public: private: vec2 calculate(AI & ai); - bool accumulate_force(vec2 & running_total, vec2 force_to_add); + bool accumulate_force(AI & ai, vec2 & running_total, vec2 force_to_add); vec2 seek(const AI & ai); + vec2 flee(const AI & ai); + vec2 arrive(const AI & ai); + vec2 path_follow(const AI & ai); }; } // namespace crepe -- cgit v1.2.3 From 9eac8d31b25c234a21b1d188df17e77e71f48088 Mon Sep 17 00:00:00 2001 From: max-001 Date: Fri, 6 Dec 2024 16:21:40 +0100 Subject: Improved example --- src/crepe/system/CollisionSystem.cpp | 2 -- src/example/AITest.cpp | 17 ++++++++++++++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/crepe/system/CollisionSystem.cpp b/src/crepe/system/CollisionSystem.cpp index 2a487fd..1282f7a 100644 --- a/src/crepe/system/CollisionSystem.cpp +++ b/src/crepe/system/CollisionSystem.cpp @@ -550,5 +550,3 @@ vec2 CollisionSystem::get_current_position(const vec2 & collider_offset, // Final positions considering scaling and rotation return (transform.position + vec2(rotated_total_offset_x1, rotated_total_offset_y1)); } - - diff --git a/src/example/AITest.cpp b/src/example/AITest.cpp index 2b6a4d6..144aef3 100644 --- a/src/example/AITest.cpp +++ b/src/example/AITest.cpp @@ -12,6 +12,7 @@ #include #include #include +#include using namespace crepe; using namespace std; @@ -23,9 +24,19 @@ class Script1 : public Script { return true; } + bool mousemove(const MouseMoveEvent & event) { + RefVector aivec = this->get_components(); + AI & ai = aivec.front().get(); + ai.seek_target + = vec2{static_cast(event.mouse_x), static_cast(event.mouse_y)}; + return true; + } + void init() { subscribe( [this](const ShutDownEvent & ev) -> bool { return this->shutdown(ev); }); + subscribe( + [this](const MouseMoveEvent & ev) -> bool { return this->mousemove(ev); }); } }; @@ -41,14 +52,14 @@ public: Texture img = Texture("asset/texture/test_ap43.png"); game_object1.add_component(img, Color::MAGENTA, Sprite::FlipSettings{false, false}, 1, 1, 195); - game_object1.add_component(200).seek_on(); + game_object1.add_component(30).seek_on(); game_object1.add_component(Rigidbody::Data{ - .mass = 1.0f, .max_linear_velocity = {21, 21}, // sqrt(21^2 + 21^2) = 30 + .mass = 0.5f, .max_linear_velocity = {21, 21}, // sqrt(21^2 + 21^2) = 30 }); + game_object1.add_component().set_script(); game_object2.add_component(Color::WHITE, ivec2{1080, 720}, vec2{1036, 780}, 1.0f); - game_object2.add_component().set_script(); } string get_name() const override { return "Scene1"; } -- cgit v1.2.3 From 0d0943d23364d7110f0232e3564f4ea63af13db2 Mon Sep 17 00:00:00 2001 From: max-001 Date: Fri, 6 Dec 2024 16:41:51 +0100 Subject: Implemented flee and arrive behaviors --- src/crepe/api/AI.h | 4 +-- src/crepe/system/AISystem.cpp | 71 ++++++++++++++++++++++++++++++++++++++----- src/example/AITest.cpp | 6 ++-- 3 files changed, 69 insertions(+), 12 deletions(-) diff --git a/src/crepe/api/AI.h b/src/crepe/api/AI.h index 046426d..d4bd9d3 100644 --- a/src/crepe/api/AI.h +++ b/src/crepe/api/AI.h @@ -44,9 +44,9 @@ public: // The target to flee from vec2 flee_target; // The distance at which the entity will start to flee from the target - float square_flee_panic_distance = 100.0f * 100.0f; + float square_flee_panic_distance = 200.0f * 200.0f; // The deceleration rate for the arrive behavior (higher values will make the entity decelerate faster (less overshoot)) - float arrive_deceleration = 2.0f; + float arrive_deceleration = 40.0f; private: int flags = 0; diff --git a/src/crepe/system/AISystem.cpp b/src/crepe/system/AISystem.cpp index 4858000..ce3147f 100644 --- a/src/crepe/system/AISystem.cpp +++ b/src/crepe/system/AISystem.cpp @@ -1,11 +1,14 @@ +#include +#include + #include "api/LoopTimer.h" #include "api/Rigidbody.h" #include "api/Transform.h" #include "manager/ComponentManager.h" #include "manager/Mediator.h" -#include "types.h" #include "AISystem.h" +#include "types.h" using namespace crepe; @@ -30,21 +33,33 @@ void AISystem::update() { vec2 AISystem::calculate(AI & ai) { vec2 force; - if (ai.on(AI::BehaviorType::SEEK)) { - vec2 force_to_add = this->seek(ai); + if (ai.on(AI::BehaviorType::FLEE)) { + vec2 force_to_add = this->flee(ai); if (!this->accumulate_force(ai, force, force_to_add)) { return force; } } - if (ai.on(AI::BehaviorType::FLEE)) { - // Flee from the target - } if (ai.on(AI::BehaviorType::ARRIVE)) { - // Arrive at the target + vec2 force_to_add = this->arrive(ai); + + if (!this->accumulate_force(ai, force, force_to_add)) { + return force; + } + } + if (ai.on(AI::BehaviorType::SEEK)) { + vec2 force_to_add = this->seek(ai); + + if (!this->accumulate_force(ai, force, force_to_add)) { + return force; + } } if (ai.on(AI::BehaviorType::PATH_FOLLOW)) { - // Follow the path + /*vec2 force_to_add = this->path_follow(ai); + + if (!this->accumulate_force(ai, force, force_to_add)) { + return force; + }*/ } return force; @@ -83,3 +98,43 @@ vec2 AISystem::seek(const AI & ai) { return desired_velocity - rigidbody.data.linear_velocity; } + +vec2 AISystem::flee(const AI & ai) { + const Mediator & mediator = this->mediator; + ComponentManager & mgr = mediator.component_manager; + RefVector transforms = mgr.get_components_by_id(ai.game_object_id); + Transform & transform = transforms.front().get(); + RefVector rigidbodies = mgr.get_components_by_id(ai.game_object_id); + Rigidbody & rigidbody = rigidbodies.front().get(); + + vec2 desired_velocity = transform.position - ai.flee_target; + if (desired_velocity.length_squared() > ai.square_flee_panic_distance) { + return vec2{0, 0}; + } + + desired_velocity.normalize(); + desired_velocity *= rigidbody.data.max_linear_velocity; + + return desired_velocity - rigidbody.data.linear_velocity; +} + +vec2 AISystem::arrive(const AI & ai) { + const Mediator & mediator = this->mediator; + ComponentManager & mgr = mediator.component_manager; + RefVector transforms = mgr.get_components_by_id(ai.game_object_id); + Transform & transform = transforms.front().get(); + RefVector rigidbodies = mgr.get_components_by_id(ai.game_object_id); + Rigidbody & rigidbody = rigidbodies.front().get(); + + vec2 to_target = ai.seek_target - transform.position; + float distance = to_target.length(); + if (distance > 0.0f) { + float speed = distance / ai.arrive_deceleration; + speed = std::min(speed, rigidbody.data.max_linear_velocity.length()); + vec2 desired_velocity = to_target * (speed / distance); + + return desired_velocity - rigidbody.data.linear_velocity; + } + + return vec2{0, 0}; +} diff --git a/src/example/AITest.cpp b/src/example/AITest.cpp index 144aef3..319d0fe 100644 --- a/src/example/AITest.cpp +++ b/src/example/AITest.cpp @@ -27,7 +27,7 @@ class Script1 : public Script { bool mousemove(const MouseMoveEvent & event) { RefVector aivec = this->get_components(); AI & ai = aivec.front().get(); - ai.seek_target + ai.flee_target = vec2{static_cast(event.mouse_x), static_cast(event.mouse_y)}; return true; } @@ -52,7 +52,9 @@ public: Texture img = Texture("asset/texture/test_ap43.png"); game_object1.add_component(img, Color::MAGENTA, Sprite::FlipSettings{false, false}, 1, 1, 195); - game_object1.add_component(30).seek_on(); + AI & ai = game_object1.add_component(30); + ai.arrive_on(); + ai.flee_on(); game_object1.add_component(Rigidbody::Data{ .mass = 0.5f, .max_linear_velocity = {21, 21}, // sqrt(21^2 + 21^2) = 30 }); -- cgit v1.2.3 From f4824f5e7e6cee12bec602f3240770945a73d043 Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Fri, 6 Dec 2024 17:13:59 +0100 Subject: add more fetching functions to ComponentManager --- src/crepe/api/Script.h | 7 +++++ src/crepe/manager/ComponentManager.cpp | 14 ++++++++++ src/crepe/manager/ComponentManager.h | 18 ++++++++++-- src/crepe/manager/ComponentManager.hpp | 51 ++++++++++++++++++++-------------- src/test/ECSTest.cpp | 34 +++++++++++++++++++++++ 5 files changed, 101 insertions(+), 23 deletions(-) diff --git a/src/crepe/api/Script.h b/src/crepe/api/Script.h index 1b339b0..5862bae 100644 --- a/src/crepe/api/Script.h +++ b/src/crepe/api/Script.h @@ -84,6 +84,13 @@ protected: template RefVector get_components() const; + /** + * \copydoc ComponentManager::get_components_by_id + * \see ComponentManager::get_components_by_id + */ + template + RefVector get_components_by_id(game_object_id_t id) const; + /** * \brief Log a message using Log::logf * diff --git a/src/crepe/manager/ComponentManager.cpp b/src/crepe/manager/ComponentManager.cpp index 80cf8b4..44774d9 100644 --- a/src/crepe/manager/ComponentManager.cpp +++ b/src/crepe/manager/ComponentManager.cpp @@ -1,4 +1,5 @@ #include "../api/GameObject.h" +#include "../api/Metadata.h" #include "../types.h" #include "../util/Log.h" @@ -61,3 +62,16 @@ GameObject ComponentManager::new_object(const string & name, const string & tag, void ComponentManager::set_persistent(game_object_id_t id, bool persistent) { this->persistent[id] = persistent; } + +set ComponentManager::get_objects_by_name(const string & name) const { + return this->get_objects_by_predicate([name](const Metadata & data) { + return data.name == name; + }); +} + +set ComponentManager::get_objects_by_tag(const string & tag) const { + return this->get_objects_by_predicate([tag](const Metadata & data) { + return data.tag == tag; + }); +} + diff --git a/src/crepe/manager/ComponentManager.h b/src/crepe/manager/ComponentManager.h index ad37586..5f2cf3c 100644 --- a/src/crepe/manager/ComponentManager.h +++ b/src/crepe/manager/ComponentManager.h @@ -4,6 +4,7 @@ #include #include #include +#include #include "../Component.h" #include "../types.h" @@ -136,6 +137,17 @@ public: RefVector get_components_by_type() const; private: + template + std::set get_objects_by_predicate(const std::function & pred) const; + + std::set get_objects_by_name(const std::string & name) const; + std::set get_objects_by_tag(const std::string & tag) const; + +private: + template + using by_type = std::unordered_map; + template + using by_id_index = std::vector; /** * \brief The components * @@ -146,8 +158,7 @@ private: * The first vector is for the ids of the GameObjects and the second vector is for the * components (because a GameObject might have multiple components). */ - std::unordered_map>>> - components; + by_type>>> components; //! Persistent flag for each GameObject std::unordered_map persistent; @@ -156,6 +167,9 @@ private: game_object_id_t next_id = 0; }; +// template <> +// RefVector ComponentManager::get_components_by_id(game_object_id_t id) const; + } // namespace crepe #include "ComponentManager.hpp" diff --git a/src/crepe/manager/ComponentManager.hpp b/src/crepe/manager/ComponentManager.hpp index ffb38ec..25c2747 100644 --- a/src/crepe/manager/ComponentManager.hpp +++ b/src/crepe/manager/ComponentManager.hpp @@ -95,32 +95,24 @@ template RefVector ComponentManager::get_components_by_id(game_object_id_t id) const { using namespace std; - // Determine the type of T (this is used as the key of the unordered_map<>) - type_index type = typeid(T); - - // Create an empty vector<> - RefVector component_vector; - - if (this->components.find(type) == this->components.end()) return component_vector; - - // Get the correct vector<> - const vector>> & component_array = this->components.at(type); - - // Make sure that the id (that we are looking for) is within the boundaries of the vector<> - if (id >= component_array.size()) return component_vector; + static_assert(is_base_of::value, + "get_components_by_id must recieve a derivative class of Component"); - // Loop trough the whole vector<> - for (const unique_ptr & component_ptr : component_array[id]) { - // Cast the unique_ptr to a raw pointer - T * casted_component = static_cast(component_ptr.get()); + type_index type = typeid(T); + if (!this->components.contains(type)) return {}; - if (casted_component == nullptr) continue; + const by_id_index>> & components_by_id = this->components.at(type); + if (id >= components_by_id.size()) return {}; - // Add the dereferenced raw pointer to the vector<> - component_vector.push_back(*casted_component); + RefVector out = {}; + const vector> & components = components_by_id.at(id); + for (auto & component_ptr : components) { + if (component_ptr == nullptr) continue; + Component & component = *component_ptr.get(); + out.push_back(static_cast(component)); } - return component_vector; + return out; } template @@ -158,4 +150,21 @@ RefVector ComponentManager::get_components_by_type() const { return component_vector; } +template +std::set ComponentManager::get_objects_by_predicate(const std::function & pred) const { + using namespace std; + + set objects = {}; + RefVector components = this->get_components_by_type(); + + for (const T & component : components) { + game_object_id_t id = dynamic_cast(component).game_object_id; + if (objects.contains(id)) continue; + if (!pred(component)) continue; + objects.insert(id); + } + + return objects; +} + } // namespace crepe diff --git a/src/test/ECSTest.cpp b/src/test/ECSTest.cpp index 3e6c61c..a169b3b 100644 --- a/src/test/ECSTest.cpp +++ b/src/test/ECSTest.cpp @@ -1,6 +1,7 @@ #include #define protected public +#define private public #include #include @@ -387,3 +388,36 @@ TEST_F(ECSTest, resetPersistent) { EXPECT_EQ(metadata.size(), 0); EXPECT_EQ(transform.size(), 0); } + +TEST_F(ECSTest, GetByName) { + GameObject foo = mgr.new_object("foo"); + GameObject bar = mgr.new_object("bar"); + + { + auto objects = mgr.get_objects_by_name(""); + EXPECT_EQ(objects.size(), 0); + } + + { + auto objects = mgr.get_objects_by_name("foo"); + EXPECT_EQ(objects.size(), 1); + EXPECT_TRUE(objects.contains(foo.id)); + } +} + +TEST_F(ECSTest, GetByTag) { + GameObject foo = mgr.new_object("foo", "common tag"); + GameObject bar = mgr.new_object("bar", "common tag"); + + { + auto objects = mgr.get_objects_by_tag(""); + EXPECT_EQ(objects.size(), 0); + } + + { + auto objects = mgr.get_objects_by_tag("common tag"); + EXPECT_EQ(objects.size(), 2); + EXPECT_TRUE(objects.contains(foo.id)); + EXPECT_TRUE(objects.contains(bar.id)); + } +} -- cgit v1.2.3 From 33a072db28d71ba65e59f9491abd42dbf9695fc4 Mon Sep 17 00:00:00 2001 From: max-001 Date: Fri, 6 Dec 2024 17:14:00 +0100 Subject: Implemented path_follow --- src/crepe/api/AI.h | 14 ++++++++++++++ src/crepe/system/AISystem.cpp | 34 ++++++++++++++++++++++++++++++++-- src/crepe/system/AISystem.h | 2 +- src/example/AITest.cpp | 21 +++++++++++++-------- 4 files changed, 60 insertions(+), 11 deletions(-) diff --git a/src/crepe/api/AI.h b/src/crepe/api/AI.h index d4bd9d3..35b8998 100644 --- a/src/crepe/api/AI.h +++ b/src/crepe/api/AI.h @@ -36,6 +36,8 @@ public: if (on(PATH_FOLLOW)) flags ^= PATH_FOLLOW; } + void add_path_node(vec2 node) { path.push_back(node); } + public: float max_force; @@ -47,9 +49,21 @@ public: float square_flee_panic_distance = 200.0f * 200.0f; // The deceleration rate for the arrive behavior (higher values will make the entity decelerate faster (less overshoot)) float arrive_deceleration = 40.0f; + // The path to follow + std::vector path; + // The distance from the path node at which the entity will move to the next node + float path_node_distance = 400.0f; + // Looping behavior for the path + bool path_loop = true; private: + // The flags for the behaviors int flags = 0; + // The current path index + size_t path_index = 0; + + // The AISystem is the only class that can access the private members of AI + friend class AISystem; }; } // namespace crepe diff --git a/src/crepe/system/AISystem.cpp b/src/crepe/system/AISystem.cpp index ce3147f..55dc14c 100644 --- a/src/crepe/system/AISystem.cpp +++ b/src/crepe/system/AISystem.cpp @@ -55,11 +55,11 @@ vec2 AISystem::calculate(AI & ai) { } } if (ai.on(AI::BehaviorType::PATH_FOLLOW)) { - /*vec2 force_to_add = this->path_follow(ai); + vec2 force_to_add = this->path_follow(ai); if (!this->accumulate_force(ai, force, force_to_add)) { return force; - }*/ + } } return force; @@ -138,3 +138,33 @@ vec2 AISystem::arrive(const AI & ai) { return vec2{0, 0}; } + +vec2 AISystem::path_follow(AI & ai) { + const Mediator & mediator = this->mediator; + ComponentManager & mgr = mediator.component_manager; + RefVector transforms = mgr.get_components_by_id(ai.game_object_id); + Transform & transform = transforms.front().get(); + RefVector rigidbodies = mgr.get_components_by_id(ai.game_object_id); + Rigidbody & rigidbody = rigidbodies.front().get(); + + if (ai.path.empty()) { + return vec2{0, 0}; + } + + vec2 to_target = ai.path.at(ai.path_index) - transform.position; + if (to_target.length_squared() > ai.path_node_distance * ai.path_node_distance) { + ai.seek_target = ai.path.at(ai.path_index); + } else { + ai.path_index++; + if (ai.path_index >= ai.path.size()) { + if (ai.path_loop) { + ai.path_index = 0; + } else { + ai.path_index = ai.path.size() - 1; + return this->arrive(ai); + } + } + } + + return this->seek(ai); +} diff --git a/src/crepe/system/AISystem.h b/src/crepe/system/AISystem.h index 18f1c61..27861d9 100644 --- a/src/crepe/system/AISystem.h +++ b/src/crepe/system/AISystem.h @@ -20,7 +20,7 @@ private: vec2 seek(const AI & ai); vec2 flee(const AI & ai); vec2 arrive(const AI & ai); - vec2 path_follow(const AI & ai); + vec2 path_follow(AI & ai); }; } // namespace crepe diff --git a/src/example/AITest.cpp b/src/example/AITest.cpp index 319d0fe..d12a99a 100644 --- a/src/example/AITest.cpp +++ b/src/example/AITest.cpp @@ -25,10 +25,10 @@ class Script1 : public Script { } bool mousemove(const MouseMoveEvent & event) { - RefVector aivec = this->get_components(); + /*RefVector aivec = this->get_components(); AI & ai = aivec.front().get(); ai.flee_target - = vec2{static_cast(event.mouse_x), static_cast(event.mouse_y)}; + = vec2{static_cast(event.mouse_x), static_cast(event.mouse_y)};*/ return true; } @@ -46,21 +46,26 @@ public: Mediator & mediator = this->mediator; ComponentManager & mgr = mediator.component_manager; - GameObject game_object1 = mgr.new_object("", "", vec2{250, 250}, 0, 1); + GameObject game_object1 = mgr.new_object("", "", vec2{0, 0}, 0, 1); GameObject game_object2 = mgr.new_object("", "", vec2{0, 0}, 0, 1); Texture img = Texture("asset/texture/test_ap43.png"); game_object1.add_component(img, Color::MAGENTA, Sprite::FlipSettings{false, false}, 1, 1, 195); - AI & ai = game_object1.add_component(30); - ai.arrive_on(); - ai.flee_on(); + AI & ai = game_object1.add_component(300); + // ai.arrive_on(); + // ai.flee_on(); + ai.path_follow_on(); + ai.add_path_node(vec2{1200, 1200}); + ai.add_path_node(vec2{-1200, 1200}); + ai.add_path_node(vec2{1200, -1200}); + ai.add_path_node(vec2{-1200, -1200}); game_object1.add_component(Rigidbody::Data{ - .mass = 0.5f, .max_linear_velocity = {21, 21}, // sqrt(21^2 + 21^2) = 30 + .mass = 0.5f, .max_linear_velocity = {50, 50}, // sqrt(21^2 + 21^2) = 30 }); game_object1.add_component().set_script(); - game_object2.add_component(Color::WHITE, ivec2{1080, 720}, vec2{1036, 780}, + game_object2.add_component(Color::WHITE, ivec2{1080, 720}, vec2{5000, 5000}, 1.0f); } -- cgit v1.2.3 From 90c6bf03e59fdec64f850310bcbff45ae86f69e3 Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Sat, 7 Dec 2024 14:18:54 +0100 Subject: more script utilities --- src/crepe/api/Script.h | 12 ++++++++ src/crepe/api/Script.hpp | 27 +++++++++++++++--- src/crepe/manager/ComponentManager.h | 20 ++++++++++++++ src/crepe/manager/ComponentManager.hpp | 23 ++++++++++++++++ src/test/CMakeLists.txt | 1 + src/test/ECSTest.cpp | 50 ++++++++++++++++++++++++++++++++-- src/test/ScriptECSTest.cpp | 42 ++++++++++++++++++++++++++++ src/test/ScriptEventTest.cpp | 2 +- src/test/ScriptSceneTest.cpp | 3 +- src/test/ScriptTest.cpp | 3 +- src/test/ScriptTest.h | 2 ++ 11 files changed, 175 insertions(+), 10 deletions(-) create mode 100644 src/test/ScriptECSTest.cpp diff --git a/src/crepe/api/Script.h b/src/crepe/api/Script.h index 5862bae..a040608 100644 --- a/src/crepe/api/Script.h +++ b/src/crepe/api/Script.h @@ -90,6 +90,18 @@ protected: */ template RefVector get_components_by_id(game_object_id_t id) const; + /** + * \copydoc ComponentManager::get_components_by_name + * \see ComponentManager::get_components_by_name + */ + template + RefVector get_components_by_name(const std::string & name) const; + /** + * \copydoc ComponentManager::get_components_by_tag + * \see ComponentManager::get_components_by_tag + */ + template + RefVector get_components_by_tag(const std::string & tag) const; /** * \brief Log a message using Log::logf diff --git a/src/crepe/api/Script.hpp b/src/crepe/api/Script.hpp index 45f1ff1..16e0dc5 100644 --- a/src/crepe/api/Script.hpp +++ b/src/crepe/api/Script.hpp @@ -20,10 +20,7 @@ T & Script::get_component() const { template RefVector Script::get_components() const { - Mediator & mediator = this->mediator; - ComponentManager & mgr = mediator.component_manager; - - return mgr.get_components_by_id(this->game_object_id); + return this->get_components_by_id(this->game_object_id); } template @@ -56,4 +53,26 @@ void Script::subscribe(const EventHandler & callback) { this->subscribe_internal(callback, EventManager::CHANNEL_ALL); } +template +RefVector Script::get_components_by_id(game_object_id_t id) const { + Mediator & mediator = this->mediator; + ComponentManager & mgr = mediator.component_manager; + + return mgr.get_components_by_id(id); +} +template +RefVector Script::get_components_by_name(const std::string & name) const { + Mediator & mediator = this->mediator; + ComponentManager & mgr = mediator.component_manager; + + return mgr.get_components_by_name(name); +} +template +RefVector Script::get_components_by_tag(const std::string & tag) const { + Mediator & mediator = this->mediator; + ComponentManager & mgr = mediator.component_manager; + + return mgr.get_components_by_tag(tag); +} + } // namespace crepe diff --git a/src/crepe/manager/ComponentManager.h b/src/crepe/manager/ComponentManager.h index 5f2cf3c..4e53954 100644 --- a/src/crepe/manager/ComponentManager.h +++ b/src/crepe/manager/ComponentManager.h @@ -135,10 +135,30 @@ public: */ template RefVector get_components_by_type() const; + /** + * \brief Get all components of a specific type on a GameObject with name \c name + * + * \tparam T The type of the component + * \param name Metadata::name for the same game_object_id as the returned components + * \return Components matching criteria + */ + template + RefVector get_components_by_name(const std::string & name) const; + /** + * \brief Get all components of a specific type on a GameObject with tag \c tag + * + * \tparam T The type of the component + * \param name Metadata::tag for the same game_object_id as the returned components + * \return Components matching criteria + */ + template + RefVector get_components_by_tag(const std::string & tag) const; private: template std::set get_objects_by_predicate(const std::function & pred) const; + template + RefVector get_components_by_ids(const std::set & ids) const; std::set get_objects_by_name(const std::string & name) const; std::set get_objects_by_tag(const std::string & tag) const; diff --git a/src/crepe/manager/ComponentManager.hpp b/src/crepe/manager/ComponentManager.hpp index 25c2747..52df368 100644 --- a/src/crepe/manager/ComponentManager.hpp +++ b/src/crepe/manager/ComponentManager.hpp @@ -167,4 +167,27 @@ std::set ComponentManager::get_objects_by_predicate(const std: return objects; } +template +RefVector ComponentManager::get_components_by_ids(const std::set & ids) const { + using namespace std; + + RefVector out = {}; + for (game_object_id_t id : ids) { + RefVector components = get_components_by_id(id); + out.insert(out.end(), components.begin(), components.end()); + } + + return out; +} + +template +RefVector ComponentManager::get_components_by_name(const std::string & name) const { + return this->get_components_by_ids(this->get_objects_by_name(name)); +} + +template +RefVector ComponentManager::get_components_by_tag(const std::string & tag) const { + return this->get_components_by_ids(this->get_objects_by_tag(tag)); +} + } // namespace crepe diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index e19d7de..43f564a 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -15,4 +15,5 @@ target_sources(test_main PUBLIC InputTest.cpp ScriptEventTest.cpp ScriptSceneTest.cpp + ScriptECSTest.cpp ) diff --git a/src/test/ECSTest.cpp b/src/test/ECSTest.cpp index a169b3b..ed5341e 100644 --- a/src/test/ECSTest.cpp +++ b/src/test/ECSTest.cpp @@ -17,6 +17,10 @@ class ECSTest : public ::testing::Test { public: ComponentManager mgr{m}; + + class TestComponent : public Component { + using Component::Component; + }; }; TEST_F(ECSTest, createGameObject) { @@ -389,7 +393,7 @@ TEST_F(ECSTest, resetPersistent) { EXPECT_EQ(transform.size(), 0); } -TEST_F(ECSTest, GetByName) { +TEST_F(ECSTest, IDByName) { GameObject foo = mgr.new_object("foo"); GameObject bar = mgr.new_object("bar"); @@ -405,7 +409,7 @@ TEST_F(ECSTest, GetByName) { } } -TEST_F(ECSTest, GetByTag) { +TEST_F(ECSTest, IDByTag) { GameObject foo = mgr.new_object("foo", "common tag"); GameObject bar = mgr.new_object("bar", "common tag"); @@ -421,3 +425,45 @@ TEST_F(ECSTest, GetByTag) { EXPECT_TRUE(objects.contains(bar.id)); } } + +TEST_F(ECSTest, ComponentsByName) { + GameObject foo = mgr.new_object("foo"); + foo.add_component(); + GameObject bar = mgr.new_object("bar"); + bar.add_component(); + bar.add_component(); + + { + auto objects = mgr.get_components_by_name(""); + EXPECT_EQ(objects.size(), 0); + } + + { + auto objects = mgr.get_components_by_name("foo"); + EXPECT_EQ(objects.size(), 1); + } + + { + auto objects = mgr.get_components_by_name("bar"); + EXPECT_EQ(objects.size(), 2); + } +} + +TEST_F(ECSTest, ComponentsByTag) { + GameObject foo = mgr.new_object("foo", "common tag"); + foo.add_component(); + GameObject bar = mgr.new_object("bar", "common tag"); + bar.add_component(); + bar.add_component(); + + { + auto objects = mgr.get_components_by_tag(""); + EXPECT_EQ(objects.size(), 0); + } + + { + auto objects = mgr.get_components_by_tag("common tag"); + EXPECT_EQ(objects.size(), 3); + } +} + diff --git a/src/test/ScriptECSTest.cpp b/src/test/ScriptECSTest.cpp new file mode 100644 index 0000000..4477e55 --- /dev/null +++ b/src/test/ScriptECSTest.cpp @@ -0,0 +1,42 @@ +#include + +#define protected public + +#include +#include +#include +#include +#include +#include + +#include "ScriptTest.h" + +using namespace std; +using namespace crepe; +using namespace testing; + +class ScriptECSTest : public ScriptTest { +public: + class TestComponent : public Component { + using Component::Component; + }; +}; + +TEST_F(ScriptECSTest, GetOwnComponent) { + MyScript & script = this->script; + Metadata & metadata = script.get_component(); + + EXPECT_EQ(metadata.name, OBJ_NAME); +} + +TEST_F(ScriptECSTest, GetOwnComponents) { + const unsigned COUNT = 4; + + for (unsigned i = 0; i < COUNT; i++) + entity.add_component(); + + MyScript & script = this->script; + RefVector components = script.get_components(); + + EXPECT_EQ(components.size(), COUNT); +} diff --git a/src/test/ScriptEventTest.cpp b/src/test/ScriptEventTest.cpp index 5da31e7..c1b4028 100644 --- a/src/test/ScriptEventTest.cpp +++ b/src/test/ScriptEventTest.cpp @@ -26,7 +26,7 @@ public: class MyEvent : public Event {}; }; -TEST_F(ScriptEventTest, Inactive) { +TEST_F(ScriptEventTest, Default) { BehaviorScript & behaviorscript = this->behaviorscript; MyScript & script = this->script; EventManager & evmgr = this->event_manager; diff --git a/src/test/ScriptSceneTest.cpp b/src/test/ScriptSceneTest.cpp index 9ee1e52..8e849c1 100644 --- a/src/test/ScriptSceneTest.cpp +++ b/src/test/ScriptSceneTest.cpp @@ -18,7 +18,7 @@ public: class MyScene : public Scene {}; }; -TEST_F(ScriptSceneTest, Inactive) { +TEST_F(ScriptSceneTest, Default) { BehaviorScript & behaviorscript = this->behaviorscript; MyScript & script = this->script; @@ -28,3 +28,4 @@ TEST_F(ScriptSceneTest, Inactive) { script.set_next_scene(non_default_value); EXPECT_EQ(non_default_value, scene_manager.next_scene); } + diff --git a/src/test/ScriptTest.cpp b/src/test/ScriptTest.cpp index 1d2d6dd..b0b2546 100644 --- a/src/test/ScriptTest.cpp +++ b/src/test/ScriptTest.cpp @@ -6,7 +6,6 @@ #define protected public #include "ScriptTest.h" -#include using namespace std; using namespace crepe; @@ -14,7 +13,6 @@ using namespace testing; void ScriptTest::SetUp() { auto & mgr = this->component_manager; - GameObject entity = mgr.new_object("name"); BehaviorScript & component = entity.add_component(); this->behaviorscript = component; @@ -75,3 +73,4 @@ TEST_F(ScriptTest, UpdateInactive) { system.update(); } } + diff --git a/src/test/ScriptTest.h b/src/test/ScriptTest.h index 1bbfdd3..309e016 100644 --- a/src/test/ScriptTest.h +++ b/src/test/ScriptTest.h @@ -11,10 +11,12 @@ class ScriptTest : public testing::Test { protected: crepe::Mediator mediator; + static constexpr const char * OBJ_NAME = "foo"; public: crepe::ComponentManager component_manager{mediator}; crepe::ScriptSystem system{mediator}; + crepe::GameObject entity = component_manager.new_object(OBJ_NAME); class MyScript : public crepe::Script { // NOTE: explicitly stating `public:` is not required on actual scripts -- cgit v1.2.3 From f3009ab8f0785a54d3fd83c0d758c8ebd901adda Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Sat, 7 Dec 2024 14:19:26 +0100 Subject: `make format` --- src/crepe/manager/ComponentManager.cpp | 11 ++++------- src/crepe/manager/ComponentManager.h | 5 +++-- src/crepe/manager/ComponentManager.hpp | 11 +++++++---- src/test/ECSTest.cpp | 1 - src/test/ScriptECSTest.cpp | 5 ++--- src/test/ScriptSceneTest.cpp | 1 - src/test/ScriptTest.cpp | 1 - 7 files changed, 16 insertions(+), 19 deletions(-) diff --git a/src/crepe/manager/ComponentManager.cpp b/src/crepe/manager/ComponentManager.cpp index 44774d9..df30d27 100644 --- a/src/crepe/manager/ComponentManager.cpp +++ b/src/crepe/manager/ComponentManager.cpp @@ -64,14 +64,11 @@ void ComponentManager::set_persistent(game_object_id_t id, bool persistent) { } set ComponentManager::get_objects_by_name(const string & name) const { - return this->get_objects_by_predicate([name](const Metadata & data) { - return data.name == name; - }); + return this->get_objects_by_predicate( + [name](const Metadata & data) { return data.name == name; }); } set ComponentManager::get_objects_by_tag(const string & tag) const { - return this->get_objects_by_predicate([tag](const Metadata & data) { - return data.tag == tag; - }); + return this->get_objects_by_predicate( + [tag](const Metadata & data) { return data.tag == tag; }); } - diff --git a/src/crepe/manager/ComponentManager.h b/src/crepe/manager/ComponentManager.h index 4e53954..685cae5 100644 --- a/src/crepe/manager/ComponentManager.h +++ b/src/crepe/manager/ComponentManager.h @@ -1,10 +1,10 @@ #pragma once #include +#include #include #include #include -#include #include "../Component.h" #include "../types.h" @@ -156,7 +156,8 @@ public: private: template - std::set get_objects_by_predicate(const std::function & pred) const; + std::set + get_objects_by_predicate(const std::function & pred) const; template RefVector get_components_by_ids(const std::set & ids) const; diff --git a/src/crepe/manager/ComponentManager.hpp b/src/crepe/manager/ComponentManager.hpp index 52df368..9e70865 100644 --- a/src/crepe/manager/ComponentManager.hpp +++ b/src/crepe/manager/ComponentManager.hpp @@ -101,7 +101,8 @@ RefVector ComponentManager::get_components_by_id(game_object_id_t id) const { type_index type = typeid(T); if (!this->components.contains(type)) return {}; - const by_id_index>> & components_by_id = this->components.at(type); + const by_id_index>> & components_by_id + = this->components.at(type); if (id >= components_by_id.size()) return {}; RefVector out = {}; @@ -151,7 +152,8 @@ RefVector ComponentManager::get_components_by_type() const { } template -std::set ComponentManager::get_objects_by_predicate(const std::function & pred) const { +std::set +ComponentManager::get_objects_by_predicate(const std::function & pred) const { using namespace std; set objects = {}; @@ -168,9 +170,10 @@ std::set ComponentManager::get_objects_by_predicate(const std: } template -RefVector ComponentManager::get_components_by_ids(const std::set & ids) const { +RefVector +ComponentManager::get_components_by_ids(const std::set & ids) const { using namespace std; - + RefVector out = {}; for (game_object_id_t id : ids) { RefVector components = get_components_by_id(id); diff --git a/src/test/ECSTest.cpp b/src/test/ECSTest.cpp index ed5341e..af2b7b0 100644 --- a/src/test/ECSTest.cpp +++ b/src/test/ECSTest.cpp @@ -466,4 +466,3 @@ TEST_F(ECSTest, ComponentsByTag) { EXPECT_EQ(objects.size(), 3); } } - diff --git a/src/test/ScriptECSTest.cpp b/src/test/ScriptECSTest.cpp index 4477e55..1ec33ba 100644 --- a/src/test/ScriptECSTest.cpp +++ b/src/test/ScriptECSTest.cpp @@ -4,8 +4,8 @@ #include #include -#include #include +#include #include #include @@ -32,8 +32,7 @@ TEST_F(ScriptECSTest, GetOwnComponent) { TEST_F(ScriptECSTest, GetOwnComponents) { const unsigned COUNT = 4; - for (unsigned i = 0; i < COUNT; i++) - entity.add_component(); + for (unsigned i = 0; i < COUNT; i++) entity.add_component(); MyScript & script = this->script; RefVector components = script.get_components(); diff --git a/src/test/ScriptSceneTest.cpp b/src/test/ScriptSceneTest.cpp index 8e849c1..2568049 100644 --- a/src/test/ScriptSceneTest.cpp +++ b/src/test/ScriptSceneTest.cpp @@ -28,4 +28,3 @@ TEST_F(ScriptSceneTest, Default) { script.set_next_scene(non_default_value); EXPECT_EQ(non_default_value, scene_manager.next_scene); } - diff --git a/src/test/ScriptTest.cpp b/src/test/ScriptTest.cpp index b0b2546..acdae70 100644 --- a/src/test/ScriptTest.cpp +++ b/src/test/ScriptTest.cpp @@ -73,4 +73,3 @@ TEST_F(ScriptTest, UpdateInactive) { system.update(); } } - -- cgit v1.2.3 From 76f94a8cdd2945e26d716191b664eb906ebb9032 Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Sat, 7 Dec 2024 14:36:08 +0100 Subject: add doxygen comments --- src/crepe/manager/ComponentManager.h | 40 +++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/src/crepe/manager/ComponentManager.h b/src/crepe/manager/ComponentManager.h index e7eeaa2..19a8e81 100644 --- a/src/crepe/manager/ComponentManager.h +++ b/src/crepe/manager/ComponentManager.h @@ -155,18 +155,55 @@ public: RefVector get_components_by_tag(const std::string & tag) const; private: + /** + * \brief Get object IDs by predicate function + * + * This function calls the predicate function \c pred for all components matching type \c T, + * and adds their parent game_object_id to a \c std::set if the predicate returns true. + * + * \tparam T The type of the component to check the predicate against + * \param pred Predicate function + * + * \note The predicate function may be called for multiple components with the same \c + * game_object_id. In this case, the ID is added if *any* call returns \c true. + * + * \returns game_object_id for all components where the predicate returned true + */ template std::set get_objects_by_predicate(const std::function & pred) const; + + /** + * \brief Get components of type \c T for multiple game object IDs + * + * \tparam T The type of the components to return + * \param ids The object IDs + * + * \return All components matching type \c T and one of the IDs in \c ids + */ template RefVector get_components_by_ids(const std::set & ids) const; + /** + * \brief Get object IDs for objects with name \c name + * + * \param name Object name to match + * \returns Object IDs where Metadata::name is equal to \c name + */ std::set get_objects_by_name(const std::string & name) const; + /** + * \brief Get object IDs for objects with tag \c tag + * + * \param tag Object tag to match + * \returns Object IDs where Metadata::tag is equal to \c tag + */ std::set get_objects_by_tag(const std::string & tag) const; private: + //! By Component \c std::type_index (readability helper type) template using by_type = std::unordered_map; + //! By \c game_object_id index (readability helper type) template using by_id_index = std::vector; /** @@ -188,9 +225,6 @@ private: game_object_id_t next_id = 0; }; -// template <> -// RefVector ComponentManager::get_components_by_id(game_object_id_t id) const; - } // namespace crepe #include "ComponentManager.hpp" -- cgit v1.2.3 From f19f37ae3eff84161f86e62a26fbd8b68f8f91a9 Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Sat, 7 Dec 2024 15:29:33 +0100 Subject: make SaveManager no longer a singleton --- src/crepe/manager/Mediator.h | 4 ++-- src/crepe/manager/SaveManager.cpp | 32 +++++++++++++--------------- src/crepe/manager/SaveManager.h | 27 ++++++++++-------------- src/example/CMakeLists.txt | 2 -- src/example/asset_manager.cpp | 36 -------------------------------- src/example/savemgr.cpp | 44 --------------------------------------- src/test/CMakeLists.txt | 1 + src/test/SaveManagerTest.cpp | 41 ++++++++++++++++++++++++++++++++++++ 8 files changed, 69 insertions(+), 118 deletions(-) delete mode 100644 src/example/asset_manager.cpp delete mode 100644 src/example/savemgr.cpp create mode 100644 src/test/SaveManagerTest.cpp diff --git a/src/crepe/manager/Mediator.h b/src/crepe/manager/Mediator.h index 8094d80..6507a74 100644 --- a/src/crepe/manager/Mediator.h +++ b/src/crepe/manager/Mediator.h @@ -5,13 +5,13 @@ // TODO: remove these singletons: #include "../facade/SDLContext.h" #include "EventManager.h" -#include "SaveManager.h" #include "api/LoopTimer.h" namespace crepe { class ComponentManager; class SceneManager; +class SaveManager; /** * Struct to pass references to classes that would otherwise need to be singletons down to @@ -28,7 +28,7 @@ class SceneManager; struct Mediator { OptionalRef component_manager; OptionalRef scene_manager; - OptionalRef save_manager = SaveManager::get_instance(); + OptionalRef save_manager; OptionalRef event_manager = EventManager::get_instance(); OptionalRef sdl_context = SDLContext::get_instance(); OptionalRef timer = LoopTimer::get_instance(); diff --git a/src/crepe/manager/SaveManager.cpp b/src/crepe/manager/SaveManager.cpp index d4ed1c1..292e8fd 100644 --- a/src/crepe/manager/SaveManager.cpp +++ b/src/crepe/manager/SaveManager.cpp @@ -1,13 +1,24 @@ #include "../ValueBroker.h" #include "../api/Config.h" #include "../facade/DB.h" -#include "../util/Log.h" #include "SaveManager.h" using namespace std; using namespace crepe; +SaveManager::SaveManager(Mediator & mediator) : Manager(mediator) { + mediator.save_manager = *this; +} + +DB & SaveManager::get_db() { + if (this->db == nullptr) { + Config & cfg = Config::get_instance(); + this->db = make_unique(cfg.savemgr.location); + } + return *this->db; +} + template <> string SaveManager::serialize(const string & value) const noexcept { return value; @@ -90,22 +101,6 @@ int32_t SaveManager::deserialize(const string & value) const noexcept { return deserialize(value); } -SaveManager::SaveManager() { dbg_trace(); } - -SaveManager & SaveManager::get_instance() { - dbg_trace(); - static SaveManager instance; - return instance; -} - -DB & SaveManager::get_db() { - Config & cfg = Config::get_instance(); - // TODO: make this path relative to XDG_DATA_HOME on Linux and whatever the - // default equivalent is on Windows using some third party library - static DB db(cfg.savemgr.location); - return db; -} - bool SaveManager::has(const string & key) { DB & db = this->get_db(); return db.has(key); @@ -155,7 +150,8 @@ ValueBroker SaveManager::get(const string & key) { return { [this, key](const T & target) { this->set(key, target); }, [this, key, value]() mutable -> const T & { - value = this->deserialize(this->get_db().get(key)); + DB & db = this->get_db(); + value = this->deserialize(db.get(key)); return value; }, }; diff --git a/src/crepe/manager/SaveManager.h b/src/crepe/manager/SaveManager.h index 3d8c852..d13a97a 100644 --- a/src/crepe/manager/SaveManager.h +++ b/src/crepe/manager/SaveManager.h @@ -4,6 +4,8 @@ #include "../ValueBroker.h" +#include "Manager.h" + namespace crepe { class DB; @@ -18,7 +20,7 @@ class DB; * * The underlying database is a key-value store. */ -class SaveManager { +class SaveManager : public Manager { public: /** * \brief Get a read/write reference to a value and initialize it if it does not yet exist @@ -63,8 +65,8 @@ public: */ bool has(const std::string & key); -private: - SaveManager(); +public: + SaveManager(Mediator & mediator); virtual ~SaveManager() = default; private: @@ -90,25 +92,18 @@ private: T deserialize(const std::string & value) const noexcept; public: - // singleton - static SaveManager & get_instance(); SaveManager(const SaveManager &) = delete; SaveManager(SaveManager &&) = delete; SaveManager & operator=(const SaveManager &) = delete; SaveManager & operator=(SaveManager &&) = delete; +protected: + //! Create or return DB + virtual DB & get_db(); + private: - /** - * \brief Create an instance of DB and return its reference - * - * \returns DB instance - * - * This function exists because DB is a facade class, which can't directly be used in the API - * without workarounds - * - * TODO: better solution - */ - static DB & get_db(); + //! Database + std::unique_ptr db = nullptr; }; } // namespace crepe diff --git a/src/example/CMakeLists.txt b/src/example/CMakeLists.txt index 8ef71bb..5a93b1f 100644 --- a/src/example/CMakeLists.txt +++ b/src/example/CMakeLists.txt @@ -16,8 +16,6 @@ function(add_example target_name) add_dependencies(examples ${target_name}) endfunction() -add_example(asset_manager) -add_example(savemgr) add_example(rendering_particle) add_example(game) add_example(button) diff --git a/src/example/asset_manager.cpp b/src/example/asset_manager.cpp deleted file mode 100644 index 917b547..0000000 --- a/src/example/asset_manager.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include -#include -#include - -using namespace crepe; - -int main() { - - // this needs to be called before the asset manager otherwise the destructor of sdl is not in - // the right order - { Texture test("../asset/texture/img.png"); } - // FIXME: make it so the issue described by the above comment is not possible (i.e. the order - // in which internal classes are instantiated should not impact the way the engine works). - - auto & mgr = AssetManager::get_instance(); - - { - // TODO: [design] the Sound class can't be directly included by the user as it includes - // SoLoud headers. - auto bgm = mgr.cache("../mwe/audio/bgm.ogg"); - auto sfx1 = mgr.cache("../mwe/audio/sfx1.wav"); - auto sfx2 = mgr.cache("../mwe/audio/sfx2.wav"); - - auto img = mgr.cache("../asset/texture/img.png"); - auto img1 = mgr.cache("../asset/texture/second.png"); - } - - { - auto bgm = mgr.cache("../mwe/audio/bgm.ogg"); - auto sfx1 = mgr.cache("../mwe/audio/sfx1.wav"); - auto sfx2 = mgr.cache("../mwe/audio/sfx2.wav"); - - auto img = mgr.cache("../asset/texture/img.png"); - auto img1 = mgr.cache("../asset/texture/second.png"); - } -} diff --git a/src/example/savemgr.cpp b/src/example/savemgr.cpp deleted file mode 100644 index 65c4a34..0000000 --- a/src/example/savemgr.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/** \file - * - * Standalone example for usage of the save manager - */ - -#include -#include -#include -#include -#include - -using namespace crepe; - -// unrelated setup code -int _ = []() { - // make sure all log messages get printed - auto & cfg = Config::get_instance(); - cfg.log.level = Log::Level::TRACE; - - return 0; // satisfy compiler -}(); - -int main() { - const char * key = "mygame.test"; - - SaveManager & mgr = SaveManager::get_instance(); - - dbg_logf("has key = {}", mgr.has(key)); - ValueBroker prop = mgr.get(key, 0); - Proxy val = mgr.get(key, 0); - - dbg_logf("val = {}", mgr.get(key).get()); - prop.set(1); - dbg_logf("val = {}", mgr.get(key).get()); - val = 2; - dbg_logf("val = {}", mgr.get(key).get()); - mgr.set(key, 3); - dbg_logf("val = {}", mgr.get(key).get()); - - dbg_logf("has key = {}", mgr.has(key)); - assert(true == mgr.has(key)); - - return 0; -} diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index c9cbac5..734e3ee 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -17,4 +17,5 @@ target_sources(test_main PUBLIC ScriptEventTest.cpp ScriptSceneTest.cpp Profiling.cpp + SaveManagerTest.cpp ) diff --git a/src/test/SaveManagerTest.cpp b/src/test/SaveManagerTest.cpp new file mode 100644 index 0000000..a1efc33 --- /dev/null +++ b/src/test/SaveManagerTest.cpp @@ -0,0 +1,41 @@ +#include + +#include +#include +#include + +using namespace std; +using namespace crepe; +using namespace testing; + +class SaveManagerTest : public Test { + Mediator m; + class TestSaveManager : public SaveManager { + using SaveManager::SaveManager; + + // in-memory database for testing + DB db{}; + virtual DB & get_db() override { return this->db; } + }; + +public: + TestSaveManager mgr{m}; +}; + +TEST_F(SaveManagerTest, ReadWrite) { + ASSERT_FALSE(mgr.has("foo")); + mgr.set("foo", "bar"); + ASSERT_TRUE(mgr.has("foo")); + + ValueBroker value = mgr.get("foo"); + EXPECT_EQ(value.get(), "bar"); +} + +TEST_F(SaveManagerTest, DefaultValue) { + ValueBroker value = mgr.get("foo", 3); + + ASSERT_EQ(value.get(), 3); + value.set(5); + ASSERT_EQ(value.get(), 5); +} + -- cgit v1.2.3 From 2e6fcb1d048edd13a2ec69ddd226fc8ebabc2389 Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Sat, 7 Dec 2024 16:01:19 +0100 Subject: add SaveManager to Script --- src/crepe/api/Script.cpp | 11 +++++++---- src/crepe/api/Script.h | 4 ++++ src/crepe/api/Script.hpp | 6 ++---- src/crepe/util/OptionalRef.h | 10 +++++++++- src/crepe/util/OptionalRef.hpp | 7 +++++++ src/test/CMakeLists.txt | 1 + src/test/ScriptSaveManagerTest.cpp | 36 ++++++++++++++++++++++++++++++++++++ 7 files changed, 66 insertions(+), 9 deletions(-) create mode 100644 src/test/ScriptSaveManagerTest.cpp diff --git a/src/crepe/api/Script.cpp b/src/crepe/api/Script.cpp index 4091fd4..961e6e7 100644 --- a/src/crepe/api/Script.cpp +++ b/src/crepe/api/Script.cpp @@ -8,8 +8,7 @@ using namespace crepe; using namespace std; Script::~Script() { - Mediator & mediator = this->mediator; - EventManager & mgr = mediator.event_manager; + EventManager & mgr = this->mediator->event_manager; for (auto id : this->listeners) { mgr.unsubscribe(id); } @@ -21,7 +20,11 @@ void Script::subscribe(const EventHandler & callback) { } void Script::set_next_scene(const string & name) { - Mediator & mediator = this->mediator; - SceneManager & mgr = mediator.scene_manager; + SceneManager & mgr = this->mediator->scene_manager; mgr.set_next_scene(name); } + +SaveManager & Script::get_save_manager() const { + return this->mediator->save_manager; +} + diff --git a/src/crepe/api/Script.h b/src/crepe/api/Script.h index d99ab0e..024f1d7 100644 --- a/src/crepe/api/Script.h +++ b/src/crepe/api/Script.h @@ -7,6 +7,7 @@ #include "../system/CollisionSystem.h" #include "../types.h" #include "../util/OptionalRef.h" +#include "../ValueBroker.h" namespace crepe { @@ -113,6 +114,9 @@ protected: */ void set_next_scene(const std::string & name); + //! Retrieve SaveManager reference + SaveManager & get_save_manager() const; + //! \} private: diff --git a/src/crepe/api/Script.hpp b/src/crepe/api/Script.hpp index 45f1ff1..23d69d9 100644 --- a/src/crepe/api/Script.hpp +++ b/src/crepe/api/Script.hpp @@ -20,8 +20,7 @@ T & Script::get_component() const { template RefVector Script::get_components() const { - Mediator & mediator = this->mediator; - ComponentManager & mgr = mediator.component_manager; + ComponentManager & mgr = this->mediator->component_manager; return mgr.get_components_by_id(this->game_object_id); } @@ -34,8 +33,7 @@ void Script::logf(Args &&... args) { template void Script::subscribe_internal(const EventHandler & callback, event_channel_t channel) { - Mediator & mediator = this->mediator; - EventManager & mgr = mediator.event_manager; + EventManager & mgr = this->mediator->event_manager; subscription_t listener = mgr.subscribe( [this, callback](const EventType & data) -> bool { bool & active = this->active; diff --git a/src/crepe/util/OptionalRef.h b/src/crepe/util/OptionalRef.h index 3201667..1b2cb3f 100644 --- a/src/crepe/util/OptionalRef.h +++ b/src/crepe/util/OptionalRef.h @@ -25,13 +25,21 @@ public: */ OptionalRef & operator=(T & ref); /** - * \brief Retrieve this reference + * \brief Retrieve this reference (cast) * * \returns Internal reference if it is set * * \throws std::runtime_error if this function is called while the reference it not set */ operator T &() const; + /** + * \brief Retrieve this reference (member access) + * + * \returns Internal reference if it is set + * + * \throws std::runtime_error if this function is called while the reference it not set + */ + T * operator->() const; /** * \brief Check if this reference is not empty * diff --git a/src/crepe/util/OptionalRef.hpp b/src/crepe/util/OptionalRef.hpp index 4608c9e..5e36b3a 100644 --- a/src/crepe/util/OptionalRef.hpp +++ b/src/crepe/util/OptionalRef.hpp @@ -18,6 +18,13 @@ OptionalRef::operator T &() const { return *this->ref; } +template +T * OptionalRef::operator->() const { + if (this->ref == nullptr) + throw std::runtime_error("OptionalRef: attempt to dereference nullptr"); + return this->ref; +} + template OptionalRef & OptionalRef::operator=(T & ref) { this->ref = &ref; diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index 734e3ee..2cb7c7a 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -18,4 +18,5 @@ target_sources(test_main PUBLIC ScriptSceneTest.cpp Profiling.cpp SaveManagerTest.cpp + ScriptSaveManagerTest.cpp ) diff --git a/src/test/ScriptSaveManagerTest.cpp b/src/test/ScriptSaveManagerTest.cpp new file mode 100644 index 0000000..098afa0 --- /dev/null +++ b/src/test/ScriptSaveManagerTest.cpp @@ -0,0 +1,36 @@ +#include + +// stupid hack to allow access to private/protected members under test +#define private public +#define protected public + +#include +#include + +#include "ScriptTest.h" + +using namespace std; +using namespace crepe; +using namespace testing; + +class ScriptSaveManagerTest : public ScriptTest { +public: + class TestSaveManager : public SaveManager { + using SaveManager::SaveManager; + + // in-memory database for testing + DB db{}; + virtual DB & get_db() override { return this->db; } + }; + + TestSaveManager save_mgr{mediator}; +}; + +TEST_F(ScriptSaveManagerTest, GetSaveManager) { + MyScript & script = this->script; + + SaveManager & mgr = script.get_save_manager(); + + EXPECT_EQ(&mgr, &save_mgr); +} + -- cgit v1.2.3 From dd8bbe2fde97786ab29490bc7ba9962deb08fb4c Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Sat, 7 Dec 2024 16:01:59 +0100 Subject: `make format` --- src/crepe/api/Script.cpp | 5 +---- src/crepe/api/Script.h | 2 +- src/test/SaveManagerTest.cpp | 5 ++--- src/test/ScriptSaveManagerTest.cpp | 3 +-- 4 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/crepe/api/Script.cpp b/src/crepe/api/Script.cpp index 961e6e7..753a9e3 100644 --- a/src/crepe/api/Script.cpp +++ b/src/crepe/api/Script.cpp @@ -24,7 +24,4 @@ void Script::set_next_scene(const string & name) { mgr.set_next_scene(name); } -SaveManager & Script::get_save_manager() const { - return this->mediator->save_manager; -} - +SaveManager & Script::get_save_manager() const { return this->mediator->save_manager; } diff --git a/src/crepe/api/Script.h b/src/crepe/api/Script.h index 024f1d7..0d59ab6 100644 --- a/src/crepe/api/Script.h +++ b/src/crepe/api/Script.h @@ -2,12 +2,12 @@ #include +#include "../ValueBroker.h" #include "../manager/EventManager.h" #include "../manager/Mediator.h" #include "../system/CollisionSystem.h" #include "../types.h" #include "../util/OptionalRef.h" -#include "../ValueBroker.h" namespace crepe { diff --git a/src/test/SaveManagerTest.cpp b/src/test/SaveManagerTest.cpp index a1efc33..e9b0c29 100644 --- a/src/test/SaveManagerTest.cpp +++ b/src/test/SaveManagerTest.cpp @@ -1,8 +1,8 @@ #include -#include -#include #include +#include +#include using namespace std; using namespace crepe; @@ -38,4 +38,3 @@ TEST_F(SaveManagerTest, DefaultValue) { value.set(5); ASSERT_EQ(value.get(), 5); } - diff --git a/src/test/ScriptSaveManagerTest.cpp b/src/test/ScriptSaveManagerTest.cpp index 098afa0..64403c4 100644 --- a/src/test/ScriptSaveManagerTest.cpp +++ b/src/test/ScriptSaveManagerTest.cpp @@ -4,8 +4,8 @@ #define private public #define protected public -#include #include +#include #include "ScriptTest.h" @@ -33,4 +33,3 @@ TEST_F(ScriptSaveManagerTest, GetSaveManager) { EXPECT_EQ(&mgr, &save_mgr); } - -- cgit v1.2.3 From b5bf36aec3caa879d77457e3b2d1d29b6b625f27 Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Sat, 7 Dec 2024 16:03:47 +0100 Subject: minor cleanup --- src/crepe/api/Script.h | 1 - src/crepe/manager/SaveManager.h | 7 ------- 2 files changed, 8 deletions(-) diff --git a/src/crepe/api/Script.h b/src/crepe/api/Script.h index 0d59ab6..3417bb4 100644 --- a/src/crepe/api/Script.h +++ b/src/crepe/api/Script.h @@ -2,7 +2,6 @@ #include -#include "../ValueBroker.h" #include "../manager/EventManager.h" #include "../manager/Mediator.h" #include "../system/CollisionSystem.h" diff --git a/src/crepe/manager/SaveManager.h b/src/crepe/manager/SaveManager.h index d13a97a..1b55a22 100644 --- a/src/crepe/manager/SaveManager.h +++ b/src/crepe/manager/SaveManager.h @@ -91,16 +91,9 @@ private: template T deserialize(const std::string & value) const noexcept; -public: - SaveManager(const SaveManager &) = delete; - SaveManager(SaveManager &&) = delete; - SaveManager & operator=(const SaveManager &) = delete; - SaveManager & operator=(SaveManager &&) = delete; - protected: //! Create or return DB virtual DB & get_db(); - private: //! Database std::unique_ptr db = nullptr; -- cgit v1.2.3 From 6cee1cff083fc50eeedf88537965d3c79e7b790a Mon Sep 17 00:00:00 2001 From: max-001 Date: Mon, 9 Dec 2024 11:28:06 +0100 Subject: Added Doxygen --- src/crepe/api/AI.cpp | 23 ++++++++++++++++++++ src/crepe/api/AI.h | 50 ++++++++++++++++++++++++++++++++++--------- src/crepe/system/AISystem.cpp | 1 + src/crepe/system/AISystem.h | 44 +++++++++++++++++++++++++++++++++++++ src/example/AITest.cpp | 10 ++++----- 5 files changed, 112 insertions(+), 16 deletions(-) diff --git a/src/crepe/api/AI.cpp b/src/crepe/api/AI.cpp index d785bb5..49f6b92 100644 --- a/src/crepe/api/AI.cpp +++ b/src/crepe/api/AI.cpp @@ -4,4 +4,27 @@ namespace crepe { AI::AI(game_object_id_t id, float max_force) : Component(id), max_force(max_force) {} +void AI::make_circle_path(float radius, vec2 center, float start_angle, bool clockwise) { + // The step size is determined by the radius (step size is in radians) + float step = 400.0f / radius; + // Force at least 16 steps (in case of a small radius) + if (step > 2 * M_PI / 16) { + step = 2 * M_PI / 16; + } + // The path node distance is determined by the step size and the radius + path_node_distance = radius * step * 0.75f; + + if (clockwise) { + for (float i = start_angle; i < 2 * M_PI + start_angle; i += step) { + path.push_back(vec2{static_cast(center.x + radius * cos(i)), + static_cast(center.y + radius * sin(i))}); + } + } else { + for (float i = start_angle; i > start_angle - 2 * M_PI; i -= step) { + path.push_back(vec2{static_cast(center.x + radius * cos(i)), + static_cast(center.y + radius * sin(i))}); + } + } +} + } // namespace crepe diff --git a/src/crepe/api/AI.h b/src/crepe/api/AI.h index 35b8998..9f5c0a8 100644 --- a/src/crepe/api/AI.h +++ b/src/crepe/api/AI.h @@ -5,8 +5,15 @@ namespace crepe { +/** + * \brief The AI component is used to control the movement of an entity using AI. + * + * The AI component can be used to control the movement of an entity. The AI component can be used + * to implement different behaviors such as seeking, fleeing, arriving, and path following. + */ class AI : public Component { public: + //! The different types of behaviors that can be used enum BehaviorType { NONE = 0x00000, SEEK = 0x00002, @@ -16,53 +23,76 @@ public: }; public: + /** + * \param id The id of the game object + * \param max_force The maximum force that can be applied to the entity + */ AI(game_object_id_t id, float max_force); + /** + * \brief Check if a behavior is on/activated + * + * \param behavior The behavior to check + * \return true if the behavior is on, false otherwise + */ bool on(BehaviorType behavior) const { return (flags & behavior) == behavior; } + //! Turn on the seek behavior void seek_on() { flags |= SEEK; } + //! Turn off the seek behavior void seek_off() { if (on(SEEK)) flags ^= SEEK; } + //! Turn on the flee behavior void flee_on() { flags |= FLEE; } + //! Turn off the flee behavior void flee_off() { if (on(FLEE)) flags ^= FLEE; } + //! Turn on the arrive behavior void arrive_on() { flags |= ARRIVE; } + //! Turn off the arrive behavior void arrive_off() { if (on(ARRIVE)) flags ^= ARRIVE; } + //! Turn on the path follow behavior void path_follow_on() { flags |= PATH_FOLLOW; } + //! Turn off the path follow behavior void path_follow_off() { if (on(PATH_FOLLOW)) flags ^= PATH_FOLLOW; } + //! Add a path node to the path void add_path_node(vec2 node) { path.push_back(node); } + //! Create a circle path + void make_circle_path(float radius, vec2 center = {0, 0}, float start_angle = 0, + bool clockwise = true); public: + //! The maximum force that can be applied to the entity (higher values will make the entity adjust faster) float max_force; - // The target to seek or arrive at + //! The target to seek or arrive at vec2 seek_target; - // The target to flee from + //! The target to flee from vec2 flee_target; - // The distance at which the entity will start to flee from the target + //! The distance at which the entity will start to flee from the target float square_flee_panic_distance = 200.0f * 200.0f; - // The deceleration rate for the arrive behavior (higher values will make the entity decelerate faster (less overshoot)) + //! The deceleration rate for the arrive behavior (higher values will make the entity decelerate faster (less overshoot)) float arrive_deceleration = 40.0f; - // The path to follow + //! The path to follow std::vector path; - // The distance from the path node at which the entity will move to the next node + //! The distance from the path node at which the entity will move to the next node float path_node_distance = 400.0f; - // Looping behavior for the path + //! Looping behavior for the path bool path_loop = true; private: - // The flags for the behaviors + //! The flags for the behaviors int flags = 0; - // The current path index + //! The current path index size_t path_index = 0; - // The AISystem is the only class that can access the private members of AI + //! The AISystem is the only class that should access the flags and path_index variables friend class AISystem; }; diff --git a/src/crepe/system/AISystem.cpp b/src/crepe/system/AISystem.cpp index 55dc14c..7b801c3 100644 --- a/src/crepe/system/AISystem.cpp +++ b/src/crepe/system/AISystem.cpp @@ -17,6 +17,7 @@ void AISystem::update() { ComponentManager & mgr = mediator.component_manager; RefVector ai_components = mgr.get_components_by_type(); + //TODO: Use fixed loop dt (this is not available at master at the moment) double dt = LoopTimer::get_instance().get_delta_time(); for (AI & ai : ai_components) { diff --git a/src/crepe/system/AISystem.h b/src/crepe/system/AISystem.h index 27861d9..670d20d 100644 --- a/src/crepe/system/AISystem.h +++ b/src/crepe/system/AISystem.h @@ -7,19 +7,63 @@ namespace crepe { +/** + * \brief The AISystem is used to control the movement of entities using AI. + * + * The AISystem is used to control the movement of entities using AI. The AISystem can be used to + * implement different behaviors such as seeking, fleeing, arriving, and path following. + */ class AISystem : public System { public: using System::System; + //! Update the AI system void update() override; private: + /** + * \brief Calculate the total force to apply to the entity + * + * \param ai The AI component + */ vec2 calculate(AI & ai); + /** + * \brief Accumulate the force to apply to the entity + * + * \param ai The AI component + * \param running_total The running total of the force + * \param force_to_add The force to add + * \return true if the force was added, false otherwise + */ bool accumulate_force(AI & ai, vec2 & running_total, vec2 force_to_add); + /** + * \brief Calculate the seek force + * + * \param ai The AI component + * \return The seek force + */ vec2 seek(const AI & ai); + /** + * \brief Calculate the flee force + * + * \param ai The AI component + * \return The flee force + */ vec2 flee(const AI & ai); + /** + * \brief Calculate the arrive force + * + * \param ai The AI component + * \return The arrive force + */ vec2 arrive(const AI & ai); + /** + * \brief Calculate the path follow force + * + * \param ai The AI component + * \return The path follow force + */ vec2 path_follow(AI & ai); }; diff --git a/src/example/AITest.cpp b/src/example/AITest.cpp index d12a99a..72e06cf 100644 --- a/src/example/AITest.cpp +++ b/src/example/AITest.cpp @@ -52,16 +52,14 @@ public: Texture img = Texture("asset/texture/test_ap43.png"); game_object1.add_component(img, Color::MAGENTA, Sprite::FlipSettings{false, false}, 1, 1, 195); - AI & ai = game_object1.add_component(300); + AI & ai = game_object1.add_component(3000); // ai.arrive_on(); // ai.flee_on(); ai.path_follow_on(); - ai.add_path_node(vec2{1200, 1200}); - ai.add_path_node(vec2{-1200, 1200}); - ai.add_path_node(vec2{1200, -1200}); - ai.add_path_node(vec2{-1200, -1200}); + ai.make_circle_path(1000, {0, -1000}, 1.5707, true); + ai.make_circle_path(1000, {0, 1000}, 4.7124, false); game_object1.add_component(Rigidbody::Data{ - .mass = 0.5f, .max_linear_velocity = {50, 50}, // sqrt(21^2 + 21^2) = 30 + .mass = 0.5f, .max_linear_velocity = {40, 40}, // sqrt(21^2 + 21^2) = 30 }); game_object1.add_component().set_script(); -- cgit v1.2.3 From 54d93519e90569a6f127da301e6e612ef89f2fc3 Mon Sep 17 00:00:00 2001 From: max-001 Date: Mon, 9 Dec 2024 11:29:11 +0100 Subject: Deleted unnecessary header --- src/example/AITest.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/example/AITest.cpp b/src/example/AITest.cpp index 72e06cf..857eb94 100644 --- a/src/example/AITest.cpp +++ b/src/example/AITest.cpp @@ -1,5 +1,3 @@ -#include -#include #include #include #include -- cgit v1.2.3 From f5169437395a8cdec4654c7d2bfef952f3dcde2c Mon Sep 17 00:00:00 2001 From: max-001 Date: Mon, 9 Dec 2024 11:36:07 +0100 Subject: Improved Doxygen --- src/crepe/api/AI.h | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/crepe/api/AI.h b/src/crepe/api/AI.h index 9f5c0a8..18276a1 100644 --- a/src/crepe/api/AI.h +++ b/src/crepe/api/AI.h @@ -61,9 +61,24 @@ public: if (on(PATH_FOLLOW)) flags ^= PATH_FOLLOW; } - //! Add a path node to the path + /** + * \brief Add a path node + * + * \note The path is not relative to the entity's position (it is an absolute path) + * + * \param node The path node to add + */ void add_path_node(vec2 node) { path.push_back(node); } - //! Create a circle path + /** + * \brief Make a circle path + * + * \note The path is not relative to the entity's position (it is an absolute path) + * + * \param radius The radius of the circle (in game units) + * \param center The center of the circle (in game units) + * \param start_angle The start angle of the circle (in radians) + * \param clockwise The direction of the circle + */ void make_circle_path(float radius, vec2 center = {0, 0}, float start_angle = 0, bool clockwise = true); -- cgit v1.2.3 From c43885fa393ddf4ab28ad55643100f987b82abdc Mon Sep 17 00:00:00 2001 From: max-001 Date: Mon, 9 Dec 2024 11:36:24 +0100 Subject: Modified path_follow a bit --- src/crepe/system/AISystem.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/crepe/system/AISystem.cpp b/src/crepe/system/AISystem.cpp index 7b801c3..72f3d9b 100644 --- a/src/crepe/system/AISystem.cpp +++ b/src/crepe/system/AISystem.cpp @@ -152,9 +152,10 @@ vec2 AISystem::path_follow(AI & ai) { return vec2{0, 0}; } - vec2 to_target = ai.path.at(ai.path_index) - transform.position; + vec2 target = ai.path.at(ai.path_index); + vec2 to_target = target - transform.position; if (to_target.length_squared() > ai.path_node_distance * ai.path_node_distance) { - ai.seek_target = ai.path.at(ai.path_index); + ai.seek_target = target; } else { ai.path_index++; if (ai.path_index >= ai.path.size()) { -- cgit v1.2.3 From a4d76993e51ac4486fc313e868285eb7b4cb89f2 Mon Sep 17 00:00:00 2001 From: max-001 Date: Mon, 9 Dec 2024 12:04:26 +0100 Subject: Make format --- src/example/AITest.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/example/AITest.cpp b/src/example/AITest.cpp index 857eb94..0920fb2 100644 --- a/src/example/AITest.cpp +++ b/src/example/AITest.cpp @@ -57,7 +57,8 @@ public: ai.make_circle_path(1000, {0, -1000}, 1.5707, true); ai.make_circle_path(1000, {0, 1000}, 4.7124, false); game_object1.add_component(Rigidbody::Data{ - .mass = 0.5f, .max_linear_velocity = {40, 40}, // sqrt(21^2 + 21^2) = 30 + .mass = 0.5f, + .max_linear_velocity = {40, 40}, }); game_object1.add_component().set_script(); -- cgit v1.2.3 From 34afa0036dc1fce79ea3db1885a56f9c395f29aa Mon Sep 17 00:00:00 2001 From: max-001 Date: Mon, 9 Dec 2024 13:27:10 +0100 Subject: Deleted header --- src/crepe/api/LoopManager.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/crepe/api/LoopManager.cpp b/src/crepe/api/LoopManager.cpp index cf8a0d0..558ff3a 100644 --- a/src/crepe/api/LoopManager.cpp +++ b/src/crepe/api/LoopManager.cpp @@ -1,4 +1,3 @@ -#include "../facade/SDLContext.h" #include "../system/AISystem.h" #include "../system/AnimatorSystem.h" #include "../system/CollisionSystem.h" -- cgit v1.2.3 From d41730984f971489fb4b14b73ce2888ad1858efe Mon Sep 17 00:00:00 2001 From: max-001 Date: Mon, 9 Dec 2024 13:28:29 +0100 Subject: Fixed merge issue --- src/crepe/api/LoopManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crepe/api/LoopManager.cpp b/src/crepe/api/LoopManager.cpp index 558ff3a..7617600 100644 --- a/src/crepe/api/LoopManager.cpp +++ b/src/crepe/api/LoopManager.cpp @@ -77,4 +77,4 @@ void LoopManager::render() { this->get_system().update(); } -void LoopManager::update() { this->get_system().update(); } +void LoopManager::update() {} -- cgit v1.2.3 From a12986c0855e68ac027c2686223813c112960165 Mon Sep 17 00:00:00 2001 From: max-001 Date: Mon, 9 Dec 2024 13:32:18 +0100 Subject: Fixed merge issue --- src/crepe/api/Script.h | 1 - src/example/game.cpp | 4 ---- 2 files changed, 5 deletions(-) diff --git a/src/crepe/api/Script.h b/src/crepe/api/Script.h index e351e6a..d99ab0e 100644 --- a/src/crepe/api/Script.h +++ b/src/crepe/api/Script.h @@ -7,7 +7,6 @@ #include "../system/CollisionSystem.h" #include "../types.h" #include "../util/OptionalRef.h" -#include "system/CollisionSystem.h" namespace crepe { diff --git a/src/example/game.cpp b/src/example/game.cpp index 2b4e46f..4239c15 100644 --- a/src/example/game.cpp +++ b/src/example/game.cpp @@ -66,10 +66,6 @@ class MyScript1 : public Script { //add collider switch break; } - case Keycode::Q: { - throw "Test"; - break; - } default: break; } -- cgit v1.2.3 From cdaf587006053874c2e286a7541e6a2b246ce2b3 Mon Sep 17 00:00:00 2001 From: max-001 Date: Mon, 9 Dec 2024 13:49:34 +0100 Subject: Added comments --- src/crepe/api/AI.h | 10 +++++----- src/crepe/system/AISystem.cpp | 23 ++++++++++++++++++++++- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/crepe/api/AI.h b/src/crepe/api/AI.h index 18276a1..0dccd5f 100644 --- a/src/crepe/api/AI.h +++ b/src/crepe/api/AI.h @@ -30,7 +30,7 @@ public: AI(game_object_id_t id, float max_force); /** - * \brief Check if a behavior is on/activated + * \brief Check if a behavior is on (aka activated) * * \param behavior The behavior to check * \return true if the behavior is on, false otherwise @@ -62,7 +62,7 @@ public: } /** - * \brief Add a path node + * \brief Add a path node (for the path following behavior) * * \note The path is not relative to the entity's position (it is an absolute path) * @@ -70,7 +70,7 @@ public: */ void add_path_node(vec2 node) { path.push_back(node); } /** - * \brief Make a circle path + * \brief Make a circle path (for the path following behavior) * * \note The path is not relative to the entity's position (it is an absolute path) * @@ -94,9 +94,9 @@ public: float square_flee_panic_distance = 200.0f * 200.0f; //! The deceleration rate for the arrive behavior (higher values will make the entity decelerate faster (less overshoot)) float arrive_deceleration = 40.0f; - //! The path to follow + //! The path to follow (for the path following behavior) std::vector path; - //! The distance from the path node at which the entity will move to the next node + //! The distance from the path node at which the entity will move to the next node (automatically set by make_circle_path()) float path_node_distance = 400.0f; //! Looping behavior for the path bool path_loop = true; diff --git a/src/crepe/system/AISystem.cpp b/src/crepe/system/AISystem.cpp index 72f3d9b..8be5ddc 100644 --- a/src/crepe/system/AISystem.cpp +++ b/src/crepe/system/AISystem.cpp @@ -20,13 +20,21 @@ void AISystem::update() { //TODO: Use fixed loop dt (this is not available at master at the moment) double dt = LoopTimer::get_instance().get_delta_time(); + // Loop through all AI components for (AI & ai : ai_components) { + if (!ai.active) { + continue; + } + RefVector rigidbodies = mgr.get_components_by_id(ai.game_object_id); Rigidbody & rigidbody = rigidbodies.front().get(); + // Calculate the force to apply to the entity vec2 force = this->calculate(ai); + // Calculate the acceleration (using the above calculated force) vec2 acceleration = force / rigidbody.data.mass; + // Finally, update Rigidbody's velocity rigidbody.data.linear_velocity += acceleration * dt; } } @@ -34,6 +42,7 @@ void AISystem::update() { vec2 AISystem::calculate(AI & ai) { vec2 force; + // Run all the behaviors that are on, and stop if the force gets too high if (ai.on(AI::BehaviorType::FLEE)) { vec2 force_to_add = this->flee(ai); @@ -71,13 +80,16 @@ bool AISystem::accumulate_force(AI & ai, vec2 & running_total, vec2 force_to_add float magnitude_remaining = ai.max_force - magnitude; if (magnitude_remaining <= 0.0f) { + // If the force is already at/above the max force, return false return false; } float magnitude_to_add = force_to_add.length(); if (magnitude_to_add < magnitude_remaining) { + // If the force to add is less than the remaining force, add it running_total += force_to_add; } else { + // If the force to add is greater than the remaining force, add a fraction of it force_to_add.normalize(); running_total += force_to_add * magnitude_remaining; } @@ -93,6 +105,7 @@ vec2 AISystem::seek(const AI & ai) { RefVector rigidbodies = mgr.get_components_by_id(ai.game_object_id); Rigidbody & rigidbody = rigidbodies.front().get(); + // Calculate the desired velocity vec2 desired_velocity = ai.seek_target - transform.position; desired_velocity.normalize(); desired_velocity *= rigidbody.data.max_linear_velocity; @@ -108,11 +121,11 @@ vec2 AISystem::flee(const AI & ai) { RefVector rigidbodies = mgr.get_components_by_id(ai.game_object_id); Rigidbody & rigidbody = rigidbodies.front().get(); + // Calculate the desired velocity if the entity is within the panic distance vec2 desired_velocity = transform.position - ai.flee_target; if (desired_velocity.length_squared() > ai.square_flee_panic_distance) { return vec2{0, 0}; } - desired_velocity.normalize(); desired_velocity *= rigidbody.data.max_linear_velocity; @@ -127,6 +140,7 @@ vec2 AISystem::arrive(const AI & ai) { RefVector rigidbodies = mgr.get_components_by_id(ai.game_object_id); Rigidbody & rigidbody = rigidbodies.front().get(); + // Calculate the desired velocity (taking into account the deceleration rate) vec2 to_target = ai.seek_target - transform.position; float distance = to_target.length(); if (distance > 0.0f) { @@ -152,21 +166,28 @@ vec2 AISystem::path_follow(AI & ai) { return vec2{0, 0}; } + // Get the target node vec2 target = ai.path.at(ai.path_index); + // Calculate the force to apply to the entity vec2 to_target = target - transform.position; if (to_target.length_squared() > ai.path_node_distance * ai.path_node_distance) { + // If the entity is not close enough to the target node, seek it ai.seek_target = target; } else { + // If the entity is close enough to the target node, move to the next node ai.path_index++; if (ai.path_index >= ai.path.size()) { if (ai.path_loop) { + // If the path is looping, reset the path index ai.path_index = 0; } else { + // If the path is not looping, arrive at the last node ai.path_index = ai.path.size() - 1; return this->arrive(ai); } } } + // Seek the target node return this->seek(ai); } -- cgit v1.2.3 From 857e408d6d3a8631b61ebd283b337819783f092c Mon Sep 17 00:00:00 2001 From: max-001 Date: Mon, 9 Dec 2024 14:14:03 +0100 Subject: Implemented oval path --- src/crepe/api/AI.cpp | 46 ++++++++++++++++++++++++++++++++++++++++++++++ src/crepe/api/AI.h | 14 ++++++++++++++ src/example/AITest.cpp | 4 ++-- 3 files changed, 62 insertions(+), 2 deletions(-) diff --git a/src/crepe/api/AI.cpp b/src/crepe/api/AI.cpp index 49f6b92..00e5b37 100644 --- a/src/crepe/api/AI.cpp +++ b/src/crepe/api/AI.cpp @@ -27,4 +27,50 @@ void AI::make_circle_path(float radius, vec2 center, float start_angle, bool clo } } +void AI::make_oval_path(float radius_x, float radius_y, vec2 center, float start_angle, + bool clockwise, float rotation) { + float max_radius = std::max(radius_x, radius_y); + // The step size is determined by the radius (step size is in radians) + float step = 400.0f / max_radius; + // Force at least 16 steps (in case of a small radius) + if (step > 2 * M_PI / 16) { + step = 2 * M_PI / 16; + } + // The path node distance is determined by the step size and the radius + path_node_distance = max_radius * step * 0.75f; + + auto rotate_point = [rotation](vec2 point, vec2 center) { + float s = sin(rotation); + float c = cos(rotation); + + // Translate point back to origin + point.x -= center.x; + point.y -= center.y; + + // Rotate point + float xnew = point.x * c - point.y * s; + float ynew = point.x * s + point.y * c; + + // Translate point back + point.x = xnew + center.x; + point.y = ynew + center.y; + + return point; + }; + + if (clockwise) { + for (float i = start_angle; i < 2 * M_PI + start_angle; i += step) { + vec2 point = {static_cast(center.x + radius_x * cos(i)), + static_cast(center.y + radius_y * sin(i))}; + path.push_back(rotate_point(point, center)); + } + } else { + for (float i = start_angle; i > start_angle - 2 * M_PI; i -= step) { + vec2 point = {static_cast(center.x + radius_x * cos(i)), + static_cast(center.y + radius_y * sin(i))}; + path.push_back(rotate_point(point, center)); + } + } +} + } // namespace crepe diff --git a/src/crepe/api/AI.h b/src/crepe/api/AI.h index 0dccd5f..c95924d 100644 --- a/src/crepe/api/AI.h +++ b/src/crepe/api/AI.h @@ -81,6 +81,20 @@ public: */ void make_circle_path(float radius, vec2 center = {0, 0}, float start_angle = 0, bool clockwise = true); + /** + * \brief Make an oval path (for the path following behavior) + * + * \note The path is not relative to the entity's position (it is an absolute path) + * + * \param radius_x The x radius of the oval (in game units) + * \param radius_y The y radius of the oval (in game units) + * \param center The center of the oval (in game units) + * \param start_angle The start angle of the oval (in radians) + * \param clockwise The direction of the oval + * \param rotation The rotation of the oval (in radians) + */ + void make_oval_path(float radius_x, float radius_y, vec2 center = {0, 0}, + float start_angle = 0, bool clockwise = true, float rotation = 0); public: //! The maximum force that can be applied to the entity (higher values will make the entity adjust faster) diff --git a/src/example/AITest.cpp b/src/example/AITest.cpp index 28537ed..f4efc9f 100644 --- a/src/example/AITest.cpp +++ b/src/example/AITest.cpp @@ -59,8 +59,8 @@ public: // ai.arrive_on(); // ai.flee_on(); ai.path_follow_on(); - ai.make_circle_path(1000, {0, -1000}, 1.5707, true); - ai.make_circle_path(1000, {0, 1000}, 4.7124, false); + ai.make_oval_path(500, 1000, {0, -1000}, 1.5708, true); + ai.make_oval_path(1000, 500, {0, 500}, 4.7124, false); game_object1.add_component(Rigidbody::Data{ .mass = 0.1f, .max_linear_velocity = {40, 40}, -- cgit v1.2.3 From e5e2eefc7f0f6199fe2b36688b2ad64a97784717 Mon Sep 17 00:00:00 2001 From: max-001 Date: Mon, 9 Dec 2024 14:15:24 +0100 Subject: Deleted header --- src/crepe/system/AISystem.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/crepe/system/AISystem.cpp b/src/crepe/system/AISystem.cpp index 8be5ddc..62fa553 100644 --- a/src/crepe/system/AISystem.cpp +++ b/src/crepe/system/AISystem.cpp @@ -8,7 +8,6 @@ #include "manager/Mediator.h" #include "AISystem.h" -#include "types.h" using namespace crepe; -- cgit v1.2.3 From c8d05f759bb1be0ec99e8f23eaa65c80c36ce03d Mon Sep 17 00:00:00 2001 From: max-001 Date: Tue, 10 Dec 2024 08:48:06 +0100 Subject: Implemented feedback --- src/crepe/api/AI.cpp | 15 ++++++++++++-- src/crepe/api/AI.h | 6 +++--- src/crepe/system/AISystem.cpp | 46 ++++++++++++++++++++++--------------------- src/crepe/system/AISystem.h | 18 +++++++++++------ 4 files changed, 52 insertions(+), 33 deletions(-) diff --git a/src/crepe/api/AI.cpp b/src/crepe/api/AI.cpp index 00e5b37..472550b 100644 --- a/src/crepe/api/AI.cpp +++ b/src/crepe/api/AI.cpp @@ -1,10 +1,17 @@ +#include + #include "AI.h" namespace crepe { AI::AI(game_object_id_t id, float max_force) : Component(id), max_force(max_force) {} -void AI::make_circle_path(float radius, vec2 center, float start_angle, bool clockwise) { +void AI::make_circle_path(float radius, const vec2 & center, float start_angle, + bool clockwise) { + if (radius <= 0) { + throw std::runtime_error("Radius must be greater than 0"); + } + // The step size is determined by the radius (step size is in radians) float step = 400.0f / radius; // Force at least 16 steps (in case of a small radius) @@ -27,8 +34,12 @@ void AI::make_circle_path(float radius, vec2 center, float start_angle, bool clo } } -void AI::make_oval_path(float radius_x, float radius_y, vec2 center, float start_angle, +void AI::make_oval_path(float radius_x, float radius_y, const vec2 & center, float start_angle, bool clockwise, float rotation) { + if (radius_x <= 0 && radius_y <= 0) { + throw std::runtime_error("Radius must be greater than 0"); + } + float max_radius = std::max(radius_x, radius_y); // The step size is determined by the radius (step size is in radians) float step = 400.0f / max_radius; diff --git a/src/crepe/api/AI.h b/src/crepe/api/AI.h index c95924d..de574cd 100644 --- a/src/crepe/api/AI.h +++ b/src/crepe/api/AI.h @@ -68,7 +68,7 @@ public: * * \param node The path node to add */ - void add_path_node(vec2 node) { path.push_back(node); } + void add_path_node(const vec2 & node) { path.push_back(node); } /** * \brief Make a circle path (for the path following behavior) * @@ -79,7 +79,7 @@ public: * \param start_angle The start angle of the circle (in radians) * \param clockwise The direction of the circle */ - void make_circle_path(float radius, vec2 center = {0, 0}, float start_angle = 0, + void make_circle_path(float radius, const vec2 & center = {0, 0}, float start_angle = 0, bool clockwise = true); /** * \brief Make an oval path (for the path following behavior) @@ -93,7 +93,7 @@ public: * \param clockwise The direction of the oval * \param rotation The rotation of the oval (in radians) */ - void make_oval_path(float radius_x, float radius_y, vec2 center = {0, 0}, + void make_oval_path(float radius_x, float radius_y, const vec2 & center = {0, 0}, float start_angle = 0, bool clockwise = true, float rotation = 0); public: diff --git a/src/crepe/system/AISystem.cpp b/src/crepe/system/AISystem.cpp index 62fa553..4d5039b 100644 --- a/src/crepe/system/AISystem.cpp +++ b/src/crepe/system/AISystem.cpp @@ -2,7 +2,6 @@ #include #include "api/LoopTimer.h" -#include "api/Rigidbody.h" #include "api/Transform.h" #include "manager/ComponentManager.h" #include "manager/Mediator.h" @@ -27,10 +26,17 @@ void AISystem::update() { RefVector rigidbodies = mgr.get_components_by_id(ai.game_object_id); + if (rigidbodies.empty()) { + throw std::runtime_error( + "AI component must be attached to a GameObject with a Rigidbody component"); + } Rigidbody & rigidbody = rigidbodies.front().get(); + if (rigidbody.data.mass <= 0) { + throw std::runtime_error("Mass must be greater than 0"); + } // Calculate the force to apply to the entity - vec2 force = this->calculate(ai); + vec2 force = this->calculate(ai, rigidbody); // Calculate the acceleration (using the above calculated force) vec2 acceleration = force / rigidbody.data.mass; // Finally, update Rigidbody's velocity @@ -38,33 +44,33 @@ void AISystem::update() { } } -vec2 AISystem::calculate(AI & ai) { +vec2 AISystem::calculate(AI & ai, const Rigidbody & rigidbody) { vec2 force; // Run all the behaviors that are on, and stop if the force gets too high if (ai.on(AI::BehaviorType::FLEE)) { - vec2 force_to_add = this->flee(ai); + vec2 force_to_add = this->flee(ai, rigidbody); if (!this->accumulate_force(ai, force, force_to_add)) { return force; } } if (ai.on(AI::BehaviorType::ARRIVE)) { - vec2 force_to_add = this->arrive(ai); + vec2 force_to_add = this->arrive(ai, rigidbody); if (!this->accumulate_force(ai, force, force_to_add)) { return force; } } if (ai.on(AI::BehaviorType::SEEK)) { - vec2 force_to_add = this->seek(ai); + vec2 force_to_add = this->seek(ai, rigidbody); if (!this->accumulate_force(ai, force, force_to_add)) { return force; } } if (ai.on(AI::BehaviorType::PATH_FOLLOW)) { - vec2 force_to_add = this->path_follow(ai); + vec2 force_to_add = this->path_follow(ai, rigidbody); if (!this->accumulate_force(ai, force, force_to_add)) { return force; @@ -74,7 +80,7 @@ vec2 AISystem::calculate(AI & ai) { return force; } -bool AISystem::accumulate_force(AI & ai, vec2 & running_total, vec2 force_to_add) { +bool AISystem::accumulate_force(const AI & ai, vec2 & running_total, vec2 force_to_add) { float magnitude = running_total.length(); float magnitude_remaining = ai.max_force - magnitude; @@ -96,13 +102,11 @@ bool AISystem::accumulate_force(AI & ai, vec2 & running_total, vec2 force_to_add return true; } -vec2 AISystem::seek(const AI & ai) { +vec2 AISystem::seek(const AI & ai, const Rigidbody & rigidbody) const { const Mediator & mediator = this->mediator; ComponentManager & mgr = mediator.component_manager; RefVector transforms = mgr.get_components_by_id(ai.game_object_id); Transform & transform = transforms.front().get(); - RefVector rigidbodies = mgr.get_components_by_id(ai.game_object_id); - Rigidbody & rigidbody = rigidbodies.front().get(); // Calculate the desired velocity vec2 desired_velocity = ai.seek_target - transform.position; @@ -112,13 +116,11 @@ vec2 AISystem::seek(const AI & ai) { return desired_velocity - rigidbody.data.linear_velocity; } -vec2 AISystem::flee(const AI & ai) { +vec2 AISystem::flee(const AI & ai, const Rigidbody & rigidbody) const { const Mediator & mediator = this->mediator; ComponentManager & mgr = mediator.component_manager; RefVector transforms = mgr.get_components_by_id(ai.game_object_id); Transform & transform = transforms.front().get(); - RefVector rigidbodies = mgr.get_components_by_id(ai.game_object_id); - Rigidbody & rigidbody = rigidbodies.front().get(); // Calculate the desired velocity if the entity is within the panic distance vec2 desired_velocity = transform.position - ai.flee_target; @@ -131,18 +133,20 @@ vec2 AISystem::flee(const AI & ai) { return desired_velocity - rigidbody.data.linear_velocity; } -vec2 AISystem::arrive(const AI & ai) { +vec2 AISystem::arrive(const AI & ai, const Rigidbody & rigidbody) const { const Mediator & mediator = this->mediator; ComponentManager & mgr = mediator.component_manager; RefVector transforms = mgr.get_components_by_id(ai.game_object_id); Transform & transform = transforms.front().get(); - RefVector rigidbodies = mgr.get_components_by_id(ai.game_object_id); - Rigidbody & rigidbody = rigidbodies.front().get(); // Calculate the desired velocity (taking into account the deceleration rate) vec2 to_target = ai.seek_target - transform.position; float distance = to_target.length(); if (distance > 0.0f) { + if (ai.arrive_deceleration <= 0.0f) { + throw std::runtime_error("Deceleration rate must be greater than 0"); + } + float speed = distance / ai.arrive_deceleration; speed = std::min(speed, rigidbody.data.max_linear_velocity.length()); vec2 desired_velocity = to_target * (speed / distance); @@ -153,13 +157,11 @@ vec2 AISystem::arrive(const AI & ai) { return vec2{0, 0}; } -vec2 AISystem::path_follow(AI & ai) { +vec2 AISystem::path_follow(AI & ai, const Rigidbody & rigidbody) { const Mediator & mediator = this->mediator; ComponentManager & mgr = mediator.component_manager; RefVector transforms = mgr.get_components_by_id(ai.game_object_id); Transform & transform = transforms.front().get(); - RefVector rigidbodies = mgr.get_components_by_id(ai.game_object_id); - Rigidbody & rigidbody = rigidbodies.front().get(); if (ai.path.empty()) { return vec2{0, 0}; @@ -182,11 +184,11 @@ vec2 AISystem::path_follow(AI & ai) { } else { // If the path is not looping, arrive at the last node ai.path_index = ai.path.size() - 1; - return this->arrive(ai); + return this->arrive(ai, rigidbody); } } } // Seek the target node - return this->seek(ai); + return this->seek(ai, rigidbody); } diff --git a/src/crepe/system/AISystem.h b/src/crepe/system/AISystem.h index 670d20d..160df01 100644 --- a/src/crepe/system/AISystem.h +++ b/src/crepe/system/AISystem.h @@ -1,6 +1,7 @@ #pragma once #include "api/AI.h" +#include "api/Rigidbody.h" #include "System.h" #include "types.h" @@ -25,8 +26,9 @@ private: * \brief Calculate the total force to apply to the entity * * \param ai The AI component + * \param rigidbody The Rigidbody component */ - vec2 calculate(AI & ai); + vec2 calculate(AI & ai, const Rigidbody & rigidbody); /** * \brief Accumulate the force to apply to the entity * @@ -35,36 +37,40 @@ private: * \param force_to_add The force to add * \return true if the force was added, false otherwise */ - bool accumulate_force(AI & ai, vec2 & running_total, vec2 force_to_add); + bool accumulate_force(const AI & ai, vec2 & running_total, vec2 force_to_add); /** * \brief Calculate the seek force * * \param ai The AI component + * \param rigidbody The Rigidbody component * \return The seek force */ - vec2 seek(const AI & ai); + vec2 seek(const AI & ai, const Rigidbody & rigidbody) const; /** * \brief Calculate the flee force * * \param ai The AI component + * \param rigidbody The Rigidbody component * \return The flee force */ - vec2 flee(const AI & ai); + vec2 flee(const AI & ai, const Rigidbody & rigidbody) const; /** * \brief Calculate the arrive force * * \param ai The AI component + * \param rigidbody The Rigidbody component * \return The arrive force */ - vec2 arrive(const AI & ai); + vec2 arrive(const AI & ai, const Rigidbody & rigidbody) const; /** * \brief Calculate the path follow force * * \param ai The AI component + * \param rigidbody The Rigidbody component * \return The path follow force */ - vec2 path_follow(AI & ai); + vec2 path_follow(AI & ai, const Rigidbody & rigidbody); }; } // namespace crepe -- cgit v1.2.3 From 4e7ddc9d8eb396f7160e09da8c9b3d797274600a Mon Sep 17 00:00:00 2001 From: max-001 Date: Tue, 10 Dec 2024 08:53:03 +0100 Subject: Replaced copy by reference --- src/crepe/system/AISystem.cpp | 2 +- src/crepe/system/AISystem.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/crepe/system/AISystem.cpp b/src/crepe/system/AISystem.cpp index 4d5039b..b42cb11 100644 --- a/src/crepe/system/AISystem.cpp +++ b/src/crepe/system/AISystem.cpp @@ -80,7 +80,7 @@ vec2 AISystem::calculate(AI & ai, const Rigidbody & rigidbody) { return force; } -bool AISystem::accumulate_force(const AI & ai, vec2 & running_total, vec2 force_to_add) { +bool AISystem::accumulate_force(const AI & ai, vec2 & running_total, vec2 & force_to_add) { float magnitude = running_total.length(); float magnitude_remaining = ai.max_force - magnitude; diff --git a/src/crepe/system/AISystem.h b/src/crepe/system/AISystem.h index 160df01..9a937d2 100644 --- a/src/crepe/system/AISystem.h +++ b/src/crepe/system/AISystem.h @@ -37,7 +37,7 @@ private: * \param force_to_add The force to add * \return true if the force was added, false otherwise */ - bool accumulate_force(const AI & ai, vec2 & running_total, vec2 force_to_add); + bool accumulate_force(const AI & ai, vec2 & running_total, vec2 & force_to_add); /** * \brief Calculate the seek force -- cgit v1.2.3 From 7b3e1090f314e5ad669add8cabd9dd2cda790a0f Mon Sep 17 00:00:00 2001 From: max-001 Date: Tue, 10 Dec 2024 08:59:54 +0100 Subject: Replaced xor --- src/crepe/api/AI.h | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/crepe/api/AI.h b/src/crepe/api/AI.h index de574cd..d48d9df 100644 --- a/src/crepe/api/AI.h +++ b/src/crepe/api/AI.h @@ -39,27 +39,19 @@ public: //! Turn on the seek behavior void seek_on() { flags |= SEEK; } //! Turn off the seek behavior - void seek_off() { - if (on(SEEK)) flags ^= SEEK; - } + void seek_off() { flags &= ~SEEK; } //! Turn on the flee behavior void flee_on() { flags |= FLEE; } //! Turn off the flee behavior - void flee_off() { - if (on(FLEE)) flags ^= FLEE; - } + void flee_off() { flags &= ~FLEE; } //! Turn on the arrive behavior void arrive_on() { flags |= ARRIVE; } //! Turn off the arrive behavior - void arrive_off() { - if (on(ARRIVE)) flags ^= ARRIVE; - } + void arrive_off() { flags &= ~ARRIVE; } //! Turn on the path follow behavior void path_follow_on() { flags |= PATH_FOLLOW; } //! Turn off the path follow behavior - void path_follow_off() { - if (on(PATH_FOLLOW)) flags ^= PATH_FOLLOW; - } + void path_follow_off() { flags &= ~PATH_FOLLOW; } /** * \brief Add a path node (for the path following behavior) -- cgit v1.2.3 From 6fc38e15e4b88d480d5fcb69eec36f7d8685e853 Mon Sep 17 00:00:00 2001 From: max-001 Date: Tue, 10 Dec 2024 09:21:58 +0100 Subject: Passing transform by reference --- src/crepe/system/AISystem.cpp | 49 ++++++++++++++++--------------------------- src/crepe/system/AISystem.h | 13 ++++++++---- 2 files changed, 27 insertions(+), 35 deletions(-) diff --git a/src/crepe/system/AISystem.cpp b/src/crepe/system/AISystem.cpp index b42cb11..d1ebeb5 100644 --- a/src/crepe/system/AISystem.cpp +++ b/src/crepe/system/AISystem.cpp @@ -2,7 +2,6 @@ #include #include "api/LoopTimer.h" -#include "api/Transform.h" #include "manager/ComponentManager.h" #include "manager/Mediator.h" @@ -45,32 +44,37 @@ void AISystem::update() { } vec2 AISystem::calculate(AI & ai, const Rigidbody & rigidbody) { + const Mediator & mediator = this->mediator; + ComponentManager & mgr = mediator.component_manager; + RefVector transforms = mgr.get_components_by_id(ai.game_object_id); + Transform & transform = transforms.front().get(); + vec2 force; // Run all the behaviors that are on, and stop if the force gets too high if (ai.on(AI::BehaviorType::FLEE)) { - vec2 force_to_add = this->flee(ai, rigidbody); + vec2 force_to_add = this->flee(ai, rigidbody, transform); if (!this->accumulate_force(ai, force, force_to_add)) { return force; } } if (ai.on(AI::BehaviorType::ARRIVE)) { - vec2 force_to_add = this->arrive(ai, rigidbody); + vec2 force_to_add = this->arrive(ai, rigidbody, transform); if (!this->accumulate_force(ai, force, force_to_add)) { return force; } } if (ai.on(AI::BehaviorType::SEEK)) { - vec2 force_to_add = this->seek(ai, rigidbody); + vec2 force_to_add = this->seek(ai, rigidbody, transform); if (!this->accumulate_force(ai, force, force_to_add)) { return force; } } if (ai.on(AI::BehaviorType::PATH_FOLLOW)) { - vec2 force_to_add = this->path_follow(ai, rigidbody); + vec2 force_to_add = this->path_follow(ai, rigidbody, transform); if (!this->accumulate_force(ai, force, force_to_add)) { return force; @@ -102,12 +106,8 @@ bool AISystem::accumulate_force(const AI & ai, vec2 & running_total, vec2 & forc return true; } -vec2 AISystem::seek(const AI & ai, const Rigidbody & rigidbody) const { - const Mediator & mediator = this->mediator; - ComponentManager & mgr = mediator.component_manager; - RefVector transforms = mgr.get_components_by_id(ai.game_object_id); - Transform & transform = transforms.front().get(); - +vec2 AISystem::seek(const AI & ai, const Rigidbody & rigidbody, + const Transform & transform) const { // Calculate the desired velocity vec2 desired_velocity = ai.seek_target - transform.position; desired_velocity.normalize(); @@ -116,12 +116,8 @@ vec2 AISystem::seek(const AI & ai, const Rigidbody & rigidbody) const { return desired_velocity - rigidbody.data.linear_velocity; } -vec2 AISystem::flee(const AI & ai, const Rigidbody & rigidbody) const { - const Mediator & mediator = this->mediator; - ComponentManager & mgr = mediator.component_manager; - RefVector transforms = mgr.get_components_by_id(ai.game_object_id); - Transform & transform = transforms.front().get(); - +vec2 AISystem::flee(const AI & ai, const Rigidbody & rigidbody, + const Transform & transform) const { // Calculate the desired velocity if the entity is within the panic distance vec2 desired_velocity = transform.position - ai.flee_target; if (desired_velocity.length_squared() > ai.square_flee_panic_distance) { @@ -133,12 +129,8 @@ vec2 AISystem::flee(const AI & ai, const Rigidbody & rigidbody) const { return desired_velocity - rigidbody.data.linear_velocity; } -vec2 AISystem::arrive(const AI & ai, const Rigidbody & rigidbody) const { - const Mediator & mediator = this->mediator; - ComponentManager & mgr = mediator.component_manager; - RefVector transforms = mgr.get_components_by_id(ai.game_object_id); - Transform & transform = transforms.front().get(); - +vec2 AISystem::arrive(const AI & ai, const Rigidbody & rigidbody, + const Transform & transform) const { // Calculate the desired velocity (taking into account the deceleration rate) vec2 to_target = ai.seek_target - transform.position; float distance = to_target.length(); @@ -157,12 +149,7 @@ vec2 AISystem::arrive(const AI & ai, const Rigidbody & rigidbody) const { return vec2{0, 0}; } -vec2 AISystem::path_follow(AI & ai, const Rigidbody & rigidbody) { - const Mediator & mediator = this->mediator; - ComponentManager & mgr = mediator.component_manager; - RefVector transforms = mgr.get_components_by_id(ai.game_object_id); - Transform & transform = transforms.front().get(); - +vec2 AISystem::path_follow(AI & ai, const Rigidbody & rigidbody, const Transform & transform) { if (ai.path.empty()) { return vec2{0, 0}; } @@ -184,11 +171,11 @@ vec2 AISystem::path_follow(AI & ai, const Rigidbody & rigidbody) { } else { // If the path is not looping, arrive at the last node ai.path_index = ai.path.size() - 1; - return this->arrive(ai, rigidbody); + return this->arrive(ai, rigidbody, transform); } } } // Seek the target node - return this->seek(ai, rigidbody); + return this->seek(ai, rigidbody, transform); } diff --git a/src/crepe/system/AISystem.h b/src/crepe/system/AISystem.h index 9a937d2..d5f8a8e 100644 --- a/src/crepe/system/AISystem.h +++ b/src/crepe/system/AISystem.h @@ -4,6 +4,7 @@ #include "api/Rigidbody.h" #include "System.h" +#include "api/Transform.h" #include "types.h" namespace crepe { @@ -44,33 +45,37 @@ private: * * \param ai The AI component * \param rigidbody The Rigidbody component + * \param transform The Transform component * \return The seek force */ - vec2 seek(const AI & ai, const Rigidbody & rigidbody) const; + vec2 seek(const AI & ai, const Rigidbody & rigidbody, const Transform & transform) const; /** * \brief Calculate the flee force * * \param ai The AI component * \param rigidbody The Rigidbody component + * \param transform The Transform component * \return The flee force */ - vec2 flee(const AI & ai, const Rigidbody & rigidbody) const; + vec2 flee(const AI & ai, const Rigidbody & rigidbody, const Transform & transform) const; /** * \brief Calculate the arrive force * * \param ai The AI component * \param rigidbody The Rigidbody component + * \param transform The Transform component * \return The arrive force */ - vec2 arrive(const AI & ai, const Rigidbody & rigidbody) const; + vec2 arrive(const AI & ai, const Rigidbody & rigidbody, const Transform & transform) const; /** * \brief Calculate the path follow force * * \param ai The AI component * \param rigidbody The Rigidbody component + * \param transform The Transform component * \return The path follow force */ - vec2 path_follow(AI & ai, const Rigidbody & rigidbody); + vec2 path_follow(AI & ai, const Rigidbody & rigidbody, const Transform & transform); }; } // namespace crepe -- cgit v1.2.3 From 55f245cb5cbd1cba54e0dc5f0cbceaf3f526c8b1 Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Tue, 10 Dec 2024 14:13:42 +0100 Subject: process feedback on #60 --- src/crepe/Component.h | 2 -- src/crepe/api/LoopManager.cpp | 3 +++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/crepe/Component.h b/src/crepe/Component.h index 060ff00..eff5a58 100644 --- a/src/crepe/Component.h +++ b/src/crepe/Component.h @@ -50,8 +50,6 @@ public: * \return The maximum number of instances for this component */ virtual int get_instances_max() const { return -1; } - //! Only ComponentManager needs to know the max instance count - friend class ComponentManager; }; } // namespace crepe diff --git a/src/crepe/api/LoopManager.cpp b/src/crepe/api/LoopManager.cpp index 88243c4..3e9e21c 100644 --- a/src/crepe/api/LoopManager.cpp +++ b/src/crepe/api/LoopManager.cpp @@ -1,4 +1,5 @@ #include "../system/AnimatorSystem.h" +#include "../system/AudioSystem.h" #include "../system/CollisionSystem.h" #include "../system/InputSystem.h" #include "../system/ParticleSystem.h" @@ -20,6 +21,7 @@ LoopManager::LoopManager() { this->load_system(); this->load_system(); this->load_system(); + this->load_system(); } void LoopManager::process_input() { this->get_system().update(); } @@ -37,6 +39,7 @@ void LoopManager::fixed_update() { this->get_system().update(); this->get_system().update(); this->get_system().update(); + this->get_system().update(); } void LoopManager::loop() { -- cgit v1.2.3 From fe865eef33eb78b6dab6a177b463554f2ffe7387 Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Tue, 10 Dec 2024 15:19:17 +0100 Subject: add ResourceManager to LoopManager --- src/crepe/api/LoopManager.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/crepe/api/LoopManager.h b/src/crepe/api/LoopManager.h index d8910a0..0947f94 100644 --- a/src/crepe/api/LoopManager.h +++ b/src/crepe/api/LoopManager.h @@ -4,6 +4,7 @@ #include "../facade/SDLContext.h" #include "../manager/ComponentManager.h" +#include "../manager/ResourceManager.h" #include "../manager/SceneManager.h" #include "../system/System.h" @@ -95,6 +96,8 @@ private: ComponentManager component_manager{mediator}; //! Scene manager instance SceneManager scene_manager{mediator}; + //! Resource manager instance + ResourceManager resource_manager{mediator}; //! SDL context \todo no more singletons! SDLContext & sdl_context = SDLContext::get_instance(); -- cgit v1.2.3 From 543dc375228b520605bb099bc95a23918f75e9f8 Mon Sep 17 00:00:00 2001 From: max-001 Date: Tue, 10 Dec 2024 17:52:46 +0100 Subject: Implemented feedback --- src/crepe/api/AI.h | 9 +++++---- src/crepe/system/AISystem.cpp | 14 +++++++++----- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/crepe/api/AI.h b/src/crepe/api/AI.h index d48d9df..80feda5 100644 --- a/src/crepe/api/AI.h +++ b/src/crepe/api/AI.h @@ -14,8 +14,7 @@ namespace crepe { class AI : public Component { public: //! The different types of behaviors that can be used - enum BehaviorType { - NONE = 0x00000, + enum BehaviorTypeMask { SEEK = 0x00002, FLEE = 0x00004, ARRIVE = 0x00008, @@ -35,7 +34,7 @@ public: * \param behavior The behavior to check * \return true if the behavior is on, false otherwise */ - bool on(BehaviorType behavior) const { return (flags & behavior) == behavior; } + bool on(BehaviorTypeMask behavior) const { return (flags & behavior); } //! Turn on the seek behavior void seek_on() { flags |= SEEK; } //! Turn off the seek behavior @@ -92,8 +91,10 @@ public: //! The maximum force that can be applied to the entity (higher values will make the entity adjust faster) float max_force; - //! The target to seek or arrive at + //! The target to seek at vec2 seek_target; + //! The target to arrive at + vec2 arrive_target; //! The target to flee from vec2 flee_target; //! The distance at which the entity will start to flee from the target diff --git a/src/crepe/system/AISystem.cpp b/src/crepe/system/AISystem.cpp index d1ebeb5..e2e36a5 100644 --- a/src/crepe/system/AISystem.cpp +++ b/src/crepe/system/AISystem.cpp @@ -30,6 +30,9 @@ void AISystem::update() { "AI component must be attached to a GameObject with a Rigidbody component"); } Rigidbody & rigidbody = rigidbodies.front().get(); + if (!rigidbody.active) { + continue; + } if (rigidbody.data.mass <= 0) { throw std::runtime_error("Mass must be greater than 0"); } @@ -52,28 +55,28 @@ vec2 AISystem::calculate(AI & ai, const Rigidbody & rigidbody) { vec2 force; // Run all the behaviors that are on, and stop if the force gets too high - if (ai.on(AI::BehaviorType::FLEE)) { + if (ai.on(AI::BehaviorTypeMask::FLEE)) { vec2 force_to_add = this->flee(ai, rigidbody, transform); if (!this->accumulate_force(ai, force, force_to_add)) { return force; } } - if (ai.on(AI::BehaviorType::ARRIVE)) { + if (ai.on(AI::BehaviorTypeMask::ARRIVE)) { vec2 force_to_add = this->arrive(ai, rigidbody, transform); if (!this->accumulate_force(ai, force, force_to_add)) { return force; } } - if (ai.on(AI::BehaviorType::SEEK)) { + if (ai.on(AI::BehaviorTypeMask::SEEK)) { vec2 force_to_add = this->seek(ai, rigidbody, transform); if (!this->accumulate_force(ai, force, force_to_add)) { return force; } } - if (ai.on(AI::BehaviorType::PATH_FOLLOW)) { + if (ai.on(AI::BehaviorTypeMask::PATH_FOLLOW)) { vec2 force_to_add = this->path_follow(ai, rigidbody, transform); if (!this->accumulate_force(ai, force, force_to_add)) { @@ -132,7 +135,7 @@ vec2 AISystem::flee(const AI & ai, const Rigidbody & rigidbody, vec2 AISystem::arrive(const AI & ai, const Rigidbody & rigidbody, const Transform & transform) const { // Calculate the desired velocity (taking into account the deceleration rate) - vec2 to_target = ai.seek_target - transform.position; + vec2 to_target = ai.arrive_target - transform.position; float distance = to_target.length(); if (distance > 0.0f) { if (ai.arrive_deceleration <= 0.0f) { @@ -161,6 +164,7 @@ vec2 AISystem::path_follow(AI & ai, const Rigidbody & rigidbody, const Transform if (to_target.length_squared() > ai.path_node_distance * ai.path_node_distance) { // If the entity is not close enough to the target node, seek it ai.seek_target = target; + ai.arrive_target = target; } else { // If the entity is close enough to the target node, move to the next node ai.path_index++; -- cgit v1.2.3 From 7cbc577e94ed048f2a8146fab6972ae6ff290be7 Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Tue, 10 Dec 2024 18:57:03 +0100 Subject: fix AudioSystem bug + add regression test --- src/crepe/system/AudioSystem.cpp | 6 +++--- src/test/AudioTest.cpp | 9 +++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/crepe/system/AudioSystem.cpp b/src/crepe/system/AudioSystem.cpp index b2c1dc6..ddba268 100644 --- a/src/crepe/system/AudioSystem.cpp +++ b/src/crepe/system/AudioSystem.cpp @@ -26,12 +26,12 @@ void AudioSystem::diff_update(AudioSource & component, Sound & resource) { SoundContext & context = this->get_context(); if (component.active != component.last_active) { - if (component.active) { - component.oneshot_play = component.play_on_awake; - } else { + if (!component.active) { context.stop(component.voice); return; } + if (component.play_on_awake) + component.oneshot_play = true; } if (!component.active) return; diff --git a/src/test/AudioTest.cpp b/src/test/AudioTest.cpp index 774fdb8..48bba1b 100644 --- a/src/test/AudioTest.cpp +++ b/src/test/AudioTest.cpp @@ -150,3 +150,12 @@ TEST_F(AudioTest, PlayOnActive) { system.update(); } } + +TEST_F(AudioTest, PlayImmediately) { + component.play_on_awake = false; + component.play(); + + EXPECT_CALL(context, play(_)).Times(1); + + system.update(); +} -- cgit v1.2.3 From 8ed0c3f425b02d4f064c455270288a6c4a359109 Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Tue, 10 Dec 2024 20:10:58 +0100 Subject: use opaque type instead of forward declared DB for unique_ptr in SaveManager --- src/crepe/manager/SaveManager.cpp | 7 +++++-- src/crepe/manager/SaveManager.h | 3 ++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/crepe/manager/SaveManager.cpp b/src/crepe/manager/SaveManager.cpp index 292e8fd..39b92d4 100644 --- a/src/crepe/manager/SaveManager.cpp +++ b/src/crepe/manager/SaveManager.cpp @@ -14,9 +14,12 @@ SaveManager::SaveManager(Mediator & mediator) : Manager(mediator) { DB & SaveManager::get_db() { if (this->db == nullptr) { Config & cfg = Config::get_instance(); - this->db = make_unique(cfg.savemgr.location); + this->db = { + new DB(cfg.savemgr.location), + [](void * db){ delete static_cast(db); } + }; } - return *this->db; + return *static_cast(this->db.get()); } template <> diff --git a/src/crepe/manager/SaveManager.h b/src/crepe/manager/SaveManager.h index 1b55a22..27e625c 100644 --- a/src/crepe/manager/SaveManager.h +++ b/src/crepe/manager/SaveManager.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include "../ValueBroker.h" @@ -96,7 +97,7 @@ protected: virtual DB & get_db(); private: //! Database - std::unique_ptr db = nullptr; + std::unique_ptr> db = nullptr; }; } // namespace crepe -- cgit v1.2.3 From c45b60941b82dec2097d958b396a117b1634eada Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Tue, 10 Dec 2024 20:26:18 +0100 Subject: add SaveManager to LoopManager --- src/crepe/api/LoopManager.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/crepe/api/LoopManager.h b/src/crepe/api/LoopManager.h index 0947f94..33a61a3 100644 --- a/src/crepe/api/LoopManager.h +++ b/src/crepe/api/LoopManager.h @@ -6,6 +6,7 @@ #include "../manager/ComponentManager.h" #include "../manager/ResourceManager.h" #include "../manager/SceneManager.h" +#include "../manager/SaveManager.h" #include "../system/System.h" #include "LoopTimer.h" @@ -98,6 +99,8 @@ private: SceneManager scene_manager{mediator}; //! Resource manager instance ResourceManager resource_manager{mediator}; + //! Save manager instance + SaveManager save_manager{mediator}; //! SDL context \todo no more singletons! SDLContext & sdl_context = SDLContext::get_instance(); -- cgit v1.2.3 From 405bf73b273c7b9a6574d77b4a034d9588c9af1b Mon Sep 17 00:00:00 2001 From: max-001 Date: Wed, 11 Dec 2024 13:18:59 +0100 Subject: Removed magic numbers --- src/crepe/api/AI.cpp | 16 ++++++++-------- src/crepe/api/AI.h | 3 +++ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/crepe/api/AI.cpp b/src/crepe/api/AI.cpp index 472550b..34e1438 100644 --- a/src/crepe/api/AI.cpp +++ b/src/crepe/api/AI.cpp @@ -13,10 +13,10 @@ void AI::make_circle_path(float radius, const vec2 & center, float start_angle, } // The step size is determined by the radius (step size is in radians) - float step = 400.0f / radius; - // Force at least 16 steps (in case of a small radius) - if (step > 2 * M_PI / 16) { - step = 2 * M_PI / 16; + float step = RADIUS_TO_STEP / radius; + // Force at least MIN_STEP steps (in case of a small radius) + if (step > 2 * M_PI / MIN_STEP) { + step = 2 * M_PI / MIN_STEP; } // The path node distance is determined by the step size and the radius path_node_distance = radius * step * 0.75f; @@ -42,10 +42,10 @@ void AI::make_oval_path(float radius_x, float radius_y, const vec2 & center, flo float max_radius = std::max(radius_x, radius_y); // The step size is determined by the radius (step size is in radians) - float step = 400.0f / max_radius; - // Force at least 16 steps (in case of a small radius) - if (step > 2 * M_PI / 16) { - step = 2 * M_PI / 16; + float step = RADIUS_TO_STEP / max_radius; + // Force at least MIN_STEP steps (in case of a small radius) + if (step > 2 * M_PI / MIN_STEP) { + step = 2 * M_PI / MIN_STEP; } // The path node distance is determined by the step size and the radius path_node_distance = max_radius * step * 0.75f; diff --git a/src/crepe/api/AI.h b/src/crepe/api/AI.h index 80feda5..fc28451 100644 --- a/src/crepe/api/AI.h +++ b/src/crepe/api/AI.h @@ -116,6 +116,9 @@ private: //! The AISystem is the only class that should access the flags and path_index variables friend class AISystem; + + static constexpr const int MIN_STEP = 16; + static constexpr const float RADIUS_TO_STEP = 400.0f; }; } // namespace crepe -- cgit v1.2.3 From 6eef90e9ffb1d8fc25161e912bc5d8aa8e4024da Mon Sep 17 00:00:00 2001 From: max-001 Date: Wed, 11 Dec 2024 13:20:32 +0100 Subject: Added Doxygen --- src/crepe/api/AI.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/crepe/api/AI.h b/src/crepe/api/AI.h index fc28451..f1c8951 100644 --- a/src/crepe/api/AI.h +++ b/src/crepe/api/AI.h @@ -117,7 +117,9 @@ private: //! The AISystem is the only class that should access the flags and path_index variables friend class AISystem; + //! The minimum amount of steps for the path following behavior static constexpr const int MIN_STEP = 16; + //! The radius to step size ratio for the path following behavior static constexpr const float RADIUS_TO_STEP = 400.0f; }; -- cgit v1.2.3 From fff2fe2ed43fe61cf12eb861fd6a652e1fcc70c2 Mon Sep 17 00:00:00 2001 From: max-001 Date: Wed, 11 Dec 2024 13:26:51 +0100 Subject: Corrected constexpr --- src/crepe/api/AI.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/crepe/api/AI.h b/src/crepe/api/AI.h index f1c8951..4f7692b 100644 --- a/src/crepe/api/AI.h +++ b/src/crepe/api/AI.h @@ -118,9 +118,9 @@ private: friend class AISystem; //! The minimum amount of steps for the path following behavior - static constexpr const int MIN_STEP = 16; + static constexpr int MIN_STEP = 16; //! The radius to step size ratio for the path following behavior - static constexpr const float RADIUS_TO_STEP = 400.0f; + static constexpr float RADIUS_TO_STEP = 400.0f; }; } // namespace crepe -- cgit v1.2.3 From bea86a6fcea272d7cc7fba44d6c489bd70587578 Mon Sep 17 00:00:00 2001 From: max-001 Date: Wed, 11 Dec 2024 13:27:24 +0100 Subject: Make format --- src/crepe/api/LoopManager.h | 2 +- src/crepe/manager/SaveManager.cpp | 6 ++---- src/crepe/manager/SaveManager.h | 5 +++-- src/crepe/system/AudioSystem.cpp | 3 +-- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/crepe/api/LoopManager.h b/src/crepe/api/LoopManager.h index 33a61a3..700afe4 100644 --- a/src/crepe/api/LoopManager.h +++ b/src/crepe/api/LoopManager.h @@ -5,8 +5,8 @@ #include "../facade/SDLContext.h" #include "../manager/ComponentManager.h" #include "../manager/ResourceManager.h" -#include "../manager/SceneManager.h" #include "../manager/SaveManager.h" +#include "../manager/SceneManager.h" #include "../system/System.h" #include "LoopTimer.h" diff --git a/src/crepe/manager/SaveManager.cpp b/src/crepe/manager/SaveManager.cpp index 39b92d4..691ea2f 100644 --- a/src/crepe/manager/SaveManager.cpp +++ b/src/crepe/manager/SaveManager.cpp @@ -14,10 +14,8 @@ SaveManager::SaveManager(Mediator & mediator) : Manager(mediator) { DB & SaveManager::get_db() { if (this->db == nullptr) { Config & cfg = Config::get_instance(); - this->db = { - new DB(cfg.savemgr.location), - [](void * db){ delete static_cast(db); } - }; + this->db + = {new DB(cfg.savemgr.location), [](void * db) { delete static_cast(db); }}; } return *static_cast(this->db.get()); } diff --git a/src/crepe/manager/SaveManager.h b/src/crepe/manager/SaveManager.h index 27e625c..61a978d 100644 --- a/src/crepe/manager/SaveManager.h +++ b/src/crepe/manager/SaveManager.h @@ -1,7 +1,7 @@ #pragma once -#include #include +#include #include "../ValueBroker.h" @@ -95,9 +95,10 @@ private: protected: //! Create or return DB virtual DB & get_db(); + private: //! Database - std::unique_ptr> db = nullptr; + std::unique_ptr> db = nullptr; }; } // namespace crepe diff --git a/src/crepe/system/AudioSystem.cpp b/src/crepe/system/AudioSystem.cpp index ddba268..b1aa0f8 100644 --- a/src/crepe/system/AudioSystem.cpp +++ b/src/crepe/system/AudioSystem.cpp @@ -30,8 +30,7 @@ void AudioSystem::diff_update(AudioSource & component, Sound & resource) { context.stop(component.voice); return; } - if (component.play_on_awake) - component.oneshot_play = true; + if (component.play_on_awake) component.oneshot_play = true; } if (!component.active) return; -- cgit v1.2.3 From 6f89e67c9b2dfcb182ed2fa9d9a0ea7afa53fbf0 Mon Sep 17 00:00:00 2001 From: max-001 Date: Wed, 11 Dec 2024 14:06:26 +0100 Subject: Clarified 0.75f --- src/crepe/api/AI.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/crepe/api/AI.cpp b/src/crepe/api/AI.cpp index 34e1438..a4d3e98 100644 --- a/src/crepe/api/AI.cpp +++ b/src/crepe/api/AI.cpp @@ -47,8 +47,8 @@ void AI::make_oval_path(float radius_x, float radius_y, const vec2 & center, flo if (step > 2 * M_PI / MIN_STEP) { step = 2 * M_PI / MIN_STEP; } - // The path node distance is determined by the step size and the radius - path_node_distance = max_radius * step * 0.75f; + // The path node distance is determined by the step size times the radius times 75% + this->path_node_distance = max_radius * step * 0.75f; auto rotate_point = [rotation](vec2 point, vec2 center) { float s = sin(rotation); -- cgit v1.2.3 From 0dbbbe4bac4ad4fcb9e88908034e90000056363e Mon Sep 17 00:00:00 2001 From: max-001 Date: Wed, 11 Dec 2024 14:10:43 +0100 Subject: Implemented feedback --- src/crepe/api/AI.cpp | 10 ++++++---- src/crepe/api/AI.h | 2 ++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/crepe/api/AI.cpp b/src/crepe/api/AI.cpp index a4d3e98..2195249 100644 --- a/src/crepe/api/AI.cpp +++ b/src/crepe/api/AI.cpp @@ -1,6 +1,8 @@ #include +#include #include "AI.h" +#include "types.h" namespace crepe { @@ -19,7 +21,7 @@ void AI::make_circle_path(float radius, const vec2 & center, float start_angle, step = 2 * M_PI / MIN_STEP; } // The path node distance is determined by the step size and the radius - path_node_distance = radius * step * 0.75f; + this->path_node_distance = radius * step * PATH_NODE_DISTANCE_FACTOR; if (clockwise) { for (float i = start_angle; i < 2 * M_PI + start_angle; i += step) { @@ -47,10 +49,10 @@ void AI::make_oval_path(float radius_x, float radius_y, const vec2 & center, flo if (step > 2 * M_PI / MIN_STEP) { step = 2 * M_PI / MIN_STEP; } - // The path node distance is determined by the step size times the radius times 75% - this->path_node_distance = max_radius * step * 0.75f; + // The path node distance is determined by the step size and the radius + this->path_node_distance = max_radius * step * PATH_NODE_DISTANCE_FACTOR; - auto rotate_point = [rotation](vec2 point, vec2 center) { + std::function rotate_point = [rotation](vec2 point, vec2 center) { float s = sin(rotation); float c = cos(rotation); diff --git a/src/crepe/api/AI.h b/src/crepe/api/AI.h index 4f7692b..c780a91 100644 --- a/src/crepe/api/AI.h +++ b/src/crepe/api/AI.h @@ -121,6 +121,8 @@ private: static constexpr int MIN_STEP = 16; //! The radius to step size ratio for the path following behavior static constexpr float RADIUS_TO_STEP = 400.0f; + //! The path node distance factor for the path following behavior + static constexpr float PATH_NODE_DISTANCE_FACTOR = 0.75f; }; } // namespace crepe -- cgit v1.2.3