diff options
Diffstat (limited to 'src/crepe/api')
-rw-r--r-- | src/crepe/api/AI.cpp | 30 | ||||
-rw-r--r-- | src/crepe/api/AI.h | 114 | ||||
-rw-r--r-- | src/crepe/api/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/crepe/api/LoopManager.cpp | 6 | ||||
-rw-r--r-- | src/crepe/api/Script.h | 1 | ||||
-rw-r--r-- | src/crepe/api/Vector2.h | 24 | ||||
-rw-r--r-- | src/crepe/api/Vector2.hpp | 48 |
7 files changed, 224 insertions, 1 deletions
diff --git a/src/crepe/api/AI.cpp b/src/crepe/api/AI.cpp new file mode 100644 index 0000000..49f6b92 --- /dev/null +++ b/src/crepe/api/AI.cpp @@ -0,0 +1,30 @@ +#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) { + // 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 new file mode 100644 index 0000000..18276a1 --- /dev/null +++ b/src/crepe/api/AI.h @@ -0,0 +1,114 @@ +#pragma once + +#include "Component.h" +#include "types.h" + +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, + FLEE = 0x00004, + ARRIVE = 0x00008, + PATH_FOLLOW = 0x00010, + }; + +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; + } + + /** + * \brief Add a path node + * + * \note The path is not relative to the entity's position (it is an absolute path) + * + * \param node The path node to add + */ + void add_path_node(vec2 node) { path.push_back(node); } + /** + * \brief Make a circle path + * + * \note The path is not relative to the entity's position (it is an absolute path) + * + * \param radius The radius of the circle (in game units) + * \param center The center of the circle (in game units) + * \param start_angle The start angle of the circle (in radians) + * \param clockwise The direction of the circle + */ + void make_circle_path(float radius, vec2 center = {0, 0}, float start_angle = 0, + bool clockwise = true); + +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 + 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 = 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 should access the flags and path_index variables + friend class AISystem; +}; + +} // namespace crepe diff --git a/src/crepe/api/CMakeLists.txt b/src/crepe/api/CMakeLists.txt index 593c4e6..f869d88 100644 --- a/src/crepe/api/CMakeLists.txt +++ b/src/crepe/api/CMakeLists.txt @@ -24,6 +24,7 @@ target_sources(crepe PUBLIC Script.cpp Button.cpp UIObject.cpp + AI.cpp ) target_sources(crepe PUBLIC FILE_SET HEADERS FILES @@ -58,4 +59,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 88243c4..cf8a0d0 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" @@ -20,6 +22,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(); } @@ -35,6 +38,7 @@ void LoopManager::fixed_update() { EventManager & ev = this->mediator.event_manager; ev.dispatch_events(); this->get_system<ScriptSystem>().update(); + this->get_system<AISystem>().update(); this->get_system<PhysicsSystem>().update(); this->get_system<CollisionSystem>().update(); } @@ -74,4 +78,4 @@ void LoopManager::render() { this->get_system<RenderSystem>().update(); } -void LoopManager::update() {} +void LoopManager::update() { this->get_system<AnimatorSystem>().update(); } diff --git a/src/crepe/api/Script.h b/src/crepe/api/Script.h index d99ab0e..e351e6a 100644 --- a/src/crepe/api/Script.h +++ b/src/crepe/api/Script.h @@ -7,6 +7,7 @@ #include "../system/CollisionSystem.h" #include "../types.h" #include "../util/OptionalRef.h" +#include "system/CollisionSystem.h" namespace crepe { diff --git a/src/crepe/api/Vector2.h b/src/crepe/api/Vector2.h index c278c87..bf9d124 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 (resulting in vector with a length of 1). + 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 (inwendig 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 |