diff --git a/modules/wave_survival/enemies/enemy_rifleman.cpp b/modules/wave_survival/enemies/enemy_rifleman.cpp index 6f1655ae..d7fe0f73 100644 --- a/modules/wave_survival/enemies/enemy_rifleman.cpp +++ b/modules/wave_survival/enemies/enemy_rifleman.cpp @@ -53,8 +53,24 @@ 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 cast_to(get_body()); + 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(); } void RiflemanPatrolState::enter_state() { diff --git a/modules/wave_survival/enemies/enemy_rifleman.h b/modules/wave_survival/enemies/enemy_rifleman.h index 611398f4..aad13aba 100644 --- a/modules/wave_survival/enemies/enemy_rifleman.h +++ b/modules/wave_survival/enemies/enemy_rifleman.h @@ -29,12 +29,19 @@ private: /* ============================== STATES ============================== */ -class RiflemanState : public EnemyState { +class RiflemanState : public State { 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 7e0265e8..ce90ad5f 100644 --- a/modules/wave_survival/enemies/enemy_wretched.cpp +++ b/modules/wave_survival/enemies/enemy_wretched.cpp @@ -1,15 +1,27 @@ #include "enemy_wretched.h" -#include "scene/animation/animation_player.h" +#include "wave_survival/macros.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::_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::ready() { - get_fsm()->add_state(memnew(WretchedPatrolState)); - get_fsm()->add_state(memnew(WretchedChaseState)); - get_fsm()->add_state(memnew(WretchedAttackState)); + this->fsm->add_state(memnew(WretchedPatrolState)); + this->fsm->add_state(memnew(WretchedChaseState)); + this->fsm->add_state(memnew(WretchedAttackState)); } void EnemyWretched::_notification(int what) { @@ -19,26 +31,99 @@ 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 cast_to(get_body()); + 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); } String WretchedPatrolState::get_next_state() const { - if (get_body()->get_unit()->is_aware_of_player()) { + if (get_target()->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_max_speed()); - get_nav()->set_max_speed(get_target()->get_max_speed()); + get_target()->set_movement_speed(get_target()->get_chase_speed()); + get_nav()->set_max_speed(get_target()->get_chase_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 521d4ae8..a9b82182 100644 --- a/modules/wave_survival/enemies/enemy_wretched.h +++ b/modules/wave_survival/enemies/enemy_wretched.h @@ -1,6 +1,7 @@ #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; @@ -10,28 +11,56 @@ 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 EnemyState { +class WretchedState : public State { 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 PatrolState { - GDCLASS(WretchedPatrolState, PatrolState); +class WretchedPatrolState : public WretchedState { + GDCLASS(WretchedPatrolState, WretchedState); static void _bind_methods() {} + void set_patrol_target(Vector3 path_point); + void on_velocity_calculated(Vector3 direction); public: - String get_next_state() const override; + 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) }; }; class WretchedChaseState : public WretchedState { diff --git a/modules/wave_survival/enemy_body.cpp b/modules/wave_survival/enemy_body.cpp index 6aa2bc1f..25c792b8 100644 --- a/modules/wave_survival/enemy_body.cpp +++ b/modules/wave_survival/enemy_body.cpp @@ -1,13 +1,10 @@ #include "enemy_body.h" #include "macros.h" -#include "scene/animation/animation_player.h" -#include "wave_survival/npc_unit.h" -#include "wave_survival/patrol_path.h" +#include "npc_unit.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) { @@ -17,9 +14,6 @@ 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() { @@ -48,9 +42,6 @@ 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(); @@ -61,14 +52,6 @@ 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; } @@ -89,14 +72,6 @@ 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; } @@ -116,64 +91,3 @@ 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 b8a5599c..2ff1016c 100644 --- a/modules/wave_survival/enemy_body.h +++ b/modules/wave_survival/enemy_body.h @@ -4,11 +4,8 @@ #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); @@ -17,23 +14,15 @@ class EnemyBody : public CharacterBody3D { void ready(); void physics_process(double delta); -protected: +public: 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); @@ -41,7 +30,6 @@ public: Vector3 get_unit_offset_3d() const; private: - float max_speed{ 4.f }; float movement_speed{ 1.f }; Vector2 movement_direction{ 0, 0 }; @@ -49,40 +37,7 @@ 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 diff --git a/project/assets/models/environment/wall_2x1.blend b/project/assets/models/environment/wall_2x1.blend index 11f93329..b749766a 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/assets/models/environment/wall_top_half_slope.blend b/project/assets/models/environment/wall_top_half_slope.blend index 7c14c266..ce6d09e0 100644 Binary files a/project/assets/models/environment/wall_top_half_slope.blend and b/project/assets/models/environment/wall_top_half_slope.blend differ diff --git a/project/assets/models/environment/wall_top_half_slope_top.blend b/project/assets/models/environment/wall_top_half_slope_top.blend index b708a827..13c209f8 100644 Binary files a/project/assets/models/environment/wall_top_half_slope_top.blend and b/project/assets/models/environment/wall_top_half_slope_top.blend differ diff --git a/project/maps/industrial_area_map.scn b/project/maps/industrial_area_map.scn index d1e97a03..31f5b85b 100644 Binary files a/project/maps/industrial_area_map.scn and b/project/maps/industrial_area_map.scn differ diff --git a/project/objects/pickups/demo_pack_pickup.tscn b/project/objects/pickups/demo_pack_pickup.tscn index 5e2f9b2a..f68bbc45 100644 --- a/project/objects/pickups/demo_pack_pickup.tscn +++ b/project/objects/pickups/demo_pack_pickup.tscn @@ -14,16 +14,13 @@ func _highlight_changed(_interactor: PlayerInteractor, value: bool) -> void: func _activated(interactor: PlayerInteractor) -> void: interactor.pickup_demo_pack() get_owner().queue_free() - -func _process(delta : float): - $\"../MeshInstance3D\".global_rotate(Vector3(0, 1, 0), delta) " [sub_resource type="BoxMesh" id="BoxMesh_kl827"] size = Vector3(0.19555664, 0.13061523, 0.37719727) [node name="DemoPackPickup" type="StaticBody3D" unique_id=1833876644] -collision_layer = 16 +collision_layer = 18 [node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=1902989490] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.248144, 0)