#include "patrol_path.h" void PatrolPath::_bind_methods() {} void PatrolPath::child_added(Node *child) { if (Node3D * child3d{ cast_to(child) }) { this->path.push_back(child3d); } } void PatrolPath::child_removed(Node *child) { if (Node3D * child3d{ cast_to(child) }) { this->path.erase(child3d); } } void PatrolPath::enter_tree() { this->connect("child_entered_tree", callable_mp(this, &self_type::child_added)); this->connect("child_exiting_tree", callable_mp(this, &self_type::child_removed)); } void PatrolPath::_notification(int what) { if (Engine::get_singleton()->is_editor_hint()) { return; } switch (what) { default: return; case NOTIFICATION_ENTER_TREE: enter_tree(); return; } } int PatrolPath::point_count() const { return this->path.size(); } Vector3 PatrolPath::point_at(int &index) const { index = Math::abs(index) % point_count(); return point_at_unchecked(index); } Vector3 PatrolPath::point_at_unchecked(int const index) const { return this->path.get(index)->get_global_position(); } int PatrolPath::get_closest_point(Vector3 global_position) { int best_choice_idx{ -1 }; float best_choice_distance{ Math::INF }; for (int i{ 0 }; i < point_count(); ++i) { int const next_idx{ (i + 1) % point_count() }; Vector3 const current{ point_at(i) }; Vector3 const next{ point_at_unchecked(next_idx) }; Vector3 const path_direction{ (next - current).normalized() }; Vector3 const direction{ (global_position - current).normalized() }; float const distance{ global_position.distance_squared_to(next) }; if (path_direction.dot(direction) > 1.0 && distance < best_choice_distance) { best_choice_idx = next_idx; best_choice_distance = distance; } } return best_choice_idx; }