Compare commits

..

No commits in common. "c4bd5edb540a0bc4991a5ea1cc865a1a73f500e6" and "6153e73492ee9e03e09617d966267a348914b49f" have entirely different histories.

21 changed files with 239 additions and 372 deletions

3
.gitignore vendored
View file

@ -22,6 +22,3 @@ build.zip
wave-survival-fps.kdev4 wave-survival-fps.kdev4
__pycache__ __pycache__
modules/wave_survival/__pycache__ modules/wave_survival/__pycache__
# blender auto backups
*.blend1

2
engine

@ -1 +1 @@
Subproject commit 084d5d407e62efcd5be9de44148c5dedce3b9386 Subproject commit c6d130abd9188f313e6701d01a0ddd6ea32166a0

View file

@ -4,7 +4,7 @@ BUILD_NAME := "wave_survival"
build: format build: format
# Compiling Editor # Compiling Editor
cd engine/ && scons target=editor symbols=yes optimization=debug dev_build=yes linker=mold use_llvm=yes custom_modules="../modules" compiledb=yes cd engine/ && scons target=editor symbols=yes optimization=debug dev_build=yes linker=mold use_llvm=yes custom_modules="../modules"
run: build run: build
# Running Editor # Running Editor

View file

@ -33,11 +33,9 @@ void DamageBox::_notification(int what) {
default: default:
return; return;
case NOTIFICATION_ENTER_TREE: case NOTIFICATION_ENTER_TREE:
if (!is_ready()) { connect("body_entered", callable_mp(this, &self_type::on_body_entered));
connect("body_entered", callable_mp(this, &self_type::on_body_entered)); connect("area_entered", callable_mp(this, &self_type::on_body_entered));
connect("area_entered", callable_mp(this, &self_type::on_body_entered)); set_monitoring(false);
set_monitoring(false);
}
return; return;
} }
} }

View file

@ -1,26 +0,0 @@
#include "enemy_rifleman.h"
void EnemyRifleman::_bind_methods() {
}
void EnemyRifleman::on_child_entered() {
}
void EnemyRifleman::ready() {
}
void EnemyRifleman::_notification(int what) {
if (Engine::get_singleton()->is_editor_hint()) {
return;
}
switch (what) {
default:
return;
case NOTIFICATION_ENTER_TREE:
enter_tree();
return;
case NOTIFICATION_READY:
ready();
return;
}
}

View file

@ -2,55 +2,10 @@
#define ENEMY_RIFLEMAN_H #define ENEMY_RIFLEMAN_H
#include "wave_survival/enemy_body.h" #include "wave_survival/enemy_body.h"
#include "wave_survival/state.h"
class AnimationPlayer;
class NavigationAgent3D;
class EnemyRifleman : public EnemyBody { class EnemyRifleman : public EnemyBody {
GDCLASS(EnemyRifleman, EnemyBody); GDCLASS(EnemyRifleman, EnemyBody);
static void _bind_methods(); static void _bind_methods();
void on_child_entered();
void enter_tree();
void ready();
protected:
void _notification(int what);
};
/* ============================== STATES ============================== */
class RiflemanState : public State {
GDCLASS(RiflemanState, State);
static void _bind_methods();
public:
virtual void set_target(Node *target) override;
EnemyRifleman *get_target() const;
NpcUnit *get_unit() const;
NavigationAgent3D *get_agent() const;
AnimationPlayer *get_anim() const;
private:
EnemyRifleman *target{ nullptr };
};
class RiflemanPatrolState : public RiflemanState {
GDCLASS(RiflemanPatrolState, RiflemanState);
static void _bind_methods();
public:
virtual void enter_state() override;
virtual void process(double delta) override;
};
class RiflemanSeekState : public RiflemanState {
GDCLASS(RiflemanSeekState, RiflemanState);
static void _bind_methods();
};
class RiflemanFireState : public RiflemanState {
GDCLASS(RiflemanFireState, RiflemanState);
static void _bind_methods();
}; };
#endif // !ENEMY_RIFLEMAN_H #endif // !ENEMY_RIFLEMAN_H

View file

