feat: updated enemy
This commit is contained in:
parent
c3a4f8baae
commit
84673c6c29
9 changed files with 257 additions and 147 deletions
101
src/enemy.cpp
101
src/enemy.cpp
|
|
@ -19,31 +19,30 @@ void Enemy::_ready() {
|
|||
this->add_child(timer);
|
||||
timer->start(this->update_interval);
|
||||
timer->connect("timeout", callable_mp(this, &Enemy::update));
|
||||
this->target_rotation = this->get_rotation().y;
|
||||
}
|
||||
|
||||
void Enemy::_process(double delta) {
|
||||
float const angle_left{this->target_rotation - this->get_rotation().y};
|
||||
float const step(gd::Math::sign(angle_left) * delta * this->TURN_SPEED);
|
||||
if(gd::Math::abs(angle_left) <= gd::Math::abs(step)) {
|
||||
this->rotate_y(angle_left);
|
||||
this->at_target_angle = true;
|
||||
} else {
|
||||
this->rotate_y(step);
|
||||
this->at_target_angle = false;
|
||||
}
|
||||
}
|
||||
|
||||
void Enemy::update() {
|
||||
if(this->can_see_player)
|
||||
this->last_known_player_position = this->player->get_global_position();
|
||||
if(this->current_action_fn != nullptr)
|
||||
this->current_action_fn = (ActionFn)(this->*current_action_fn)();
|
||||
}
|
||||
|
||||
void Enemy::chase_enter() {
|
||||
if(this->player != nullptr)
|
||||
this->agent->set_target_position(this->player->get_global_position());
|
||||
}
|
||||
|
||||
void Enemy::chase() {
|
||||
bool const at_end{!this->agent->is_navigation_finished()};
|
||||
this->anim_tree->set_lock_running(at_end);
|
||||
this->anim_tree->set_aim_weapon(!at_end);
|
||||
if(at_end) {
|
||||
gd::Vector3 const global_pos{this->get_global_position()};
|
||||
gd::Vector3 const target{global_pos * 2 - this->agent->get_next_path_position()};
|
||||
this->look_at({target.x, global_pos.y, target.z});
|
||||
} else if(this->get_global_position().distance_to(this->player->get_global_position()) >= this->agent->get_target_desired_distance())
|
||||
this->chase_enter(); // repath
|
||||
}
|
||||
|
||||
Enemy::ActionFn Enemy::wait_line_of_sight() {
|
||||
|
||||
if(this->can_see_player)
|
||||
return (ActionFn)&Enemy::take_aim;
|
||||
else
|
||||
|
|
@ -51,49 +50,37 @@ Enemy::ActionFn Enemy::wait_line_of_sight() {
|
|||
}
|
||||
|
||||
Enemy::ActionFn Enemy::take_aim() {
|
||||
this->target_rotation = this->get_global_basis().get_column(2).signed_angle_to(this->last_known_player_position - this->get_global_position(), {0.f, 1.f, 0.f});
|
||||
this->target_rotation -= gd::Math::sign(this->target_rotation) * this->MISS_ANGLE;
|
||||
this->target_rotation += this->get_global_rotation().y;
|
||||
this->anim_tree->set_aim_weapon(true);
|
||||
if(this->anim_tree->get_current_state().begins_with("Aim"))
|
||||
return (ActionFn)&Enemy::hit;
|
||||
if(this->anim_tree->get_current_state().begins_with("Aim") && this->at_target_angle)
|
||||
return (ActionFn)&Enemy::fire;
|
||||
else
|
||||
return(ActionFn)&Enemy::take_aim;
|
||||
}
|
||||
|
||||
Enemy::ActionFn Enemy::miss() {
|
||||
if(this->can_see_player) {
|
||||
gd::Basis const basis{this->get_global_basis()};
|
||||
this->look_at(this->get_global_position() * 2 - this->player->get_global_position() + basis.get_column(0) * 0.6f);
|
||||
this->anim_tree->set_aim_weapon(true);
|
||||
this->anim_tree->set_fire_weapon();
|
||||
++this->missed_shots;
|
||||
return (ActionFn)&Enemy::wait_end_of_shot;
|
||||
} else {
|
||||
this->chase();
|
||||
}
|
||||
return (ActionFn)&Enemy::miss;
|
||||
}
|
||||
|
||||
Enemy::ActionFn Enemy::hit() {
|
||||
if(this->can_see_player) {
|
||||
this->look_at(this->get_global_position() * 2 - this->player->get_global_position());
|
||||
this->anim_tree->set_aim_weapon(true);
|
||||
this->anim_tree->set_fire_weapon();
|
||||
this->missed_shots = 0;
|
||||
return (ActionFn)&Enemy::wait_end_of_shot;
|
||||
} else {
|
||||
this->chase();
|
||||
}
|
||||
return (ActionFn)&Enemy::hit;
|
||||
Enemy::ActionFn Enemy::fire() {
|
||||
this->anim_tree->set_fire_weapon();
|
||||
this->missed_shots = (this->missed_shots + 1) % (this->SHOTS_BEFORE_HIT + 1);
|
||||
return (ActionFn)&Enemy::wait_end_of_shot;
|
||||
}
|
||||
|
||||
Enemy::ActionFn Enemy::wait_end_of_shot() {
|
||||
if(this->anim_tree->get_current_state().begins_with("Fire") || this->anim_tree->get_fire_weapon()) // last shot still going
|
||||
return (ActionFn)&Enemy::wait_end_of_shot;
|
||||
else
|
||||
return this->missed_shots >= SHOTS_BEFORE_HIT ? (ActionFn)&Enemy::hit : (ActionFn)&Enemy::miss;
|
||||
float const target_diff{this->get_global_basis().get_column(2).signed_angle_to(this->last_known_player_position - this->get_global_position(), {0.f, 1.f, 0.f})};
|
||||
this->target_rotation = this->get_global_rotation().y + target_diff;
|
||||
if(this->missed_shots < this->SHOTS_BEFORE_HIT)
|
||||
this->target_rotation -= gd::Math::sign(target_diff) * this->MISS_ANGLE;
|
||||
else if(this->missed_shots >= this->SHOTS_BEFORE_HIT)
|
||||
this->target_rotation -= gd::Math::sign(target_diff) * this->HIT_ANGLE;
|
||||
|
||||
if(this->at_target_angle && !this->anim_tree->get_current_state().begins_with("Fire") && !this->anim_tree->get_fire_weapon())
|
||||
return (ActionFn)&Enemy::fire;
|
||||
else
|
||||
return (ActionFn)&Enemy::wait_end_of_shot;
|
||||
}
|
||||
|
||||
void Enemy::_physics_process(double delta) {
|
||||
void Enemy::_physics_process(double delta [[maybe_unused]]) {
|
||||
this->update_can_see_player();
|
||||
gd::Basis const basis{this->get_global_basis()};
|
||||
gd::Vector3 const motion{this->anim_tree->get_root_motion_position()};
|
||||
|
|
@ -119,11 +106,17 @@ void Enemy::notice_player(Player *player) {
|
|||
void Enemy::update_can_see_player() {
|
||||
if(this->player == nullptr)
|
||||
return;
|
||||
gd::Vector3 origin{this->get_global_position() + gd::Vector3{0.f, 1.8f, 0.f}};
|
||||
gd::PhysicsDirectSpaceState3D *space{this->get_world_3d()->get_direct_space_state()};
|
||||
gd::Ref<gd::PhysicsRayQueryParameters3D> query{gd::PhysicsRayQueryParameters3D::create(origin, this->player->get_global_position() + gd::Vector3{0.f, 1.8f, 0.f})};
|
||||
gd::Dictionary dict{space->intersect_ray(query)};
|
||||
this->can_see_player = (dict.is_empty() || gd::Object::cast_to<Node>(dict["collider"]) == this->player);
|
||||
gd::Vector3 const origin{this->get_global_position() + gd::Vector3{0.f, 1.8f, 0.f}};
|
||||
gd::Vector3 const target{this->player->get_global_position() + gd::Vector3{0.f, 1.8f, 0.f}};
|
||||
float const dot{(target - origin).normalized().dot(this->get_global_basis().get_column(2))};
|
||||
if(dot <= 0.2f && target.distance_to(origin) > 4.f) {
|
||||
this->can_see_player = false;
|
||||
} else {
|
||||
gd::PhysicsDirectSpaceState3D *space{this->get_world_3d()->get_direct_space_state()};
|
||||
gd::Ref<gd::PhysicsRayQueryParameters3D> query{gd::PhysicsRayQueryParameters3D::create(origin, target)};
|
||||
gd::Dictionary dict{space->intersect_ray(query)};
|
||||
this->can_see_player = (dict.is_empty() || gd::Object::cast_to<Node>(dict["collider"]) == this->player);
|
||||
}
|
||||
}
|
||||
|
||||
void Enemy::set_update_interval(float time) {
|
||||
|
|
|
|||
|
|
@ -16,27 +16,29 @@ typedef void *(Enemy::*ActionFn_)();
|
|||
typedef ActionFn_ (Enemy::*ActionFn)();
|
||||
public:
|
||||
virtual void _ready() override;
|
||||
virtual void _process(double delta) override;
|
||||
void update();
|
||||
void chase_enter();
|
||||
void chase();
|
||||
ActionFn wait_line_of_sight();
|
||||
ActionFn take_aim();
|
||||
ActionFn miss();
|
||||
ActionFn hit();
|
||||
ActionFn fire();
|
||||
ActionFn stab_enter();
|
||||
ActionFn stab();
|
||||
ActionFn wait_end_of_shot();
|
||||
virtual void _physics_process(double delta) override;
|
||||
virtual void damage() override;
|
||||
|
||||
void notice_player(Player *player);
|
||||
void update_can_see_player();
|
||||
|
||||
void set_update_interval(float time);
|
||||
float get_update_interval() const;
|
||||
private:
|
||||
int const SHOTS_BEFORE_HIT{1};
|
||||
int const SHOTS_BEFORE_HIT{0};
|
||||
float const TURN_SPEED{3.f};
|
||||
float const HIT_ANGLE{.05f};
|
||||
float const MISS_ANGLE{.2f};
|
||||
|
||||
float target_rotation{0.f};
|
||||
bool at_target_angle{false};
|
||||
gd::Vector3 last_known_player_position{0.f, 0.f, 0.f};
|
||||
int missed_shots{0};
|
||||
double update_interval{0.4};
|
||||
ActionFn current_action_fn{nullptr};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue