From 16444f19ae2c7c71a2be53ce6fd2e4d671aa8765 Mon Sep 17 00:00:00 2001
From: max-001 <maxsmits21@kpnmail.nl>
Date: Wed, 4 Dec 2024 12:15:05 +0100
Subject: Modified test and setup of AISystem

---
 src/crepe/system/AISystem.cpp   |  6 ++++++
 src/crepe/system/AISystem.h     | 14 ++++++++++++++
 src/crepe/system/CMakeLists.txt |  2 ++
 3 files changed, 22 insertions(+)
 create mode 100644 src/crepe/system/AISystem.cpp
 create mode 100644 src/crepe/system/AISystem.h

(limited to 'src/crepe/system')

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 <iostream>
+
+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
 )
-- 
cgit v1.2.3


From f9f5600b60d6944dc9a7dd502988703d59d0cd62 Mon Sep 17 00:00:00 2001
From: max-001 <maxsmits21@kpnmail.nl>
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(-)

(limited to 'src/crepe/system')

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 <iostream>
 
 using namespace crepe;
 
-void AISystem::update() { std::cout << "AI System update" << std::endl; }
+void AISystem::update() {
+	ComponentManager & mgr = this->component_manager;
+	RefVector<AI> ai_components = mgr.get_components_by_type<AI>();
+
+	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 121387ba92a23d6f17b36331d25757abc899f7d2 Mon Sep 17 00:00:00 2001
From: max-001 <maxsmits21@kpnmail.nl>
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(-)

(limited to 'src/crepe/system')

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> ai_components = mgr.get_components_by_type<AI>();
 
+	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<Transform> transforms
+			= mgr.get_components_by_id<Transform>(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<Transform> transforms = mgr.get_components_by_id<Transform>(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<Sprite>(img, Color::MAGENTA,
 										   Sprite::FlipSettings{false, false}, 1, 1, 195);
-		game_object1.add_component<AI>(1, 1, 1);
+		game_object1.add_component<AI>(1, 200, 200).seek_on();
 
 		game_object2.add_component<Camera>(Color::WHITE, ivec2{1080, 720}, vec2{1036, 780},
 										   1.0f);
-- 
cgit v1.2.3


From e617b4f002638e37dbe4d2ce13849728e7e82c78 Mon Sep 17 00:00:00 2001
From: max-001 <maxsmits21@kpnmail.nl>
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(-)

(limited to 'src/crepe/system')

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> ai_components = mgr.get_components_by_type<AI>();
 
 	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<Transform> transforms = mgr.get_components_by_id<Transform>(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 <crepe/manager/Mediator.h>
 #include <SDL2/SDL_timer.h>
 #include <chrono>
-#include <crepe/ComponentManager.h>
+#include <crepe/manager/ComponentManager.h>
 #include <crepe/api/AI.h>
 #include <crepe/api/Camera.h>
 #include <crepe/api/Color.h>
@@ -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 <maxsmits21@kpnmail.nl>
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(-)

(limited to 'src/crepe/system')

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 <crepe/manager/Mediator.h>
 #include <SDL2/SDL_timer.h>
 #include <chrono>
-#include <crepe/manager/ComponentManager.h>
 #include <crepe/api/AI.h>
 #include <crepe/api/Camera.h>
 #include <crepe/api/Color.h>
@@ -10,6 +8,8 @@
 #include <crepe/api/Scene.h>
 #include <crepe/api/Sprite.h>
 #include <crepe/api/Texture.h>
+#include <crepe/manager/ComponentManager.h>
+#include <crepe/manager/Mediator.h>
 
 using namespace crepe;
 using namespace std;
-- 
cgit v1.2.3


From 93893dbe710d864d5865f361f9a8a8f8f85b94f6 Mon Sep 17 00:00:00 2001
From: max-001 <maxsmits21@kpnmail.nl>
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(-)

(limited to 'src/crepe/system')

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 <vector>
 
 #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 <utility>
 #include <variant>
 
+#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<CollisionInternal> all_colliders;
 	game_object_id_t id = 0;
 	ComponentManager & mgr = this->mediator.component_manager;
-	RefVector<Rigidbody> rigidbodies
-		= mgr.get_components_by_type<Rigidbody>();
+	RefVector<Rigidbody> rigidbodies = mgr.get_components_by_type<Rigidbody>();
 	// 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<Transform>(id).front().get();
+		Transform & transform = mgr.get_components_by_id<Transform>(id).front().get();
 		// Check if the boxcollider is active and has the same id as the rigidbody.
-		RefVector<BoxCollider> boxcolliders
-			= mgr.get_components_by_type<BoxCollider>();
+		RefVector<BoxCollider> boxcolliders = mgr.get_components_by_type<BoxCollider>();
 		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<CollisionEvent>(
-		data, info.this_collider.game_object_id);
+	emgr.trigger_event<CollisionEvent>(data, info.this_collider.game_object_id);
 }
 
 void CollisionSystem::static_collision_handler(CollisionInfo & info) {
@@ -389,14 +385,14 @@ CollisionSystem::gather_collisions(std::vector<CollisionInternal> & colliders) {
 
 bool CollisionSystem::have_common_layer(const std::set<int> & layers1,
 										const std::set<int> & 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 <crepe/api/BoxCollider.h>
 #include <crepe/api/Camera.h>
@@ -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<Transform>();
 				tf.position.x -= 1;
 				break;
 			}
-			case Keycode::W:
-			{
+			case Keycode::W: {
 				Transform & tf = this->get_component<Transform>();
 				tf.position.y -= 1;
 				break;
 			}
-			case Keycode::S:
-			{
+			case Keycode::S: {
 				Transform & tf = this->get_component<Transform>();
 				tf.position.y += 1;
 				break;
 			}
-			case Keycode::D:
-			{
+			case Keycode::D: {
 				Transform & tf = this->get_component<Transform>();
 				tf.position.x += 1;
 				break;
 			}
-			case Keycode::E:
-			{
-				if(flip){
+			case Keycode::E: {
+				if (flip) {
 					flip = false;
 					this->get_component<BoxCollider>().active = true;
 					this->get_components<Sprite>()[0].get().active = true;
 					this->get_component<CircleCollider>().active = false;
 					this->get_components<Sprite>()[1].get().active = false;
-				}
-				else {
+				} else {
 					flip = true;
 					this->get_component<BoxCollider>().active = false;
 					this->get_components<Sprite>()[0].get().active = false;
 					this->get_component<CircleCollider>().active = true;
 					this->get_components<Sprite>()[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<CollisionEvent>([this](const CollisionEvent & ev) -> bool { return this->oncollision(ev); });
-		subscribe<KeyPressEvent>([this](const KeyPressEvent & ev) -> bool { return this->keypressed(ev); });
+		subscribe<CollisionEvent>(
+			[this](const CollisionEvent & ev) -> bool { return this->oncollision(ev); });
+		subscribe<KeyPressEvent>(
+			[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<Transform>();
 				tf.position.x -= 1;
 				break;
 			}
-			case Keycode::UP:
-			{
+			case Keycode::UP: {
 				Transform & tf = this->get_component<Transform>();
 				tf.position.y -= 1;
 				break;
 			}
-			case Keycode::DOWN:
-			{
+			case Keycode::DOWN: {
 				Transform & tf = this->get_component<Transform>();
 				tf.position.y += 1;
 				break;
 			}
-			case Keycode::RIGHT:
-			{
+			case Keycode::RIGHT: {
 				Transform & tf = this->get_component<Transform>();
 				tf.position.x += 1;
 				break;
 			}
-			case Keycode::PAUSE:
-			{
-				if(flip){
+			case Keycode::PAUSE: {
+				if (flip) {
 					flip = false;
 					this->get_component<BoxCollider>().active = true;
 					this->get_components<Sprite>()[0].get().active = true;
 					this->get_component<CircleCollider>().active = false;
 					this->get_components<Sprite>()[1].get().active = false;
-				}
-				else {
+				} else {
 					flip = true;
 					this->get_component<BoxCollider>().active = false;
 					this->get_components<Sprite>()[0].get().active = false;
 					this->get_component<CircleCollider>().active = true;
 					this->get_components<Sprite>()[1].get().active = true;
 				}
-				
-				
+
 				//add collider switch
 				break;
 			}
 			default:
-			break;
+				break;
 		}
 		return false;
-	} 
+	}
 
 	void init() {
 		Log::logf("init");
-		subscribe<CollisionEvent>([this](const CollisionEvent & ev) -> bool { return this->oncollision(ev); });
-		subscribe<KeyPressEvent>([this](const KeyPressEvent & ev) -> bool { return this->keypressed(ev); });
+		subscribe<CollisionEvent>(
+			[this](const CollisionEvent & ev) -> bool { return this->oncollision(ev); });
+		subscribe<KeyPressEvent>(
+			[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<BoxCollider>(vec2{screen_size_width / 2 + world_collider / 2, 0},
 										 vec2{world_collider, world_collider}); // right
-		world.add_component<Camera>(Color::WHITE, ivec2{static_cast<int>(screen_size_width), static_cast<int>(screen_size_height)}, vec2{screen_size_width, screen_size_height}, 1.0f);
+		world.add_component<Camera>(
+			Color::WHITE,
+			ivec2{static_cast<int>(screen_size_width), static_cast<int>(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<CircleCollider>(vec2{0, 0}, 10).active = false;
 		auto img2 = Texture("asset/texture/circle.png");
-		game_object1.add_component<Sprite>(img2, color, Sprite::FlipSettings{false, false}, 1,
-										   1, 20).active = false;
-
-
+		game_object1
+			.add_component<Sprite>(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<CircleCollider>(vec2{0, 0}, 10).active = false;
 		auto img4 = Texture("asset/texture/circle.png");
-		game_object2.add_component<Sprite>(img4, color, Sprite::FlipSettings{false, false}, 1,
-										   1, 20).active = false;
-
+		game_object2
+			.add_component<Sprite>(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 <crepe/manager/ComponentManager.h>
-#include <crepe/manager/Mediator.h>
 #include <crepe/api/Event.h>
-#include <crepe/manager/EventManager.h>
 #include <crepe/api/GameObject.h>
 #include <crepe/api/Rigidbody.h>
 #include <crepe/api/Script.h>
 #include <crepe/api/Transform.h>
+#include <crepe/manager/ComponentManager.h>
+#include <crepe/manager/EventManager.h>
+#include <crepe/manager/Mediator.h>
 #include <crepe/system/CollisionSystem.h>
 #include <crepe/system/ScriptSystem.h>
 #include <crepe/types.h>
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 <crepe/manager/ComponentManager.h>
 #include <crepe/api/Event.h>
-#include <crepe/manager/EventManager.h>
 #include <crepe/api/GameObject.h>
 #include <crepe/api/ParticleEmitter.h>
 #include <crepe/api/Rigidbody.h>
 #include <crepe/api/Script.h>
 #include <crepe/api/Transform.h>
+#include <crepe/manager/ComponentManager.h>
+#include <crepe/manager/EventManager.h>
 #include <crepe/system/CollisionSystem.h>
 #include <crepe/system/ScriptSystem.h>
 #include <crepe/types.h>
@@ -162,7 +162,7 @@ TEST_F(Profiling, Profiling_2) {
 				.body_type = Rigidbody::BodyType::STATIC,
 			});
 			gameobject.add_component<BoxCollider>(vec2{0, 0}, vec2{1, 1});
-			
+
 			gameobject.add_component<BehaviorScript>().set_script<TestScript>();
 			Color color(0, 0, 0, 0);
 			auto img = Texture("asset/texture/green_square.png");
-- 
cgit v1.2.3


From 9c2cafd85ed7aa9a860ba25fbe2bd3ccc2439f29 Mon Sep 17 00:00:00 2001
From: max-001 <maxsmits21@kpnmail.nl>
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(-)

(limited to 'src/crepe/system')

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<Rigidbody> rigidbodies
+			= mgr.get_components_by_id<Rigidbody>(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<Transform> transforms
-			= mgr.get_components_by_id<Transform>(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<Transform> transforms = mgr.get_components_by_id<Transform>(ai.game_object_id);
 	Transform & transform = transforms.front().get();
+	RefVector<Rigidbody> rigidbodies = mgr.get_components_by_id<Rigidbody>(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 <crepe/api/Color.h>
 #include <crepe/api/GameObject.h>
 #include <crepe/api/LoopManager.h>
+#include <crepe/api/Rigidbody.h>
 #include <crepe/api/Scene.h>
 #include <crepe/api/Script.h>
 #include <crepe/api/Sprite.h>
@@ -40,7 +41,10 @@ public:
 		Texture img = Texture("asset/texture/test_ap43.png");
 		game_object1.add_component<Sprite>(img, Color::MAGENTA,
 										   Sprite::FlipSettings{false, false}, 1, 1, 195);
-		game_object1.add_component<AI>(1, 200, 200).seek_on();
+		game_object1.add_component<AI>(200).seek_on();
+		game_object1.add_component<Rigidbody>(Rigidbody::Data{
+			.mass = 1.0f, .max_linear_velocity = {21, 21}, // sqrt(21^2 + 21^2) = 30
+		});
 
 		game_object2.add_component<Camera>(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 <maxsmits21@kpnmail.nl>
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(-)

(limited to 'src/crepe/system')

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 <maxsmits21@kpnmail.nl>
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(-)

(limited to 'src/crepe/system')

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 <crepe/api/Sprite.h>
 #include <crepe/api/Texture.h>
 #include <crepe/manager/Mediator.h>
+#include <crepe/types.h>
 
 using namespace crepe;
 using namespace std;
@@ -23,9 +24,19 @@ class Script1 : public Script {
 		return true;
 	}
 
+	bool mousemove(const MouseMoveEvent & event) {
+		RefVector<AI> aivec = this->get_components<AI>();
+		AI & ai = aivec.front().get();
+		ai.seek_target
+			= vec2{static_cast<float>(event.mouse_x), static_cast<float>(event.mouse_y)};
+		return true;
+	}
+
 	void init() {
 		subscribe<ShutDownEvent>(
 			[this](const ShutDownEvent & ev) -> bool { return this->shutdown(ev); });
+		subscribe<MouseMoveEvent>(
+			[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<Sprite>(img, Color::MAGENTA,
 										   Sprite::FlipSettings{false, false}, 1, 1, 195);
-		game_object1.add_component<AI>(200).seek_on();
+		game_object1.add_component<AI>(30).seek_on();
 		game_object1.add_component<Rigidbody>(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<BehaviorScript>().set_script<Script1>();
 
 		game_object2.add_component<Camera>(Color::WHITE, ivec2{1080, 720}, vec2{1036, 780},
 										   1.0f);
-		game_object2.add_component<BehaviorScript>().set_script<Script1>();
 	}
 
 	string get_name() const override { return "Scene1"; }
-- 
cgit v1.2.3


From 0d0943d23364d7110f0232e3564f4ea63af13db2 Mon Sep 17 00:00:00 2001
From: max-001 <maxsmits21@kpnmail.nl>
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(-)

(limited to 'src/crepe/system')

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 <algorithm>
+#include <cmath>
+
 #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<Transform> transforms = mgr.get_components_by_id<Transform>(ai.game_object_id);
+	Transform & transform = transforms.front().get();
+	RefVector<Rigidbody> rigidbodies = mgr.get_components_by_id<Rigidbody>(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<Transform> transforms = mgr.get_components_by_id<Transform>(ai.game_object_id);
+	Transform & transform = transforms.front().get();
+	RefVector<Rigidbody> rigidbodies = mgr.get_components_by_id<Rigidbody>(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<AI> aivec = this->get_components<AI>();
 		AI & ai = aivec.front().get();
-		ai.seek_target
+		ai.flee_target
 			= vec2{static_cast<float>(event.mouse_x), static_cast<float>(event.mouse_y)};
 		return true;
 	}
@@ -52,7 +52,9 @@ public:
 		Texture img = Texture("asset/texture/test_ap43.png");
 		game_object1.add_component<Sprite>(img, Color::MAGENTA,
 										   Sprite::FlipSettings{false, false}, 1, 1, 195);
-		game_object1.add_component<AI>(30).seek_on();
+		AI & ai = game_object1.add_component<AI>(30);
+		ai.arrive_on();
+		ai.flee_on();
 		game_object1.add_component<Rigidbody>(Rigidbody::Data{
 			.mass = 0.5f, .max_linear_velocity = {21, 21}, // sqrt(21^2 + 21^2) = 30
 		});
-- 
cgit v1.2.3


From 33a072db28d71ba65e59f9491abd42dbf9695fc4 Mon Sep 17 00:00:00 2001
From: max-001 <maxsmits21@kpnmail.nl>
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(-)

(limited to 'src/crepe/system')

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<vec2> 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<Transform> transforms = mgr.get_components_by_id<Transform>(ai.game_object_id);
+	Transform & transform = transforms.front().get();
+	RefVector<Rigidbody> rigidbodies = mgr.get_components_by_id<Rigidbody>(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<AI> aivec = this->get_components<AI>();
+		/*RefVector<AI> aivec = this->get_components<AI>();
 		AI & ai = aivec.front().get();
 		ai.flee_target
-			= vec2{static_cast<float>(event.mouse_x), static_cast<float>(event.mouse_y)};
+			= vec2{static_cast<float>(event.mouse_x), static_cast<float>(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<Sprite>(img, Color::MAGENTA,
 										   Sprite::FlipSettings{false, false}, 1, 1, 195);
-		AI & ai = game_object1.add_component<AI>(30);
-		ai.arrive_on();
-		ai.flee_on();
+		AI & ai = game_object1.add_component<AI>(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>(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<BehaviorScript>().set_script<Script1>();
 
-		game_object2.add_component<Camera>(Color::WHITE, ivec2{1080, 720}, vec2{1036, 780},
+		game_object2.add_component<Camera>(Color::WHITE, ivec2{1080, 720}, vec2{5000, 5000},
 										   1.0f);
 	}
 
-- 
cgit v1.2.3


From 6cee1cff083fc50eeedf88537965d3c79e7b790a Mon Sep 17 00:00:00 2001
From: max-001 <maxsmits21@kpnmail.nl>
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(-)

(limited to 'src/crepe/system')

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<float>(center.x + radius * cos(i)),
+								static_cast<float>(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<float>(center.x + radius * cos(i)),
+								static_cast<float>(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<vec2> 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> ai_components = mgr.get_components_by_type<AI>();
 
+	//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<Sprite>(img, Color::MAGENTA,
 										   Sprite::FlipSettings{false, false}, 1, 1, 195);
-		AI & ai = game_object1.add_component<AI>(300);
+		AI & ai = game_object1.add_component<AI>(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>(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<BehaviorScript>().set_script<Script1>();
 
-- 
cgit v1.2.3


From c43885fa393ddf4ab28ad55643100f987b82abdc Mon Sep 17 00:00:00 2001
From: max-001 <maxsmits21@kpnmail.nl>
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(-)

(limited to 'src/crepe/system')

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 cdaf587006053874c2e286a7541e6a2b246ce2b3 Mon Sep 17 00:00:00 2001
From: max-001 <maxsmits21@kpnmail.nl>
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(-)

(limited to 'src/crepe/system')

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<vec2> 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<Rigidbody> rigidbodies
 			= mgr.get_components_by_id<Rigidbody>(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<Rigidbody> rigidbodies = mgr.get_components_by_id<Rigidbody>(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<Rigidbody> rigidbodies = mgr.get_components_by_id<Rigidbody>(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<Rigidbody> rigidbodies = mgr.get_components_by_id<Rigidbody>(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 e5e2eefc7f0f6199fe2b36688b2ad64a97784717 Mon Sep 17 00:00:00 2001
From: max-001 <maxsmits21@kpnmail.nl>
Date: Mon, 9 Dec 2024 14:15:24 +0100
Subject: Deleted header

---
 src/crepe/system/AISystem.cpp | 1 -
 1 file changed, 1 deletion(-)

(limited to 'src/crepe/system')

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 <maxsmits21@kpnmail.nl>
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(-)

(limited to 'src/crepe/system')

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 <stdexcept>
+
 #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 <cmath>
 
 #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<Rigidbody> rigidbodies
 			= mgr.get_components_by_id<Rigidbody>(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<Transform> transforms = mgr.get_components_by_id<Transform>(ai.game_object_id);
 	Transform & transform = transforms.front().get();
-	RefVector<Rigidbody> rigidbodies = mgr.get_components_by_id<Rigidbody>(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<Transform> transforms = mgr.get_components_by_id<Transform>(ai.game_object_id);
 	Transform & transform = transforms.front().get();
-	RefVector<Rigidbody> rigidbodies = mgr.get_components_by_id<Rigidbody>(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<Transform> transforms = mgr.get_components_by_id<Transform>(ai.game_object_id);
 	Transform & transform = transforms.front().get();
-	RefVector<Rigidbody> rigidbodies = mgr.get_components_by_id<Rigidbody>(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<Transform> transforms = mgr.get_components_by_id<Transform>(ai.game_object_id);
 	Transform & transform = transforms.front().get();
-	RefVector<Rigidbody> rigidbodies = mgr.get_components_by_id<Rigidbody>(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 <maxsmits21@kpnmail.nl>
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(-)

(limited to 'src/crepe/system')

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 6fc38e15e4b88d480d5fcb69eec36f7d8685e853 Mon Sep 17 00:00:00 2001
From: max-001 <maxsmits21@kpnmail.nl>
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(-)

(limited to 'src/crepe/system')

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 <cmath>
 
 #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<Transform> transforms = mgr.get_components_by_id<Transform>(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<Transform> transforms = mgr.get_components_by_id<Transform>(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<Transform> transforms = mgr.get_components_by_id<Transform>(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<Transform> transforms = mgr.get_components_by_id<Transform>(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<Transform> transforms = mgr.get_components_by_id<Transform>(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 543dc375228b520605bb099bc95a23918f75e9f8 Mon Sep 17 00:00:00 2001
From: max-001 <maxsmits21@kpnmail.nl>
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(-)

(limited to 'src/crepe/system')

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 <loek@pipeframe.xyz>
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(-)

(limited to 'src/crepe/system')

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 bea86a6fcea272d7cc7fba44d6c489bd70587578 Mon Sep 17 00:00:00 2001
From: max-001 <maxsmits21@kpnmail.nl>
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(-)

(limited to 'src/crepe/system')

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 *>(db); }
-		};
+		this->db
+			= {new DB(cfg.savemgr.location), [](void * db) { delete static_cast<DB *>(db); }};
 	}
 	return *static_cast<DB *>(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 <memory>
 #include <functional>
+#include <memory>
 
 #include "../ValueBroker.h"
 
@@ -95,9 +95,10 @@ private:
 protected:
 	//! Create or return DB
 	virtual DB & get_db();
+
 private:
 	//! Database
-	std::unique_ptr<void, std::function<void(void*)>> db = nullptr;
+	std::unique_ptr<void, std::function<void(void *)>> 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