#include "enemy.hpp" #include "godot_cpp/classes/time.hpp" #include "health.hpp" #include "character_actor.hpp" #include "utils/godot_macros.h" #include namespace godot { void Enemy::_bind_methods() { #define CLASSNAME Enemy GDFUNCTION_ARGS(body_entered_vision_area, "body"); GDFUNCTION_ARGS(on_death, "damage"); GDFUNCTION_ARGS(on_damage, "damage", "remaining"); } void Enemy::_ready() { GDGAMEONLY(); this->health = this->get_node("Health"); this->nav_agent = this->get_node("NavigationAgent3D"); this->vision_area = this->get_node("VisionArea"); this->vision_area->connect("body_entered", Callable(this, "body_entered_vision_area")); this->update_navigation_target(); this->health->connect("death", Callable(this, "on_death")); this->health->connect("damage", Callable(this, "on_damage")); } void Enemy::_process(double delta_time) { GDGAMEONLY(); if(this->renav_time > Time::get_singleton()->get_ticks_msec() / 1000.f) { this->update_navigation_target(); } this->process_navigation(delta_time); this->move_and_slide(); } void Enemy::process_navigation(double delta_time) { if(this->nav_agent->is_navigation_finished()) { return; } Vector3 const desired_direction = (this->nav_agent->get_next_path_position() - this->get_global_position()).normalized(); this->set_velocity(desired_direction); Transform3D trans = this->get_global_transform(); Vector3 const forward = desired_direction; trans.set_basis(Basis{desired_direction.cross(Vector3{0.f, 1.f, 0.f}), Vector3{0.f, 1.f, 0.f}, forward}); this->set_global_transform(trans); } void Enemy::body_entered_vision_area(Node3D *body) { CharacterActor *player = Object::cast_to(body); if(player == nullptr) return; // TODO: replace this with some condition deciding wether to attack the new character or the current target this->target_player = player; this->update_navigation_target(); } void Enemy::update_navigation_target() { this->renav_time = float(Time::get_singleton()->get_ticks_msec()) / 1000.f + Enemy::RENAV_INTERVAL; if(this->target_player == nullptr) this->nav_agent->set_target_position(this->get_global_position()); else this->nav_agent->set_target_position(this->target_player->get_global_position()); } void Enemy::on_damage(int delta, int health_left) { } void Enemy::on_death(int delta) { this->queue_free(); } Health *Enemy::get_health() { return this->health; } Health const *Enemy::get_health() const { return this->health; } float const Enemy::RENAV_INTERVAL{0.25f}; }