diff options
-rw-r--r-- | src/crepe/api/AI.h | 10 | ||||
-rw-r--r-- | src/crepe/system/AISystem.cpp | 23 |
2 files changed, 27 insertions, 6 deletions
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); } |