179 lines
4.8 KiB
C++
179 lines
4.8 KiB
C++
#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"
|
|
|
|
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) {
|
|
if (StateMachine * fsm{ cast_to<StateMachine>(node) }) {
|
|
this->fsm = fsm;
|
|
}
|
|
if (NavigationAgent3D * nav{ cast_to<NavigationAgent3D>(node) }) {
|
|
this->nav = nav;
|
|
}
|
|
if (node->has_node(NodePath("AnimationPlayer"))) {
|
|
this->anim = cast_to<AnimationPlayer>(node->get_node(NodePath("AnimationPlayer")));
|
|
}
|
|
}
|
|
|
|
void EnemyBody::ready() {
|
|
this->fsm = cast_to<StateMachine>(get_node(NodePath("%StateMachine")));
|
|
this->nav = cast_to<NavigationAgent3D>(get_node(NodePath("%NavigationAgent3D")));
|
|
this->health = cast_to<HealthStatus>(get_node(NodePath("%HealthStatus")));
|
|
}
|
|
|
|
void EnemyBody::physics_process(double delta) {
|
|
GETSET(velocity, {
|
|
velocity = Vector3{ this->movement_direction.x * this->movement_speed, velocity.y, this->movement_direction.y * this->movement_speed } + (velocity * delta);
|
|
if (!is_on_floor() && this->health->get_health() > 0) {
|
|
velocity += get_gravity() * delta;
|
|
}
|
|
});
|
|
if (!this->movement_direction.is_zero_approx()) {
|
|
look_at(get_global_position() + Vector3{ this->movement_direction.x, 0.f, this->movement_direction.y });
|
|
}
|
|
move_and_slide();
|
|
}
|
|
|
|
void EnemyBody::_notification(int what) {
|
|
if (Engine::get_singleton()->is_editor_hint()) {
|
|
return;
|
|
}
|
|
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();
|
|
return;
|
|
case NOTIFICATION_PHYSICS_PROCESS:
|
|
physics_process(get_physics_process_delta_time());
|
|
return;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
void EnemyBody::set_unit(NpcUnit *unit) {
|
|
this->unit = unit;
|
|
}
|
|
|
|
NpcUnit *EnemyBody::get_unit() const {
|
|
return this->unit;
|
|
}
|
|
|
|
HealthStatus *EnemyBody::get_health() const {
|
|
return this->health;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
float EnemyBody::get_movement_speed() const {
|
|
return this->movement_speed;
|
|
}
|
|
|
|
void EnemyBody::set_unit_offset(Vector2 offset) {
|
|
this->unit_offset = offset;
|
|
}
|
|
|
|
Vector2 EnemyBody::get_unit_offset() const {
|
|
return this->unit_offset;
|
|
}
|
|
|
|
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<EnemyBody>(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);
|
|
}
|