aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/crepe/api/AI.cpp15
-rw-r--r--src/crepe/api/AI.h6
-rw-r--r--src/crepe/system/AISystem.cpp46
-rw-r--r--src/crepe/system/AISystem.h18
4 files changed, 52 insertions, 33 deletions
diff --git a/src/crepe/api/AI.cpp b/src/crepe/api/AI.cpp
index 00e5b37..472550b 100644
--- a/src/crepe/api/AI.cpp
+++ b/src/crepe/api/AI.cpp
@@ -1,10 +1,17 @@
+#include <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