diff --git a/modules/break_utopia/player_camera.cpp b/modules/break_utopia/player_camera.cpp index 2904a1e1..922cb43e 100644 --- a/modules/break_utopia/player_camera.cpp +++ b/modules/break_utopia/player_camera.cpp @@ -1,5 +1,6 @@ #include "player_camera.h" #include "core/config/engine.h" +#include "core/math/math_funcs.h" #include "scene/main/node.h" #include "scene/main/scene_tree.h" @@ -8,13 +9,36 @@ PlayerCamera *PlayerCamera::instance{ nullptr }; void PlayerCamera::_bind_methods() { ClassDB::bind_static_method(get_class_static(), "get_instance", &self_type::get_instance); ClassDB::bind_method(D_METHOD("impact_effect", "color", "freeze_time", "zoom", "shake_intensity"), &self_type::impact_effect); + BIND_PROPERTY(Variant::FLOAT, max_shake); } void PlayerCamera::end_effect() { + --this->active_effects; + if (this->active_effects > 0) { + this->active_shake -= this->active_shake / float(this->active_effects); + this->active_shake = this->active_shake > 0.f ? this->active_shake : 0.f; + return; + } if (this->active_environment.is_valid()) { this->active_environment->set_ambient_light_color(this->ambient_light_color); } Engine::get_singleton()->set_time_scale(1.0); + set_process(false); + set_global_position(get_global_position() - this->shake_offset); + this->shake_offset = {}; +} + +void PlayerCamera::process(double delta) { + shake_interval -= delta / Engine::get_singleton()->get_time_scale(); + if (shake_interval < 0.0) { + shake_interval = 0.001; + Vector3 new_offset{ 0, this->active_shake < 0.5f ? this->active_shake : 0.5f, 0 }; + new_offset.rotate({ 0, 0, 1 }, Math::random(0.0, Math::PI)); + Vector3 new_location{ get_global_position() - this->shake_offset }; + Basis const basis{ get_global_basis() }; + new_location += (this->shake_offset = basis.get_column(0) * new_offset.x + basis.get_column(1) * new_offset.y); + set_global_position(new_location); + } } void PlayerCamera::_notification(int what) { @@ -27,17 +51,20 @@ void PlayerCamera::_notification(int what) { case NOTIFICATION_ENTER_TREE: instance = this; return; - case NOTIFICATION_EXIT_TREE: - if (instance == this) { - instance = nullptr; - } - return; case NOTIFICATION_READY: this->active_environment = get_world_3d()->get_environment(); if (this->active_environment.is_valid()) { this->ambient_light_color = this->active_environment->get_ambient_light_color(); } return; + case NOTIFICATION_PROCESS: + process(get_process_delta_time()); + return; + case NOTIFICATION_EXIT_TREE: + if (instance == this) { + instance = nullptr; + } + return; } } @@ -47,8 +74,11 @@ PlayerCamera *PlayerCamera::get_instance() { Ref PlayerCamera::impact_effect(Color color, float freeze_time, float zoom, float shake_intensity) { this->active_environment->set_ambient_light_color(color); - Engine::get_singleton()->set_time_scale(0.00001); + Engine::get_singleton()->set_time_scale(0.000001); Ref timer{ get_tree()->create_timer(freeze_time, true, false, true) }; timer->connect("timeout", callable_mp(this, &self_type::end_effect)); + this->active_shake += shake_intensity; + ++this->active_effects; + set_process(true); return timer; } diff --git a/modules/break_utopia/player_camera.h b/modules/break_utopia/player_camera.h index 3434c198..5450c09b 100644 --- a/modules/break_utopia/player_camera.h +++ b/modules/break_utopia/player_camera.h @@ -1,12 +1,15 @@ #pragma once #include "core/math/color.h" +#include "macros.h" #include "scene/3d/camera_3d.h" #include "scene/resources/environment.h" + class PlayerCamera : public Camera3D { GDCLASS(PlayerCamera, Camera3D); static void _bind_methods(); void end_effect(); + void process(double delta); protected: void _notification(int what); @@ -16,7 +19,17 @@ public: Ref impact_effect(Color color, float freeze_time = 0.1, float zoom = 1.f, float shake_intensity = 2.f); private: + static PlayerCamera *instance; + Color ambient_light_color{}; Ref active_environment{}; - static PlayerCamera *instance; + float max_shake{ 1.f }; + + int active_effects{ 0 }; + float active_shake{}; + Vector3 shake_offset{}; + double shake_interval{ 0.001 }; + +public: + GET_SET_FNS(float, max_shake); }; diff --git a/project/objects/effects/destroyed_object.tscn b/project/objects/effects/destroyed_object.tscn index 54208b00..d45c66e1 100644 --- a/project/objects/effects/destroyed_object.tscn +++ b/project/objects/effects/destroyed_object.tscn @@ -12,7 +12,7 @@ func _ready(): $ImpactFlash2.restart() func freeze_frame(): - await PlayerCamera.get_instance().impact_effect($DustCloud.process_material.color, 0.1, 0.0, 0.0).timeout + await PlayerCamera.get_instance().impact_effect($DustCloud.process_material.color, 0.1, 0.0, 0.5).timeout $DustCloud.restart.call_deferred() " diff --git a/project/objects/effects/dustcloud.tscn b/project/objects/effects/dustcloud.tscn index d4a192c9..19d79f60 100644 --- a/project/objects/effects/dustcloud.tscn +++ b/project/objects/effects/dustcloud.tscn @@ -5,7 +5,7 @@ [sub_resource type="CurveTexture" id="CurveTexture_m6khk"] [sub_resource type="Curve" id="Curve_m6khk"] -_data = [Vector2(0, 0.0391372), 0.0, 0.876395, 0, 0, Vector2(0.847203, 1), 0.178372, 0.178372, 0, 0, Vector2(1, 0.0232278), -10.3023, 0.0, 0, 0] +_data = [Vector2(0, 0), 0.0, 2.17614, 0, 0, Vector2(0.546074, 1), -0.130662, -0.130662, 0, 0, Vector2(1, 0.0232278), -2.0867, 0.0, 0, 0] point_count = 3 [sub_resource type="CurveTexture" id="CurveTexture_ulfqf"] @@ -44,7 +44,7 @@ center_offset = Vector3(0, 0, 0.04) [node name="DustCloud" type="GPUParticles3D"] emitting = false amount = 25 -lifetime = 0.2 +lifetime = 0.3 one_shot = true explosiveness = 0.89 randomness = 1.0 diff --git a/project/objects/effects/impact_decal.tscn b/project/objects/effects/impact_decal.tscn index ef856a19..a2b62e0f 100644 --- a/project/objects/effects/impact_decal.tscn +++ b/project/objects/effects/impact_decal.tscn @@ -16,7 +16,7 @@ func _ready(): $ImpactFlash2.restart() func freeze_frame(): - await PlayerCamera.get_instance().impact_effect($ImpactFlash2.process_material.color, 0.15, 0.0, 0.0).timeout + await PlayerCamera.get_instance().impact_effect($ImpactFlash2.process_material.color, 0.15, 0.0, 1.0).timeout $DustCloud.restart() $ImpactFlash.queue_free() $ImpactFlash2.queue_free()