diff --git a/modules/wave_survival/enemies/enemy_rifleman.cpp b/modules/wave_survival/enemies/enemy_rifleman.cpp index e6ba5a13..6f1655ae 100644 --- a/modules/wave_survival/enemies/enemy_rifleman.cpp +++ b/modules/wave_survival/enemies/enemy_rifleman.cpp @@ -2,8 +2,6 @@ #include "core/os/memory.h" #include "scene/animation/animation_player.h" #include "wave_survival/macros.h" -#include "wave_survival/npc_unit.h" -#include "wave_survival/player_detector.h" #include "wave_survival/state_machine.h" void EnemyRifleman::_bind_methods() { @@ -21,7 +19,7 @@ void EnemyRifleman::on_child_entered(Node *node) { void EnemyRifleman::ready() { this->fsm->add_state(memnew(RiflemanPatrolState)); - this->fsm->add_state(memnew(RiflemanChaseState)); + this->fsm->add_state(memnew(RiflemanSeekState)); this->fsm->add_state(memnew(RiflemanFireState)); } @@ -59,15 +57,5 @@ EnemyRifleman *RiflemanState::get_target() const { return cast_to(get_body()); } -String RiflemanPatrolState::get_next_state() const { - if (get_body()->get_unit()->is_aware_of_player()) { - return RiflemanChaseState::get_class_static(); - } - return get_class(); -} - -String RiflemanChaseState::get_next_state() const { - if (get_body()->get_detector()->line_of_sight_exists()) { - } - return get_class(); +void RiflemanPatrolState::enter_state() { } diff --git a/modules/wave_survival/enemies/enemy_rifleman.h b/modules/wave_survival/enemies/enemy_rifleman.h index e164cc68..611398f4 100644 --- a/modules/wave_survival/enemies/enemy_rifleman.h +++ b/modules/wave_survival/enemies/enemy_rifleman.h @@ -37,20 +37,18 @@ public: EnemyRifleman *get_target() const; }; -class RiflemanPatrolState : public EnemyPatrolState { - GDCLASS(RiflemanPatrolState, EnemyPatrolState); +class RiflemanPatrolState : public RiflemanState { + GDCLASS(RiflemanPatrolState, RiflemanState); static void _bind_methods() {} public: - String get_next_state() const override; + virtual void enter_state() override; + virtual void process(double delta) override; }; -class RiflemanChaseState : public EnemyChaseState { - GDCLASS(RiflemanChaseState, EnemyChaseState); +class RiflemanSeekState : public RiflemanState { + GDCLASS(RiflemanSeekState, RiflemanState); static void _bind_methods() {} - -public: - String get_next_state() const override; }; class RiflemanFireState : public RiflemanState { diff --git a/modules/wave_survival/enemies/enemy_wretched.cpp b/modules/wave_survival/enemies/enemy_wretched.cpp index 53d1b604..7e0265e8 100644 --- a/modules/wave_survival/enemies/enemy_wretched.cpp +++ b/modules/wave_survival/enemies/enemy_wretched.cpp @@ -36,8 +36,22 @@ String WretchedPatrolState::get_next_state() const { return get_class(); } +void WretchedChaseState::enter_state() { + get_target()->set_movement_speed(get_target()->get_max_speed()); + get_nav()->set_max_speed(get_target()->get_max_speed()); + get_nav()->set_target_position(PlayerBody::get_singleton()->get_global_position()); + get_anim()->play("ready"); // TODO: replace this with "run" +} + +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_body()->get_global_position().distance_to(PlayerBody::get_singleton()->get_global_position()) < 2.f) { + if (get_target()->get_global_position().distance_to(PlayerBody::get_singleton()->get_global_position()) < 2.f) { return WretchedAttackState::get_class_static(); } return get_class(); diff --git a/modules/wave_survival/enemies/enemy_wretched.h b/modules/wave_survival/enemies/enemy_wretched.h index 814bc9e6..521d4ae8 100644 --- a/modules/wave_survival/enemies/enemy_wretched.h +++ b/modules/wave_survival/enemies/enemy_wretched.h @@ -26,19 +26,21 @@ public: EnemyWretched *get_target() const; }; -class WretchedPatrolState : public EnemyPatrolState { - GDCLASS(WretchedPatrolState, EnemyPatrolState); +class WretchedPatrolState : public PatrolState { + GDCLASS(WretchedPatrolState, PatrolState); static void _bind_methods() {} public: String get_next_state() const override; }; -class WretchedChaseState : public EnemyChaseState { - GDCLASS(WretchedChaseState, EnemyChaseState); +class WretchedChaseState : public WretchedState { + GDCLASS(WretchedChaseState, WretchedState); static void _bind_methods() {} public: + virtual void enter_state() override; + virtual void process(double delta) override; virtual String get_next_state() const override; }; diff --git a/modules/wave_survival/enemy_body.cpp b/modules/wave_survival/enemy_body.cpp index f5244667..6aa2bc1f 100644 --- a/modules/wave_survival/enemy_body.cpp +++ b/modules/wave_survival/enemy_body.cpp @@ -3,8 +3,6 @@ #include "scene/animation/animation_player.h" #include "wave_survival/npc_unit.h" #include "wave_survival/patrol_path.h" -#include "wave_survival/player_body.h" -#include "wave_survival/player_detector.h" void EnemyBody::_bind_methods() { ClassDB::bind_method(D_METHOD("set_movement_direction", "direction"), &self_type::set_movement_direction); @@ -19,9 +17,6 @@ void EnemyBody::on_child_added(Node *node) { if (NavigationAgent3D * nav{ cast_to(node) }) { this->nav = nav; } - if (PlayerDetector * detector{ cast_to(node) }) { - this->detector = detector; - } if (node->has_node(NodePath("AnimationPlayer"))) { this->anim = cast_to(node->get_node(NodePath("AnimationPlayer"))); } @@ -54,9 +49,7 @@ void EnemyBody::_notification(int what) { default: return; case NOTIFICATION_ENTER_TREE: - if (!is_ready()) { - connect("child_entered_tree", callable_mp(this, &self_type::on_child_added)); - } + connect("child_entered_tree", callable_mp(this, &self_type::on_child_added)); return; case NOTIFICATION_READY: set_physics_process(true); @@ -104,10 +97,6 @@ StateMachine *EnemyBody::get_fsm() const { return this->fsm; } -PlayerDetector *EnemyBody::get_detector() const { - return this->detector; -} - void EnemyBody::set_movement_speed(float value) { this->movement_speed = value; } @@ -149,15 +138,15 @@ EnemyBody *EnemyState::get_body() const { return this->body; } -void EnemyPatrolState::set_patrol_target(Vector3 path_point) { +void PatrolState::set_patrol_target(Vector3 path_point) { get_nav()->set_target_position(path_point + get_body()->get_unit_offset_3d()); } -void EnemyPatrolState::on_velocity_calculated(Vector3 direction) { +void PatrolState::on_velocity_calculated(Vector3 direction) { get_body()->set_movement_direction(Vector2{ direction.x, direction.z } / get_body()->get_movement_speed()); } -void EnemyPatrolState::enter_state() { +void PatrolState::enter_state() { this->path = get_body()->get_unit()->get_patrol_path(); float const max_speed{ get_unit()->get_patrol_speed() }; @@ -170,7 +159,7 @@ void EnemyPatrolState::enter_state() { get_nav()->connect("velocity_computed", this->mp_on_velocity_calculated); } -void EnemyPatrolState::process(double delta) { +void PatrolState::process(double delta) { if (this->path) { if (get_nav()->is_navigation_finished()) { this->path_point += 1; @@ -185,20 +174,6 @@ void EnemyPatrolState::process(double delta) { } } -void EnemyPatrolState::exit_state() { +void PatrolState::exit_state() { get_nav()->disconnect("velocity_computed", this->mp_on_velocity_calculated); } - -void EnemyChaseState::enter_state() { - get_body()->set_movement_speed(get_body()->get_max_speed()); - get_nav()->set_max_speed(get_body()->get_max_speed()); - get_nav()->set_target_position(PlayerBody::get_singleton()->get_global_position()); - get_anim()->play("ready"); // TODO: replace this with "run" -} - -void EnemyChaseState::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_body()->get_global_position().direction_to(get_nav()->get_next_path_position()) }; - get_body()->set_movement_direction(Vector2{ direction.x, direction.z }.normalized()); -} diff --git a/modules/wave_survival/enemy_body.h b/modules/wave_survival/enemy_body.h index a2172fd5..b8a5599c 100644 --- a/modules/wave_survival/enemy_body.h +++ b/modules/wave_survival/enemy_body.h @@ -9,7 +9,6 @@ class NpcUnit; class AnimationPlayer; class PatrolPath; -class PlayerDetector; class EnemyBody : public CharacterBody3D { GDCLASS(EnemyBody, CharacterBody3D); @@ -34,7 +33,6 @@ public: NavigationAgent3D *get_nav() const; AnimationPlayer *get_anim() const; StateMachine *get_fsm() const; - PlayerDetector *get_detector() const; void set_movement_speed(float value); float get_movement_speed() const; @@ -52,12 +50,9 @@ private: HealthStatus *health{ nullptr }; NavigationAgent3D *nav{ nullptr }; AnimationPlayer *anim{ nullptr }; - PlayerDetector *detector{ nullptr }; Vector2 unit_offset{ 0, 0 }; }; -/* ============================== STATES ============================== */ - class EnemyState : public State { GDCLASS(EnemyState, State); static void _bind_methods() {} @@ -73,8 +68,8 @@ private: EnemyBody *body{ nullptr }; }; -class EnemyPatrolState : public EnemyState { - GDCLASS(EnemyPatrolState, EnemyState); +class PatrolState : public EnemyState { + GDCLASS(PatrolState, EnemyState); static void _bind_methods() {} void set_patrol_target(Vector3 path_point); void on_velocity_calculated(Vector3 direction); @@ -90,13 +85,4 @@ private: Callable mp_on_velocity_calculated{ callable_mp(this, &self_type::on_velocity_calculated) }; }; -class EnemyChaseState : public EnemyState { - GDCLASS(EnemyChaseState, EnemyState); - static void _bind_methods() {} - -public: - virtual void enter_state() override; - virtual void process(double delta) override; -}; - #endif // !ENEMY_BODY_H diff --git a/modules/wave_survival/player_detector.cpp b/modules/wave_survival/player_detector.cpp index 6869cccf..3a550bfd 100644 --- a/modules/wave_survival/player_detector.cpp +++ b/modules/wave_survival/player_detector.cpp @@ -8,6 +8,17 @@ void PlayerDetector::_bind_methods() { ADD_SIGNAL(MethodInfo(sig_awareness_changed, PropertyInfo(Variant::BOOL, "aware"))); } +// check if there is geometry between detector and player +bool PlayerDetector::line_of_sight_exists() const { + PhysicsDirectSpaceState3D::RayParameters params{ this->ray_params }; + params.from = get_global_position(); + params.to = PlayerBody::get_singleton()->get_global_position(); + PhysicsDirectSpaceState3D *space{ get_world_3d()->get_direct_space_state() }; + PhysicsDirectSpaceState3D::RayResult result{}; + space->intersect_ray(params, result); + return result.collider == nullptr; +} + // Check if the player is in a bounded area in front of the detector and unobscured. // As all tests are required to pass, we do them in increasing order of complexity, to minimize unneeded resource use. bool PlayerDetector::check() const { @@ -71,17 +82,6 @@ void PlayerDetector::_notification(int what) { } } -// check if there is geometry between detector and player -bool PlayerDetector::line_of_sight_exists() const { - PhysicsDirectSpaceState3D::RayParameters params{ this->ray_params }; - params.from = get_global_position(); - params.to = PlayerBody::get_singleton()->get_global_position(); - PhysicsDirectSpaceState3D *space{ get_world_3d()->get_direct_space_state() }; - PhysicsDirectSpaceState3D::RayResult result{}; - space->intersect_ray(params, result); - return result.collider == nullptr; -} - bool PlayerDetector::is_aware_of_player() const { return this->aware_of_player; } diff --git a/modules/wave_survival/player_detector.h b/modules/wave_survival/player_detector.h index f57f0dca..b9447aca 100644 --- a/modules/wave_survival/player_detector.h +++ b/modules/wave_survival/player_detector.h @@ -6,6 +6,7 @@ class PlayerDetector : public Node3D { GDCLASS(PlayerDetector, Node3D); static void _bind_methods(); + bool line_of_sight_exists() const; bool check() const; void ready(); void process(double delta); @@ -16,7 +17,6 @@ protected: void _notification(int what); public: - bool line_of_sight_exists() const; bool is_aware_of_player() const; private: diff --git a/project/assets/models/environment/wall_2x1.blend b/project/assets/models/environment/wall_2x1.blend index 8d0c351d..11f93329 100644 Binary files a/project/assets/models/environment/wall_2x1.blend and b/project/assets/models/environment/wall_2x1.blend differ diff --git a/project/objects/enemies/enemy_wretched.tscn b/project/objects/enemies/enemy_wretched.tscn index 0254546c..0c0fb3f5 100644 --- a/project/objects/enemies/enemy_wretched.tscn +++ b/project/objects/enemies/enemy_wretched.tscn @@ -89,7 +89,7 @@ time_horizon_agents = 0.7 [node name="PlayerDetector" type="PlayerDetector" parent="." unique_id=592530198] unique_name_in_owner = true -transform = Transform3D(-1, 0, -8.742278e-08, 0, 1, 0, 8.742278e-08, 0, -1, 0, 1.5103652, 0) +transform = Transform3D(-1, 0, -8.742278e-08, 0, 1, 0, 8.742278e-08, 0, -1, 0, 1.4599279, 0) [node name="HealthStatus" type="HealthStatus" parent="." unique_id=625738980] unique_name_in_owner = true