#include "enemy_wretched.h" #include "wave_survival/npc_unit.h" #include "wave_survival/patrol_path.h" #include "wave_survival/player_body.h" #include "wave_survival/state_machine.h" void EnemyWretched::_bind_methods() { } void EnemyWretched::ready() { if (StateMachine * fsm{ cast_to(get_node(NodePath("%StateMachine"))) }) { fsm->add_state(memnew(WretchedPatrolState)); fsm->add_state(memnew(WretchedChaseState)); fsm->add_state(memnew(WretchedAttackState)); } } void EnemyWretched::_notification(int what) { if (Engine::get_singleton()->is_editor_hint()) { return; } switch (what) { default: return; case NOTIFICATION_READY: ready(); return; } } void WretchedState::set_target(Node *node) { this->target = cast_to(node); this->nav = this->target->get_nav(); this->unit = this->target->get_unit(); } EnemyWretched *WretchedState::get_target() const { return this->target; } NpcUnit *WretchedState::get_unit() const { return this->unit; } NavigationAgent3D *WretchedState::get_nav() const { return this->nav; } void WretchedPatrolState::set_patrol_target(Vector3 path_point) { get_nav()->set_target_position(path_point + get_target()->get_unit_offset_3d()); } void WretchedPatrolState::enter_state() { this->path = get_target()->get_unit()->get_patrol_path(); float const max_speed{ get_unit()->get_patrol_speed() }; get_target()->set_movement_speed(max_speed); get_nav()->set_max_speed(max_speed); Vector3 const nav_target{ this->path->get_closest_point(get_target()->get_global_position(), &this->path_point) }; set_patrol_target(nav_target); } void WretchedPatrolState::process(double delta) { if (get_nav()->is_navigation_finished()) { this->path_point += 1; set_patrol_target(this->path->point_at(this->path_point)); } Vector3 const direction{ get_target()->get_global_position().direction_to(get_nav()->get_next_path_position()) }; get_target()->set_movement_direction(Vector2{ direction.x, direction.z }.normalized()); } String WretchedPatrolState::get_next_state() const { if (get_target()->get_unit()->is_aware_of_player()) { return WretchedChaseState::get_class_static(); } return get_class(); } void WretchedChaseState::enter_state() { // TODO: replace this with a setting somewhere get_target()->set_movement_speed(get_unit()->get_patrol_speed() * 2.f); get_nav()->set_max_speed(get_unit()->get_patrol_speed() * 2.f); get_nav()->set_target_position(PlayerBody::get_singleton()->get_global_position()); } void WretchedChaseState::process(double delta) { // TODO: optimize this with some checks to avoid re-pathing every frame get_nav()->set_target_position(PlayerBody::get_singleton()->get_global_position()); Vector3 const direction{ get_target()->get_global_position().direction_to(get_nav()->get_next_path_position()) }; get_target()->set_movement_direction(Vector2{ direction.x, direction.z }.normalized()); } String WretchedChaseState::get_next_state() const { if (get_target()->get_global_position().distance_to(PlayerBody::get_singleton()->get_global_position()) < 2.f) { return WretchedAttackState::get_class_static(); } return get_class(); } String WretchedAttackState::get_next_state() const { return WretchedChaseState::get_class_static(); }