feat: implemented camera shake
This commit is contained in:
parent
d01652bb2a
commit
7b2663cbc2
5 changed files with 54 additions and 11 deletions
|
|
@ -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<SceneTreeTimer> 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<SceneTreeTimer> 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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<SceneTreeTimer> 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<Environment> 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);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
"
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue