Compare commits

..

9 commits

14 changed files with 165 additions and 92 deletions

View file

@ -4,6 +4,7 @@
void EnemyBody::_bind_methods() { void EnemyBody::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_movement_direction", "direction"), &self_type::set_movement_direction); 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);
} }
void EnemyBody::on_child_added(Node *node) { void EnemyBody::on_child_added(Node *node) {

View file

@ -60,7 +60,7 @@ void EnemySpawner::on_phase_change(bool hunt) {
return; return;
} }
unit_3d->set_patrol_path(this->patrol_path); unit_3d->set_patrol_path(this->patrol_path);
add_child(unit_3d); callable_mp(cast_to<Node>(this->region), &Node::add_child).call_deferred(unit_3d, false, INTERNAL_MODE_DISABLED);
unit_3d->set_global_transform(this->get_global_transform()); unit_3d->set_global_transform(this->get_global_transform());
} }

View file

@ -1,5 +1,6 @@
#include "map_region.h" #include "map_region.h"
#include "enemy_body.h" #include "enemy_body.h"
#include "player_body.h"
String const MapRegion::sig_difficulty_increased{ "difficulty_increased" }; String const MapRegion::sig_difficulty_increased{ "difficulty_increased" };
String const MapRegion::sig_phase_changed{ "hunt_phase" }; String const MapRegion::sig_phase_changed{ "hunt_phase" };
@ -7,16 +8,33 @@ String const MapRegion::sig_phase_changed{ "hunt_phase" };
void MapRegion::_bind_methods() { void MapRegion::_bind_methods() {
ADD_SIGNAL(MethodInfo(sig_difficulty_increased)); ADD_SIGNAL(MethodInfo(sig_difficulty_increased));
ADD_SIGNAL(MethodInfo(sig_phase_changed, PropertyInfo(Variant::BOOL, "hunt"))); ADD_SIGNAL(MethodInfo(sig_phase_changed, PropertyInfo(Variant::BOOL, "hunt")));
ClassDB::bind_method(D_METHOD("raise_difficulty", "amount"), &self_type::raise_difficulty);
} }
void MapRegion::on_node_entered(Node *node) { void MapRegion::on_node_entered(Node3D *node) {
if (EnemyBody * body{ cast_to<EnemyBody>(node) }) { if (cast_to<PlayerBody>(node) != nullptr) {
if (!this->units.has(body->get_unit())) { this->has_player = true;
body->get_unit()->set_region(this); }
}
void MapRegion::on_node_exited(Node3D *node) {
if (cast_to<PlayerBody>(node) != nullptr) {
this->has_player = false;
}
}
void MapRegion::on_child_entered_tree(Node *node) {
if (NpcUnit * unit{ cast_to<NpcUnit>(node) }) {
if (!this->units.has(unit)) {
unit->set_region(this);
} }
} }
} }
void MapRegion::enter_tree() {
connect("child_entered_tree", callable_mp(this, &self_type::on_child_entered_tree));
}
void MapRegion::ready() { void MapRegion::ready() {
connect("body_entered", callable_mp(this, &self_type::on_node_entered)); connect("body_entered", callable_mp(this, &self_type::on_node_entered));
} }
@ -28,6 +46,9 @@ void MapRegion::_notification(int what) {
switch (what) { switch (what) {
default: default:
return; return;
case NOTIFICATION_ENTER_TREE:
enter_tree();
return;
case NOTIFICATION_READY: case NOTIFICATION_READY:
ready(); ready();
return; return;
@ -50,10 +71,12 @@ void MapRegion::raise_difficulty(double amount) {
if (this->hunt_phase) { if (this->hunt_phase) {
return; return;
} }
double const new_difficulty{ this->difficulty + amount }; print_line("Difficutly Increased");
int const new_trunc{ (int)Math::floor(new_difficulty) };
int const old_trunc{ (int)Math::floor(this->difficulty) }; int const old_trunc{ (int)Math::floor(this->difficulty) };
this->difficulty += amount;
int const new_trunc{ (int)Math::floor(this->difficulty) };
if (new_trunc != old_trunc) { if (new_trunc != old_trunc) {
print_line("Hunt Phase Started");
emit_signal(sig_difficulty_increased); emit_signal(sig_difficulty_increased);
emit_signal(sig_phase_changed, true); emit_signal(sig_phase_changed, true);
this->hunt_phase = true; this->hunt_phase = true;

View file

@ -8,7 +8,10 @@
class MapRegion : public Area3D { class MapRegion : public Area3D {
GDCLASS(MapRegion, Area3D); GDCLASS(MapRegion, Area3D);
static void _bind_methods(); static void _bind_methods();
void on_node_entered(Node *node); void on_node_entered(Node3D *node);
void on_node_exited(Node3D *node);
void on_child_entered_tree(Node *node);
void enter_tree();
void ready(); void ready();
protected: protected:
@ -24,6 +27,7 @@ private:
double difficulty{ 0.f }; double difficulty{ 0.f };
bool hunt_phase{ false }; bool hunt_phase{ false };
HashSet<NpcUnit *> units{ nullptr }; HashSet<NpcUnit *> units{ nullptr };
bool has_player{ false };
public: public:
static String const sig_difficulty_increased; static String const sig_difficulty_increased;

View file

@ -8,6 +8,24 @@
void NpcUnit::_bind_methods() { void NpcUnit::_bind_methods() {
BIND_HPROPERTY(Variant::OBJECT, patrol_path, PROPERTY_HINT_NODE_TYPE, "PatrolPath"); BIND_HPROPERTY(Variant::OBJECT, patrol_path, PROPERTY_HINT_NODE_TYPE, "PatrolPath");
BIND_PROPERTY(Variant::FLOAT, patrol_speed); BIND_PROPERTY(Variant::FLOAT, patrol_speed);
BIND_HPROPERTY(Variant::OBJECT, region, PROPERTY_HINT_NODE_TYPE, "MapRegion");
}
void NpcUnit::on_npc_death() {
// remove any dead npcs from the list
// leaving their bodies as separate nodes part of the tree
for (EnemyBody *npc : this->npcs) {
if (npc->get_health()->get_health() <= 0) {
this->get_parent()->add_child(npc);
this->npcs.erase(npc);
break;
}
}
// remove unit from world once all npcs are dead
if (this->npcs.size() <= 0) {
this->set_region(nullptr); // de-register from region
this->queue_free();
}
} }
void NpcUnit::on_npc_awareness_changed(bool value) { void NpcUnit::on_npc_awareness_changed(bool value) {
@ -22,9 +40,6 @@ void NpcUnit::child_added(Node *node) {
npc->set_unit(this); npc->set_unit(this);
Vector3 const offset{ npc->get_global_position() - get_global_position() }; Vector3 const offset{ npc->get_global_position() - get_global_position() };
npc->set_unit_offset({ offset.x, offset.z }); npc->set_unit_offset({ offset.x, offset.z });
if (PlayerDetector * detector{ cast_to<PlayerDetector>(npc->get_node(NodePath("%PlayerDetector"))) }) {
detector->connect(PlayerDetector::sig_awareness_changed, callable_mp(this, &self_type::on_npc_awareness_changed));
}
} }
} }
@ -32,7 +47,19 @@ void NpcUnit::enter_tree() {
this->connect("child_entered_tree", callable_mp(this, &self_type::child_added)); this->connect("child_entered_tree", callable_mp(this, &self_type::child_added));
} }
void NpcUnit::ready() {
for (EnemyBody *npc : this->npcs) {
if (PlayerDetector * detector{ cast_to<PlayerDetector>(npc->get_node(NodePath("%PlayerDetector"))) }) {
detector->connect(PlayerDetector::sig_awareness_changed, callable_mp(this, &self_type::on_npc_awareness_changed));
}
if (HealthStatus * health{ npc->get_health() }) {
health->connect(HealthStatus::sig_death, callable_mp(this, &self_type::on_npc_death));
}
}
}
void NpcUnit::_notification(int what) { void NpcUnit::_notification(int what) {
// only run in-game
if (Engine::get_singleton()->is_editor_hint()) { if (Engine::get_singleton()->is_editor_hint()) {
return; return;
} }
@ -42,6 +69,9 @@ void NpcUnit::_notification(int what) {
case NOTIFICATION_ENTER_TREE: case NOTIFICATION_ENTER_TREE:
enter_tree(); enter_tree();
return; return;
case NOTIFICATION_READY:
ready();
return;
} }
} }
@ -67,13 +97,17 @@ float NpcUnit::get_patrol_speed() const {
void NpcUnit::set_region(MapRegion *region) { void NpcUnit::set_region(MapRegion *region) {
if (this->region == region) { if (this->region == region) {
return; return; // don't re-register
} }
if (this->region != nullptr) { if (this->region != nullptr) {
this->region->remove_unit(this); this->region->remove_unit(this);
this->region->disconnect(MapRegion::sig_phase_changed, callable_mp(this, &self_type::on_npc_awareness_changed));
} }
this->region = region; this->region = region;
if (region != nullptr) {
region->register_unit(this); region->register_unit(this);
region->connect(MapRegion::sig_phase_changed, callable_mp(this, &self_type::on_npc_awareness_changed));
}
} }
MapRegion *NpcUnit::get_region() const { MapRegion *NpcUnit::get_region() const {

View file

@ -10,9 +10,11 @@ class MapRegion;
class NpcUnit : public Node3D { class NpcUnit : public Node3D {
GDCLASS(NpcUnit, Node3D); GDCLASS(NpcUnit, Node3D);
static void _bind_methods(); static void _bind_methods();
void on_npc_death();
void on_npc_awareness_changed(bool seen); void on_npc_awareness_changed(bool seen);
void child_added(Node *node); void child_added(Node *node);
void enter_tree(); void enter_tree();
void ready();
protected: protected:
void _notification(int what); void _notification(int what);

File diff suppressed because one or more lines are too long

View file

@ -5,12 +5,15 @@
[sub_resource type="GDScript" id="GDScript_qot2n"] [sub_resource type="GDScript" id="GDScript_qot2n"]
script/source = "extends EnemyWretched script/source = "extends EnemyWretched
@export var difficulty_weight : float = 0.25
func _on_health_status_death() -> void: func _on_health_status_death() -> void:
%StateMachine.process_mode = Node.PROCESS_MODE_DISABLED %StateMachine.process_mode = Node.PROCESS_MODE_DISABLED
%NavigationAgent3D.process_mode = Node.PROCESS_MODE_DISABLED %NavigationAgent3D.process_mode = Node.PROCESS_MODE_DISABLED
$wretched/AnimationPlayer.play(\"death\") $wretched/AnimationPlayer.play(\"death\")
$CollisionShape3D.disabled = true $CollisionShape3D.disabled = true
set_movement_direction(Vector2()) set_movement_direction(Vector2())
get_unit().region.raise_difficulty(difficulty_weight)
" "
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_ng1ul"] [sub_resource type="CapsuleShape3D" id="CapsuleShape3D_ng1ul"]