feat: added simple enemy with chase behaviour
This commit is contained in:
parent
4f564a4f4c
commit
19ba4047ca
10 changed files with 202 additions and 15 deletions
69
src/enemy.cpp
Normal file
69
src/enemy.cpp
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
#include "enemy.hpp"
|
||||
#include "godot_cpp/classes/time.hpp"
|
||||
#include "godot_cpp/variant/utility_functions.hpp"
|
||||
#include "health.hpp"
|
||||
#include "player_character.hpp"
|
||||
#include "utils/godot_macros.h"
|
||||
#include <godot_cpp/classes/navigation_agent3d.hpp>
|
||||
|
||||
namespace godot {
|
||||
void Enemy::_bind_methods() {
|
||||
#define CLASSNAME Enemy
|
||||
GDFUNCTION_ARGS(body_entered_vision_area, "body");
|
||||
}
|
||||
|
||||
void Enemy::_ready() { GDGAMEONLY();
|
||||
this->health = this->get_node<Health>("Health");
|
||||
this->nav_agent = this->get_node<NavigationAgent3D>("NavigationAgent3D");
|
||||
this->vision_area = this->get_node<Area3D>("VisionArea");
|
||||
this->vision_area->connect("body_entered", Callable(this, "body_entered_vision_area"));
|
||||
this->update_navigation_target();
|
||||
}
|
||||
|
||||
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) {
|
||||
PlayerCharacter *player = Object::cast_to<PlayerCharacter>(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());
|
||||
}
|
||||
|
||||
Health *Enemy::get_health() {
|
||||
return this->health;
|
||||
}
|
||||
|
||||
Health const *Enemy::get_health() const {
|
||||
return this->health;
|
||||
}
|
||||
|
||||
float const Enemy::RENAV_INTERVAL{0.25f};
|
||||
}
|
||||
40
src/enemy.hpp
Normal file
40
src/enemy.hpp
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
#ifndef ENEMY_HPP
|
||||
#define ENEMY_HPP
|
||||
|
||||
#include "godot_cpp/classes/area3d.hpp"
|
||||
#include "health.hpp"
|
||||
#include <godot_cpp/classes/character_body3d.hpp>
|
||||
|
||||
namespace godot {
|
||||
class PlayerCharacter;
|
||||
class NavigationAgent3D;
|
||||
|
||||
class Enemy : public CharacterBody3D,
|
||||
public IHealthEntity {
|
||||
GDCLASS(Enemy, CharacterBody3D);
|
||||
static void _bind_methods();
|
||||
public:
|
||||
virtual void _ready() override;
|
||||
virtual void _process(double delta_time) override;
|
||||
void process_navigation(double delta_time);
|
||||
|
||||
void body_entered_vision_area(Node3D *body);
|
||||
|
||||
void update_navigation_target();
|
||||
|
||||
virtual Health *get_health() override;
|
||||
virtual Health const *get_health() const override;
|
||||
|
||||
private:
|
||||
float renav_time{0.f};
|
||||
|
||||
PlayerCharacter *target_player{nullptr};
|
||||
Health *health{nullptr};
|
||||
NavigationAgent3D *nav_agent{nullptr};
|
||||
Area3D *vision_area{nullptr};
|
||||
|
||||
static float const RENAV_INTERVAL;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // !ENEMY_HPP
|
||||
|
|
@ -9,6 +9,7 @@
|
|||
#include "utils/level.hpp"
|
||||
#include "utils/player_input.hpp"
|
||||
#include "utils/spawn_point.hpp"
|
||||
#include "enemy.hpp"
|
||||
#include "health.hpp"
|
||||
#include "player_character.hpp"
|
||||
#include "tunnels_game_mode.hpp"
|
||||
|
|
@ -22,16 +23,18 @@ void initialize_gdextension_types(ModuleInitializationLevel p_level)
|
|||
return;
|
||||
}
|
||||
ClassDB::register_abstract_class<GameRoot>();
|
||||
ClassDB::register_class<GameRoot3D>();
|
||||
ClassDB::register_class<SpawnPoint3D>();
|
||||
ClassDB::register_class<PlayerInput>();
|
||||
ClassDB::register_class<GameMode>();
|
||||
ClassDB::register_class<GameRoot3D>();
|
||||
ClassDB::register_class<GameState>();
|
||||
ClassDB::register_class<Level3D>();
|
||||
ClassDB::register_class<PlayerInput>();
|
||||
ClassDB::register_class<SpawnPoint3D>();
|
||||
|
||||
ClassDB::register_class<Enemy>();
|
||||
ClassDB::register_class<Health>();
|
||||
ClassDB::register_class<PlayerCharacter>();
|
||||
ClassDB::register_class<TunnelsGameMode>();
|
||||
ClassDB::register_class<TunnelsPlayer>();
|
||||
ClassDB::register_class<PlayerCharacter>();
|
||||
ClassDB::register_class<Health>();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ void TunnelsPlayer::process_mouse_location(double delta_time) {
|
|||
|
||||
void TunnelsPlayer::process_camera_rotation(double delta_time) {
|
||||
Vector3 rotation = this->get_global_rotation();
|
||||
float const y_multiplier = std::max(0.4f, this->mouse_location.y); // the influence of the mouse's y position on the rotation speed
|
||||
float const y_multiplier = std::max(TunnelsPlayer::ROTATION_Y_MIN_INFLUENCE, this->mouse_location.y); // the influence of the mouse's y position on the rotation speed
|
||||
// rotate the camera when the mouse is close to the edge of the screen
|
||||
if(this->mouse_location.x < TunnelsPlayer::ROTATION_MARGIN) {
|
||||
// normalized measurement of how far into the rotation margin the mouse is
|
||||
|
|
@ -156,6 +156,7 @@ Ref<Curve> TunnelsPlayer::get_camera_rotation_ramp() const {
|
|||
return this->camera_rotation_ramp;
|
||||
}
|
||||
|
||||
float const TunnelsPlayer::ROTATION_SPEED{4.f};
|
||||
float const TunnelsPlayer::ROTATION_MARGIN{0.35f};
|
||||
float const TunnelsPlayer::ROTATION_SPEED{6.f};
|
||||
float const TunnelsPlayer::ROTATION_Y_MIN_INFLUENCE{7.f};
|
||||
float const TunnelsPlayer::ROTATION_MARGIN{0.4f};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,7 +53,9 @@ private:
|
|||
Camera3D *camera{nullptr};
|
||||
|
||||
Ref<Curve> camera_rotation_ramp{};
|
||||
|
||||
static float const ROTATION_SPEED;
|
||||
static float const ROTATION_Y_MIN_INFLUENCE;
|
||||
static float const ROTATION_MARGIN;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue