diff options
Diffstat (limited to 'src/crepe')
| -rw-r--r-- | src/crepe/api/AI.cpp | 15 | ||||
| -rw-r--r-- | src/crepe/api/AI.h | 6 | ||||
| -rw-r--r-- | src/crepe/system/AISystem.cpp | 46 | ||||
| -rw-r--r-- | src/crepe/system/AISystem.h | 18 | 
4 files changed, 52 insertions, 33 deletions
| diff --git a/src/crepe/api/AI.cpp b/src/crepe/api/AI.cpp index 00e5b37..472550b 100644 --- a/src/crepe/api/AI.cpp +++ b/src/crepe/api/AI.cpp @@ -1,10 +1,17 @@ +#include <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 |