@ -33,9 +33,7 @@ void EnemyWretched::_notification(int what) {
default: default:
return; return;
case NOTIFICATION_ENTER_TREE: case NOTIFICATION_ENTER_TREE:
if (!is_ready()) { connect("child_entered_tree", callable_mp(this, &self_type::on_child_entered));
connect("child_entered_tree", callable_mp(this, &self_type::on_child_entered));
}
return; return;
case NOTIFICATION_READY: case NOTIFICATION_READY:
ready(); ready();

View file

@ -19,15 +19,11 @@ void EnemyBody::on_child_added(Node *node) {
void EnemyBody::ready() { void EnemyBody::ready() {
this->fsm = cast_to<StateMachine>(get_node(NodePath("%StateMachine"))); this->fsm = cast_to<StateMachine>(get_node(NodePath("%StateMachine")));
this->nav = cast_to<NavigationAgent3D>(get_node(NodePath("%NavigationAgent3D"))); this->nav = cast_to<NavigationAgent3D>(get_node(NodePath("%NavigationAgent3D")));
this->health = cast_to<HealthStatus>(get_node(NodePath("%HealthStatus")));
} }
void EnemyBody::physics_process(double delta) { void EnemyBody::physics_process(double delta) {
GETSET(velocity, { GETSET(velocity, {
velocity = Vector3{ this->movement_direction.x * this->movement_speed, velocity.y, this->movement_direction.y * this->movement_speed } + (velocity * delta); 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()) { if (!this->movement_direction.is_zero_approx()) {
look_at(get_global_position() + Vector3{ this->movement_direction.x, 0.f, this->movement_direction.y }); look_at(get_global_position() + Vector3{ this->movement_direction.x, 0.f, this->movement_direction.y });

View file

@ -3,7 +3,7 @@
#include "core/io/resource.h" #include "core/io/resource.h"
#include "core/templates/hash_map.h" #include "core/templates/hash_map.h"
#include "scene/3d/marker_3d.h" #include "scene/3d/node_3d.h"
class MapRegion; class MapRegion;
class PatrolPath; class PatrolPath;
@ -19,8 +19,8 @@ public:
HashMap<int, Ref<PackedScene>> difficulty_spawns{}; HashMap<int, Ref<PackedScene>> difficulty_spawns{};
}; };
class EnemySpawner : public Marker3D { class EnemySpawner : public Node3D {
GDCLASS(EnemySpawner, Marker3D); GDCLASS(EnemySpawner, Node3D);
static void _bind_methods(); static void _bind_methods();
void on_phase_change(bool hunt); void on_phase_change(bool hunt);
void ready(); void ready();

View file

@ -1,5 +1,4 @@
#include "health_status.h" #include "health_status.h"
#include "core/config/engine.h"
#include "macros.h" #include "macros.h"
String HealthStatus::sig_death{ "death" }; String HealthStatus::sig_death{ "death" };

View file

@ -11,28 +11,18 @@ void NpcUnit::_bind_methods() {
BIND_HPROPERTY(Variant::OBJECT, region, PROPERTY_HINT_NODE_TYPE, "MapRegion"); BIND_HPROPERTY(Variant::OBJECT, region, PROPERTY_HINT_NODE_TYPE, "MapRegion");
} }
void NpcUnit::remove_npc(EnemyBody *npc) {
Transform3D const tf{ npc->get_global_transform() };
remove_child(npc);
this->get_parent()->add_child(npc);
npc->set_global_transform(tf);
}
void NpcUnit::on_npc_death() { void NpcUnit::on_npc_death() {
Vector<EnemyBody>::Size living{ this->npcs.size() };
// remove any dead npcs from the list // remove any dead npcs from the list
// leaving their bodies as separate nodes part of the tree // leaving their bodies as separate nodes part of the tree
for (Vector<EnemyBody>::Size i{ 0 }; i < this->npcs.size(); ++i) { for (EnemyBody *npc : this->npcs) {
EnemyBody *npc{ this->npcs[i] };
if (npc->get_health()->get_health() <= 0) { if (npc->get_health()->get_health() <= 0) {
--living; this->get_parent()->add_child(npc);
this->npcs.erase(npc);
break;
} }
} }
// remove unit from world once all npcs are dead // remove unit from world once all npcs are dead
if (living == 0) { if (this->npcs.size() <= 0) {
for (EnemyBody *npc : this->npcs) {
remove_npc(npc);
}
this->set_region(nullptr); // de-register from region this->set_region(nullptr); // de-register from region
this->queue_free(); this->queue_free();
} }

View file

@ -10,7 +10,6 @@ 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 remove_npc(EnemyBody *unit);
void on_npc_death(); 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);

View file

@ -1,6 +1,4 @@
#include "player_input.h" #include "player_input.h"
#include "core/config/engine.h"
#include "core/input/input.h"
#include "scene/main/scene_tree.h" #include "scene/main/scene_tree.h"
String PlayerInput::sig_movement_input{ "movement_input" }; String PlayerInput::sig_movement_input{ "movement_input" };

View file

@ -1,5 +1,4 @@
#include "state_machine.h" #include "state_machine.h"
#include "core/config/engine.h"
#include "state.h" #include "state.h"
void StateMachine::_bind_methods() {} void StateMachine::_bind_methods() {}
@ -19,7 +18,7 @@ void StateMachine::switch_to_state(State *state) {
} }
void StateMachine::process(double delta) { void StateMachine::process(double delta) {
if (this->current_state && is_enabled()) { if (this->current_state) {
this->current_state->process(delta); this->current_state->process(delta);
String new_state{ this->current_state->get_next_state() }; String new_state{ this->current_state->get_next_state() };
if (new_state != this->current_state->get_class()) { if (new_state != this->current_state->get_class()) {

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -7,43 +7,23 @@ script/source = "extends EnemyWretched
@export var difficulty_weight : float = 10 @export var difficulty_weight : float = 10
var is_dead := false func _on_health_status_death() -> void:
func on_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\")
$CollisionShape3D.disabled = true $CollisionShape3D.disabled = true
set_movement_direction(Vector2()) set_movement_direction(Vector2())
func _on_health_status_death() -> void:
$wretched/AnimationPlayer.play(\"death\")
get_unit().region.raise_difficulty(1.0 / difficulty_weight) get_unit().region.raise_difficulty(1.0 / difficulty_weight)
on_death.call_deferred()
is_dead = true
func _enter_tree() -> void:
if is_dead and $wretched/AnimationPlayer.current_animation != \"death\":
$wretched/AnimationPlayer.play.call_deferred(\"death\")
$wretched/AnimationPlayer.advance.call_deferred(INF)
elif is_dead:
$wretched/AnimationPlayer.play.call_deferred(\"death\")
" "
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_ng1ul"] [sub_resource type="CapsuleShape3D" id="CapsuleShape3D_ng1ul"]
radius = 0.58691406 radius = 0.26953125
[node name="EnemyWretched" type="EnemyWretched"] [node name="EnemyWretched" type="EnemyWretched"]
wall_min_slide_angle = 0.0
script = SubResource("GDScript_qot2n") script = SubResource("GDScript_qot2n")
[node name="wretched" parent="." instance=ExtResource("1_qot2n")] [node name="wretched" parent="." instance=ExtResource("1_qot2n")]
[node name="Body" parent="wretched/Character/Skeleton3D" index="0"]
gi_mode = 0
[node name="club" parent="wretched/Character/Skeleton3D" index="1"]
gi_mode = 0
[node name="Hitbox" parent="wretched/Character/Skeleton3D" index="2" node_paths=PackedStringArray("health")] [node name="Hitbox" parent="wretched/Character/Skeleton3D" index="2" node_paths=PackedStringArray("health")]
health = NodePath("../../../../HealthStatus") health = NodePath("../../../../HealthStatus")

View file

@ -12,7 +12,7 @@ config_version=5
config/name="wave_survival" config/name="wave_survival"
run/main_scene="uid://dti7d1rslmhgp" run/main_scene="uid://dti7d1rslmhgp"
config/features=PackedStringArray("4.6", "Forward Plus") config/features=PackedStringArray("4.5", "Forward Plus")
config/icon="res://icon.svg" config/icon="res://icon.svg"
[display] [display]
@ -103,10 +103,13 @@ reload={
3d_physics/layer_4="Hitbox(Player)" 3d_physics/layer_4="Hitbox(Player)"
3d_physics/layer_5="Interactables" 3d_physics/layer_5="Interactables"
[physics]
3d/physics_engine="Jolt Physics"
[rendering] [rendering]
lights_and_shadows/directional_shadow/size=8192 lights_and_shadows/directional_shadow/size=8192
lights_and_shadows/directional_shadow/soft_shadow_filter_quality=4 lights_and_shadows/directional_shadow/soft_shadow_filter_quality=4
lights_and_shadows/positional_shadow/soft_shadow_filter_quality=5 lights_and_shadows/positional_shadow/soft_shadow_filter_quality=5
global_illumination/voxel_gi/quality=1
lights_and_shadows/positional_shadow/atlas_size=8192 lights_and_shadows/positional_shadow/atlas_size=8192