From 36c7f87dc04aa045d8b6148dce157d108ca635fc Mon Sep 17 00:00:00 2001 From: Jamie Greunbaum Date: Sun, 13 Sep 2026 00:02:40 -0400 Subject: [PATCH] - Hurtboxes now create their own collision shape nodes automatically. - Character3D prevent crashes on _ready by checking for a valid skeleton. - Fixed deadzone reading as cleared for all axes when only one has done so. - Singletons once again deregistered, since it seems to now cause less crashes. - PlayerSpawn now uses the new error-printing macro. --- .../nodes/character_nodes/character_3d.cpp | 34 +++++++++++------ src/liborng/nodes/hurtbox/hurtbox_base.cpp | 38 ++++++++++++++++--- src/liborng/nodes/hurtbox/hurtbox_base.h | 10 +++-- src/liborng/register_types.cpp | 6 +-- src/liborng/resources/input_resource.cpp | 12 ++++-- 5 files changed, 74 insertions(+), 26 deletions(-) diff --git a/src/liborng/nodes/character_nodes/character_3d.cpp b/src/liborng/nodes/character_nodes/character_3d.cpp index 7cae688..4184b1d 100644 --- a/src/liborng/nodes/character_nodes/character_3d.cpp +++ b/src/liborng/nodes/character_nodes/character_3d.cpp @@ -20,15 +20,24 @@ using namespace godot; void Character3D::_ready() { - TypedArray child_mesh_candidates = this->skeleton->get_children(); - const uint32_t num_children = child_mesh_candidates.size(); - for (uint32_t i = 0; i < num_children; i++) + if (this->skeleton) { - if (MeshInstance3D *mesh = cast_to(child_mesh_candidates[i])) + TypedArray child_mesh_candidates = this->skeleton->get_children(); + const uint32_t num_children = child_mesh_candidates.size(); + for (uint32_t i = 0; i < num_children; i++) { - this->meshes.emplace_back(mesh); + if (MeshInstance3D *mesh = cast_to(child_mesh_candidates[i])) + { + this->meshes.emplace_back(mesh); + } } } +#ifdef DEBUG_ENABLED + else + { + PRINT_ERROR(CHARACTER3D_TAG, "No skeleton has been set, and there is currently no way to seek one out in the hierarchy. This will be a problem."); + } +#endif // DEBUG_ENABLED } @@ -55,16 +64,19 @@ void Character3D::take_damage(const Dictionary &hit_data) void Character3D::_activate_ragdoll() { - const TypedArray &physical_bones = this->physical_bone_simulator->get_children(); - const uint32_t num_physical_bones = physical_bones.size(); - for (uint32_t i = 0; i < num_physical_bones; i++) + if (this->physical_bone_simulator) { - if (PhysicalBone3D *bone = cast_to(physical_bones[i])) + const TypedArray &physical_bones = this->physical_bone_simulator->get_children(); + const uint32_t num_physical_bones = physical_bones.size(); + for (uint32_t i = 0; i < num_physical_bones; i++) { - bone->set_collision_layer(0); + if (PhysicalBone3D *bone = cast_to(physical_bones[i])) + { + bone->set_collision_layer(0); + } } + this->physical_bone_simulator->physical_bones_start_simulation(); } - this->physical_bone_simulator->physical_bones_start_simulation(); } diff --git a/src/liborng/nodes/hurtbox/hurtbox_base.cpp b/src/liborng/nodes/hurtbox/hurtbox_base.cpp index fa5329c..906955f 100644 --- a/src/liborng/nodes/hurtbox/hurtbox_base.cpp +++ b/src/liborng/nodes/hurtbox/hurtbox_base.cpp @@ -10,6 +10,7 @@ #include "character_3d.h" +#include #include #include #include @@ -17,8 +18,35 @@ using namespace godot; +void HurtboxBase::_enter_tree() +{ + if (!this->collision_shape) + { + this->collision_shape = memnew(CollisionShape3D); + this->collision_shape->set_shape(this->shape); + this->add_child(this->collision_shape); + } + + Area3D::_enter_tree(); +} + +void HurtboxBase::_exit_tree() +{ + if (this->collision_shape) + { + this->collision_shape->set_shape(this->shape); + this->remove_child(this->collision_shape); + this->collision_shape->queue_free(); + } + + Area3D::_exit_tree(); +} + void HurtboxBase::_ready() { +#ifdef DEBUG_ENABLED + if(Engine::get_singleton()->is_editor_hint()) { this->set_physics_process(false); return; } +#endif // DEBUG_ENABLED this->set_process(false); this->remaining_life = this->lifetime; @@ -27,11 +55,6 @@ void HurtboxBase::_ready() void HurtboxBase::_physics_process(double delta) { - if (this->remaining_life <= 0.0f) - { - this->collision_shape->set_disabled(true); - } - TypedArray characters_hit_this_frame; const TypedArray &bodies = this->get_overlapping_bodies(); @@ -73,7 +96,10 @@ void HurtboxBase::_physics_process(double delta) this->hit_character_bodies.append_array(characters_hit_this_frame); - this->remaining_life -= delta; + if (this->remaining_life <= 0.0f) + this->collision_shape->set_disabled(true); + else + this->remaining_life -= delta; } void HurtboxBase::_send_next_in_queue() diff --git a/src/liborng/nodes/hurtbox/hurtbox_base.h b/src/liborng/nodes/hurtbox/hurtbox_base.h index be6f4f4..fb371f2 100644 --- a/src/liborng/nodes/hurtbox/hurtbox_base.h +++ b/src/liborng/nodes/hurtbox/hurtbox_base.h @@ -12,6 +12,7 @@ #include "character_3d.h" #include +#include #include using namespace godot; @@ -23,11 +24,13 @@ class HurtboxBase : public Area3D GDCLASS(HurtboxBase, Area3D); public: + virtual void _enter_tree() override; + virtual void _exit_tree() override; virtual void _ready() override; virtual void _physics_process(double delta) override; - void set_collision_shape(CollisionShape3D *cs) { this->collision_shape = cs; } - CollisionShape3D *get_collision_shape() const { return this->collision_shape; } + void set_shape(Ref s) { this->shape = s; } + Ref get_shape() const { return this->shape; } void set_lifetime(const float lt) { this->lifetime = lt; } float get_lifetime() const { return this->lifetime; } @@ -42,6 +45,7 @@ private: Dictionary _create_hit_data_struct() const; void _send_next_in_queue(); + Ref shape = nullptr; CollisionShape3D *collision_shape = nullptr; float lifetime = 0.05f; @@ -55,7 +59,7 @@ private: protected: static void _bind_methods() { - ADD_GETTER_SETTER_HINTED(HurtboxBase, collision_shape, Variant::OBJECT, PROPERTY_HINT_NODE_TYPE, "CollisionShape3D"); + ADD_GETTER_SETTER_HINTED(HurtboxBase, shape, Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "Shape3D"); ADD_GETTER_SETTER(HurtboxBase, lifetime, Variant::FLOAT); ADD_GETTER_SETTER(HurtboxBase, hit_points, Variant::INT); diff --git a/src/liborng/register_types.cpp b/src/liborng/register_types.cpp index df383ab..5adf30d 100644 --- a/src/liborng/register_types.cpp +++ b/src/liborng/register_types.cpp @@ -88,9 +88,9 @@ void uninitialize_orng_module(ModuleInitializationLevel p_level) { if (p_level == ModuleInitializationLevel::MODULE_INITIALIZATION_LEVEL_SCENE) { // GDSINGLETON_UNREGISTER_CLASS(_vendor_service_singleton); - // GDSINGLETON_UNREGISTER_CLASS(_scene_loader_singleton); - // GDSINGLETON_UNREGISTER_CLASS(_save_manager_singleton); - // GDSINGLETON_UNREGISTER_CLASS(_input_handler_singleton); + GDSINGLETON_UNREGISTER_CLASS(_scene_loader_singleton); + GDSINGLETON_UNREGISTER_CLASS(_save_manager_singleton); + GDSINGLETON_UNREGISTER_CLASS(_input_handler_singleton); } } diff --git a/src/liborng/resources/input_resource.cpp b/src/liborng/resources/input_resource.cpp index bb815fc..50ccf75 100644 --- a/src/liborng/resources/input_resource.cpp +++ b/src/liborng/resources/input_resource.cpp @@ -55,7 +55,8 @@ void InputResource::update_axes(const float delta) const StringName &signal_1d = prefix + INPUTAXIS_ONE_DIMENSIONAL_SUFFIX + INPUTHANDLER_SUFFIX_SIGNAL; if (this->has_signal(signal_1d)) { - const float x_axis = axis->get_x_axis(); + float x_axis = axis->get_x_axis(); + if (UtilityFunctions::absf(x_axis) < axis_deadzone) x_axis = 0.0f; if (current_input.x != x_axis || current_input.length() > SMALL_NUMBER) this->emit_signal(signal_1d, delta, x_axis); current_input.x = x_axis; @@ -64,7 +65,9 @@ void InputResource::update_axes(const float delta) const StringName &signal_2d = prefix + INPUTAXIS_TWO_DIMENSIONAL_SUFFIX + INPUTHANDLER_SUFFIX_SIGNAL; if (this->has_signal(signal_2d)) { - const Vector2 &vector = axis->get_lateral_vector(); + Vector2 &vector = axis->get_lateral_vector(); + if (UtilityFunctions::absf(vector.x) < axis_deadzone) vector.x = 0.0f; + if (UtilityFunctions::absf(vector.y) < axis_deadzone) vector.y = 0.0f; if ((current_input.x != vector.x || current_input.z != vector.y) || current_input.length() > SMALL_NUMBER) this->emit_signal(signal_2d, delta, vector); current_input.x = vector.x; current_input.z = vector.y; @@ -73,7 +76,10 @@ void InputResource::update_axes(const float delta) const StringName &signal_3d = prefix + INPUTAXIS_THREE_DIMENSIONAL_SUFFIX + INPUTHANDLER_SUFFIX_SIGNAL; if (this->has_signal(signal_3d)) { - const Vector3 &vector = axis->get_spherical_vector(); + Vector3 &vector = axis->get_spherical_vector(); + if (UtilityFunctions::absf(vector.x) < axis_deadzone) vector.x = 0.0f; + if (UtilityFunctions::absf(vector.y) < axis_deadzone) vector.y = 0.0f; + if (UtilityFunctions::absf(vector.z) < axis_deadzone) vector.z = 0.0f; if (current_input != vector || current_input.length() > SMALL_NUMBER) this->emit_signal(signal_3d, delta, vector); current_input = vector;