diff options
Diffstat (limited to 'src/crepe')
| -rw-r--r-- | src/crepe/api/AI.cpp | 11 | ||||
| -rw-r--r-- | src/crepe/api/AI.h | 60 | ||||
| -rw-r--r-- | src/crepe/api/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/crepe/api/LoopManager.cpp | 14 | ||||
| -rw-r--r-- | src/crepe/api/Vector2.h | 24 | ||||
| -rw-r--r-- | src/crepe/api/Vector2.hpp | 48 | ||||
| -rw-r--r-- | src/crepe/system/AISystem.cpp | 75 | ||||
| -rw-r--r-- | src/crepe/system/AISystem.h | 23 | ||||
| -rw-r--r-- | src/crepe/system/CMakeLists.txt | 2 | 
9 files changed, 258 insertions, 1 deletions
| diff --git a/src/crepe/api/AI.cpp b/src/crepe/api/AI.cpp new file mode 100644 index 0000000..7f820a8 --- /dev/null +++ b/src/crepe/api/AI.cpp @@ -0,0 +1,11 @@ +#include "AI.h" + +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) {} + +} // namespace crepe diff --git a/src/crepe/api/AI.h b/src/crepe/api/AI.h new file mode 100644 index 0000000..242ff89 --- /dev/null +++ b/src/crepe/api/AI.h @@ -0,0 +1,60 @@ +#pragma once + +#include "Component.h" +#include "types.h" + +namespace crepe { + +class AI : public Component { +public: +	enum BehaviorType { +		NONE = 0x00000, +		SEEK = 0x00002, +		FLEE = 0x00004, +		ARRIVE = 0x00008, +		PATH_FOLLOW = 0x00010, +	}; + +public: +	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: +	vec2 velocity; +	friend class AISystem; + +	int flags = 0; +}; + +} // namespace crepe diff --git a/src/crepe/api/CMakeLists.txt b/src/crepe/api/CMakeLists.txt index ac8f301..0355b72 100644 --- a/src/crepe/api/CMakeLists.txt +++ b/src/crepe/api/CMakeLists.txt @@ -22,6 +22,7 @@ target_sources(crepe PUBLIC  	Script.cpp  	Button.cpp  	UIObject.cpp +	AI.cpp  )  target_sources(crepe PUBLIC FILE_SET HEADERS FILES @@ -54,4 +55,5 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES  	Asset.h  	Button.h  	UIObject.h +	AI.h  ) diff --git a/src/crepe/api/LoopManager.cpp b/src/crepe/api/LoopManager.cpp index dc2d9e0..e4b1609 100644 --- a/src/crepe/api/LoopManager.cpp +++ b/src/crepe/api/LoopManager.cpp @@ -1,3 +1,5 @@ +#include "../facade/SDLContext.h" +#include "../system/AISystem.h"  #include "../system/AnimatorSystem.h"  #include "../system/CollisionSystem.h"  #include "../system/InputSystem.h" @@ -22,6 +24,7 @@ LoopManager::LoopManager() {  	this->load_system<RenderSystem>();  	this->load_system<ScriptSystem>();  	this->load_system<InputSystem>(); +	this->load_system<AISystem>();  }  void LoopManager::process_input() { this->get_system<InputSystem>().update(); } @@ -51,6 +54,11 @@ void LoopManager::loop() {  		this->render();  		timer.enforce_frame_rate(); + +		// Stop the game after 10 seconds, for testing purposes +		if (timer.get_current_time() > 10) { +			this->game_running = false; +		}  	}  } @@ -60,6 +68,7 @@ void LoopManager::setup() {  	this->game_running = true;  	timer.start();  	timer.set_fps(200); +	this->scene_manager.load_next_scene();  }  void LoopManager::render() { @@ -68,4 +77,7 @@ void LoopManager::render() {  	this->get_system<RenderSystem>().update();  } -void LoopManager::update() {} +void LoopManager::update() { +	this->get_system<AnimatorSystem>().update(); +	this->get_system<AISystem>().update(); +} diff --git a/src/crepe/api/Vector2.h b/src/crepe/api/Vector2.h index c278c87..bbcb932 100644 --- a/src/crepe/api/Vector2.h +++ b/src/crepe/api/Vector2.h @@ -66,6 +66,30 @@ struct Vector2 {  	//! Checks if this vector is not equal to another vector.  	bool operator!=(const Vector2<T> & other) const; + +	//! Truncates the vector to a maximum length. +	void truncate(T max); + +	//! Normalizes the vector. +	void normalize(); + +	//! Returns the length of the vector. +	T length() const; + +	//! Returns the squared length of the vector. +	T length_squared() const; + +	//! Returns the dot product of this vector and another vector. +	T dot(const Vector2<T> & other) const; + +	//! Returns the distance between this vector and another vector. +	T distance(const Vector2<T> & other) const; + +	//! Returns the squared distance between this vector and another vector. +	T distance_squared(const Vector2<T> & other) const; + +	//! Returns the perpendicular vector to this vector. +	Vector2 perpendicular() const;  };  } // namespace crepe diff --git a/src/crepe/api/Vector2.hpp b/src/crepe/api/Vector2.hpp index cad15f8..ff53cb0 100644 --- a/src/crepe/api/Vector2.hpp +++ b/src/crepe/api/Vector2.hpp @@ -1,5 +1,7 @@  #pragma once +#include <cmath> +  #include "Vector2.h"  namespace crepe { @@ -115,4 +117,50 @@ bool Vector2<T>::operator!=(const Vector2<T> & other) const {  	return !(*this == other);  } +template <class T> +void Vector2<T>::truncate(T max) { +	if (length() > max) { +		normalize(); +		*this *= max; +	} +} + +template <class T> +void Vector2<T>::normalize() { +	T len = length(); +	if (len > 0) { +		*this /= len; +	} +} + +template <class T> +T Vector2<T>::length() const { +	return std::sqrt(x * x + y * y); +} + +template <class T> +T Vector2<T>::length_squared() const { +	return x * x + y * y; +} + +template <class T> +T Vector2<T>::dot(const Vector2<T> & other) const { +	return x * other.x + y * other.y; +} + +template <class T> +T Vector2<T>::distance(const Vector2<T> & other) const { +	return (*this - other).length(); +} + +template <class T> +T Vector2<T>::distance_squared(const Vector2<T> & other) const { +	return (*this - other).length_squared(); +} + +template <class T> +Vector2<T> Vector2<T>::perpendicular() const { +	return {-y, x}; +} +  } // namespace crepe diff --git a/src/crepe/system/AISystem.cpp b/src/crepe/system/AISystem.cpp new file mode 100644 index 0000000..9029f32 --- /dev/null +++ b/src/crepe/system/AISystem.cpp @@ -0,0 +1,75 @@ +#include "../ComponentManager.h" +#include "api/LoopTimer.h" +#include "api/Transform.h" +#include "types.h" + +#include "AISystem.h" + +using namespace crepe; + +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; +	} +} + +vec2 AISystem::calculate(AI & ai) { +	vec2 force; + +	if (ai.on(AI::BehaviorType::SEEK)) { +		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 +	} +	if (ai.on(AI::BehaviorType::ARRIVE)) { +		// Arrive at the target +	} +	if (ai.on(AI::BehaviorType::PATH_FOLLOW)) { +		// Follow the path +	} + +	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 new file mode 100644 index 0000000..5e94ccb --- /dev/null +++ b/src/crepe/system/AISystem.h @@ -0,0 +1,23 @@ +#pragma once + +#include "api/AI.h" + +#include "System.h" +#include "types.h" + +namespace crepe { + +class AISystem : public System { +public: +	using System::System; + +	void update() override; + +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/crepe/system/CMakeLists.txt b/src/crepe/system/CMakeLists.txt index 95f6e33..7de5198 100644 --- a/src/crepe/system/CMakeLists.txt +++ b/src/crepe/system/CMakeLists.txt @@ -7,6 +7,7 @@ target_sources(crepe PUBLIC  	RenderSystem.cpp  	AnimatorSystem.cpp  	InputSystem.cpp +	AISystem.cpp  )  target_sources(crepe PUBLIC FILE_SET HEADERS FILES @@ -17,4 +18,5 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES  	RenderSystem.h  	AnimatorSystem.h  	InputSystem.h +	AISystem.h  ) |