diff --git a/modules/wave_survival/enemies/enemy_rifleman.cpp b/modules/wave_survival/enemies/enemy_rifleman.cpp index d7fe0f73..6f1655ae 100644 --- a/modules/wave_survival/enemies/enemy_rifleman.cpp +++ b/modules/wave_survival/enemies/enemy_rifleman.cpp @@ -53,24 +53,8 @@ AnimationPlayer *EnemyRifleman::get_anim() const { return this->anim; } -void RiflemanState::set_target(Node *node) { - this->target = cast_to(node); -} - EnemyRifleman *RiflemanState::get_target() const { - return this->target; -} - -NpcUnit *RiflemanState::get_unit() const { - return this->target->get_unit(); -} - -NavigationAgent3D *RiflemanState::get_nav() const { - return this->target->get_nav(); -} - -AnimationPlayer *RiflemanState::get_anim() const { - return this->target->get_anim(); + return cast_to(get_body()); } void RiflemanPatrolState::enter_state() { diff --git a/modules/wave_survival/enemies/enemy_rifleman.h b/modules/wave_survival/enemies/enemy_rifleman.h index aad13aba..611398f4 100644 --- a/modules/wave_survival/enemies/enemy_rifleman.h +++ b/modules/wave_survival/enemies/enemy_rifleman.h @@ -29,19 +29,12 @@ private: /* ============================== STATES ============================== */ -class RiflemanState : public State { +class RiflemanState : public EnemyState { GDCLASS(RiflemanState, State); static void _bind_methods() {} public: - virtual void set_target(Node *target) override; EnemyRifleman *get_target() const; - NpcUnit *get_unit() const; - NavigationAgent3D *get_nav() const; - AnimationPlayer *get_anim() const; - -private: - EnemyRifleman *target{ nullptr }; }; class RiflemanPatrolState : public RiflemanState { diff --git a/modules/wave_survival/enemies/enemy_wretched.cpp b/modules/wave_survival/enemies/enemy_wretched.cpp index ce90ad5f..7e0265e8 100644 --- a/modules/wave_survival/enemies/enemy_wretched.cpp +++ b/modules/wave_survival/enemies/enemy_wretched.cpp @@ -1,27 +1,15 @@ #include "enemy_wretched.h" -#include "wave_survival/macros.h" +#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/state_machine.h" -void EnemyWretched::_bind_methods() { - BIND_PROPERTY(Variant::FLOAT, chase_speed); -} - -void EnemyWretched::on_child_entered(Node *node) { - if (StateMachine * fsm{ cast_to(node) }) { - this->fsm = fsm; - } - if (node->has_node(NodePath("AnimationPlayer"))) { - this->anim = cast_to(node->get_node(NodePath("AnimationPlayer"))); - } -} +void EnemyWretched::_bind_methods() {} void EnemyWretched::ready() { - this->fsm->add_state(memnew(WretchedPatrolState)); - this->fsm->add_state(memnew(WretchedChaseState)); - this->fsm->add_state(memnew(WretchedAttackState)); + get_fsm()->add_state(memnew(WretchedPatrolState)); + get_fsm()->add_state(memnew(WretchedChaseState)); + get_fsm()->add_state(memnew(WretchedAttackState)); } void EnemyWretched::_notification(int what) { @@ -31,99 +19,26 @@ void EnemyWretched::_notification(int what) { switch (what) { default: return; - case NOTIFICATION_ENTER_TREE: - if (!is_ready()) { - connect("child_entered_tree", callable_mp(this, &self_type::on_child_entered)); - } - return; case NOTIFICATION_READY: ready(); return; } } -void EnemyWretched::set_chase_speed(float speed) { - this->chase_speed = speed; -} - -float EnemyWretched::get_chase_speed() const { - return this->chase_speed; -} - -AnimationPlayer *EnemyWretched::get_anim() const { - return this->anim; -} - -void WretchedState::set_target(Node *node) { - this->target = cast_to(node); -} - EnemyWretched *WretchedState::get_target() const { - return this->target; -} - -NpcUnit *WretchedState::get_unit() const { - return this->target->get_unit(); -} - -NavigationAgent3D *WretchedState::get_nav() const { - return this->target->get_nav(); -} - -AnimationPlayer *WretchedState::get_anim() const { - return this->target->get_anim(); -} - -void WretchedPatrolState::set_patrol_target(Vector3 path_point) { - get_nav()->set_target_position(path_point + get_target()->get_unit_offset_3d()); -} - -void WretchedPatrolState::on_velocity_calculated(Vector3 direction) { - get_target()->set_movement_direction(Vector2{ direction.x, direction.z } / get_target()->get_movement_speed()); -} - -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); - if (this->path) { - Vector3 const nav_target{ this->path->get_closest_point(get_target()->get_global_position(), &this->path_point) }; - set_patrol_target(nav_target); - } - get_nav()->connect("velocity_computed", this->mp_on_velocity_calculated); -} - -void WretchedPatrolState::process(double delta) { - if (this->path) { - 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()).normalized() }; - if (get_nav()->get_avoidance_enabled()) { - get_nav()->set_velocity(direction); - } else { - on_velocity_calculated(direction); - } - } -} - -void WretchedPatrolState::exit_state() { - get_nav()->disconnect("velocity_computed", this->mp_on_velocity_calculated); + return cast_to(get_body()); } String WretchedPatrolState::get_next_state() const { - if (get_target()->get_unit()->is_aware_of_player()) { + if (get_body()->get_unit()->is_aware_of_player()) { return WretchedChaseState::get_class_static(); } return get_class(); } void WretchedChaseState::enter_state() { - get_target()->set_movement_speed(get_target()->get_chase_speed()); - get_nav()->set_max_speed(get_target()->get_chase_speed()); + 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" } diff --git a/modules/wave_survival/enemies/enemy_wretched.h b/modules/wave_survival/enemies/enemy_wretched.h index a9b82182..521d4ae8 100644 --- a/modules/wave_survival/enemies/enemy_wretched.h +++ b/modules/wave_survival/enemies/enemy_wretched.h @@ -1,7 +1,6 @@ #ifndef ENEMY_WRETCHED_H #define ENEMY_WRETCHED_H -#include "scene/animation/animation_player.h" #include "wave_survival/enemy_body.h" #include "wave_survival/state.h" class PatrolPath; @@ -11,56 +10,28 @@ class StateMachine; class EnemyWretched : public EnemyBody { GDCLASS(EnemyWretched, EnemyBody); static void _bind_methods(); - void on_child_entered(Node *node); void ready(); protected: void _notification(int what); - -public: - void set_chase_speed(float speed); - float get_chase_speed() const; - AnimationPlayer *get_anim() const; - -private: - float chase_speed{ 5.f }; - StateMachine *fsm{ nullptr }; - AnimationPlayer *anim{ nullptr }; }; /* ============================== STATES ============================== */ -class WretchedState : public State { +class WretchedState : public EnemyState { GDCLASS(WretchedState, State); static void _bind_methods() {} public: - virtual void set_target(Node *node) override; EnemyWretched *get_target() const; - NpcUnit *get_unit() const; - NavigationAgent3D *get_nav() const; - AnimationPlayer *get_anim() const; - -private: - EnemyWretched *target{ nullptr }; }; -class WretchedPatrolState : public WretchedState { - GDCLASS(WretchedPatrolState, WretchedState); +class WretchedPatrolState : public PatrolState { + GDCLASS(WretchedPatrolState, PatrolState); static void _bind_methods() {} - void set_patrol_target(Vector3 path_point); - void on_velocity_calculated(Vector3 direction); public: - virtual void enter_state() override; - virtual void process(double delta) override; - virtual String get_next_state() const override; - virtual void exit_state() override; - -private: - int path_point{ 0 }; - PatrolPath *path{ nullptr }; - Callable mp_on_velocity_calculated{ callable_mp(this, &self_type::on_velocity_calculated) }; + String get_next_state() const override; }; class WretchedChaseState : public WretchedState { diff --git a/modules/wave_survival/enemy_body.cpp b/modules/wave_survival/enemy_body.cpp index 25c792b8..6aa2bc1f 100644 --- a/modules/wave_survival/enemy_body.cpp +++ b/modules/wave_survival/enemy_body.cpp @@ -1,10 +1,13 @@ #include "enemy_body.h" #include "macros.h" -#include "npc_unit.h" +#include "scene/animation/animation_player.h" +#include "wave_survival/npc_unit.h" +#include "wave_survival/patrol_path.h" void EnemyBody::_bind_methods() { ClassDB::bind_method(D_METHOD("set_movement_direction", "direction"), &self_type::set_movement_direction); ClassDB::bind_method(D_METHOD("get_unit"), &self_type::get_unit); + BIND_PROPERTY(Variant::FLOAT, max_speed); } void EnemyBody::on_child_added(Node *node) { @@ -14,6 +17,9 @@ void EnemyBody::on_child_added(Node *node) { if (NavigationAgent3D * nav{ cast_to(node) }) { this->nav = nav; } + if (node->has_node(NodePath("AnimationPlayer"))) { + this->anim = cast_to(node->get_node(NodePath("AnimationPlayer"))); + } } void EnemyBody::ready() { @@ -42,6 +48,9 @@ void EnemyBody::_notification(int what) { switch (what) { default: return; + case NOTIFICATION_ENTER_TREE: + connect("child_entered_tree", callable_mp(this, &self_type::on_child_added)); + return; case NOTIFICATION_READY: set_physics_process(true); ready(); @@ -52,6 +61,14 @@ void EnemyBody::_notification(int what) { } } +void EnemyBody::set_max_speed(float speed) { + this->max_speed = speed; +} + +float EnemyBody::get_max_speed() const { + return this->max_speed; +} + void EnemyBody::set_movement_direction(Vector2 direction) { this->movement_direction = direction; } @@ -72,6 +89,14 @@ NavigationAgent3D *EnemyBody::get_nav() const { return this->nav; } +AnimationPlayer *EnemyBody::get_anim() const { + return this->anim; +} + +StateMachine *EnemyBody::get_fsm() const { + return this->fsm; +} + void EnemyBody::set_movement_speed(float value) { this->movement_speed = value; } @@ -91,3 +116,64 @@ Vector2 EnemyBody::get_unit_offset() const { Vector3 EnemyBody::get_unit_offset_3d() const { return { this->unit_offset.x, 0, this->unit_offset.y }; } + +void EnemyState::set_target(Node *node) { + this->body = cast_to(node); + ERR_FAIL_COND_EDMSG(this->body == nullptr, "EnemyState initialised invalid target"); +} + +NpcUnit *EnemyState::get_unit() const { + return this->body->get_unit(); +} + +NavigationAgent3D *EnemyState::get_nav() const { + return this->body->get_nav(); +} + +AnimationPlayer *EnemyState::get_anim() const { + return this->body->get_anim(); +} + +EnemyBody *EnemyState::get_body() const { + return this->body; +} + +void PatrolState::set_patrol_target(Vector3 path_point) { + get_nav()->set_target_position(path_point + get_body()->get_unit_offset_3d()); +} + +void PatrolState::on_velocity_calculated(Vector3 direction) { + get_body()->set_movement_direction(Vector2{ direction.x, direction.z } / get_body()->get_movement_speed()); +} + +void PatrolState::enter_state() { + this->path = get_body()->get_unit()->get_patrol_path(); + + float const max_speed{ get_unit()->get_patrol_speed() }; + get_body()->set_movement_speed(max_speed); + get_nav()->set_max_speed(max_speed); + if (this->path) { + Vector3 const nav_target{ this->path->get_closest_point(get_body()->get_global_position(), &this->path_point) }; + set_patrol_target(nav_target); + } + get_nav()->connect("velocity_computed", this->mp_on_velocity_calculated); +} + +void PatrolState::process(double delta) { + if (this->path) { + if (get_nav()->is_navigation_finished()) { + this->path_point += 1; + set_patrol_target(this->path->point_at(this->path_point)); + } + Vector3 const direction{ get_body()->get_global_position().direction_to(get_nav()->get_next_path_position()).normalized() }; + if (get_nav()->get_avoidance_enabled()) { + get_nav()->set_velocity(direction); + } else { + on_velocity_calculated(direction); + } + } +} + +void PatrolState::exit_state() { + get_nav()->disconnect("velocity_computed", this->mp_on_velocity_calculated); +} diff --git a/modules/wave_survival/enemy_body.h b/modules/wave_survival/enemy_body.h index 2ff1016c..b8a5599c 100644 --- a/modules/wave_survival/enemy_body.h +++ b/modules/wave_survival/enemy_body.h @@ -4,8 +4,11 @@ #include "scene/3d/navigation/navigation_agent_3d.h" #include "scene/3d/physics/character_body_3d.h" #include "wave_survival/health_status.h" +#include "wave_survival/state.h" #include "wave_survival/state_machine.h" class NpcUnit; +class AnimationPlayer; +class PatrolPath; class EnemyBody : public CharacterBody3D { GDCLASS(EnemyBody, CharacterBody3D); @@ -14,15 +17,23 @@ class EnemyBody : public CharacterBody3D { void ready(); void physics_process(double delta); -public: +protected: void _notification(int what); +public: + void set_max_speed(float speed); + float get_max_speed() const; + void set_movement_direction(Vector2 direction); + void set_unit(NpcUnit *unit); NpcUnit *get_unit() const; HealthStatus *get_health() const; NavigationAgent3D *get_nav() const; + AnimationPlayer *get_anim() const; + StateMachine *get_fsm() const; + void set_movement_speed(float value); float get_movement_speed() const; void set_unit_offset(Vector2 offset); @@ -30,6 +41,7 @@ public: Vector3 get_unit_offset_3d() const; private: + float max_speed{ 4.f }; float movement_speed{ 1.f }; Vector2 movement_direction{ 0, 0 }; @@ -37,7 +49,40 @@ private: NpcUnit *unit{ nullptr }; HealthStatus *health{ nullptr }; NavigationAgent3D *nav{ nullptr }; + AnimationPlayer *anim{ nullptr }; Vector2 unit_offset{ 0, 0 }; }; +class EnemyState : public State { + GDCLASS(EnemyState, State); + static void _bind_methods() {} + +public: + void set_target(Node *node) override; + NpcUnit *get_unit() const; + NavigationAgent3D *get_nav() const; + AnimationPlayer *get_anim() const; + EnemyBody *get_body() const; + +private: + EnemyBody *body{ nullptr }; +}; + +class PatrolState : public EnemyState { + GDCLASS(PatrolState, EnemyState); + static void _bind_methods() {} + void set_patrol_target(Vector3 path_point); + void on_velocity_calculated(Vector3 direction); + +public: + virtual void enter_state() override; + virtual void process(double delta) override; + virtual void exit_state() override; + +private: + int path_point{ 0 }; + PatrolPath *path{ nullptr }; + Callable mp_on_velocity_calculated{ callable_mp(this, &self_type::on_velocity_calculated) }; +}; + #endif // !ENEMY_BODY_H