#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" 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); } get_tree()->set_pause(false); set_process(false); set_global_position(get_global_position() - this->shake_offset); this->shake_offset = {}; this->active_environment->set_ambient_light_energy(1.f); } void PlayerCamera::process(double delta) { this->shake_interval -= delta / Engine::get_singleton()->get_time_scale(); if (this->shake_interval < 0.0) { this->shake_interval = 0.03; Vector3 const new_location{ get_position() - this->shake_offset }; Vector3 const new_offset{ Vector3{ 0, this->active_shake < 0.5f ? this->active_shake : 0.5f, 0 }.rotated({ 0, 0, 1 }, Math::random(0.0, Math::PI)) }; Basis const basis{ get_basis() }; set_position(new_location + (this->shake_offset = basis.get_column(0) * new_offset.x + basis.get_column(1) * new_offset.y)); } } void PlayerCamera::_notification(int what) { if (Engine::get_singleton()->is_editor_hint()) { return; } switch (what) { default: return; case NOTIFICATION_ENTER_TREE: set_process_mode(ProcessMode::PROCESS_MODE_ALWAYS); instance = this; 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; } } PlayerCamera *PlayerCamera::get_instance() { return instance; } Ref PlayerCamera::impact_effect(Color color, float freeze_time, float zoom, float shake_intensity) { this->active_environment->set_ambient_light_color(color); this->active_environment->set_ambient_light_energy(1.f); Ref timer{ get_tree()->create_timer(freeze_time, true, false, true) }; timer->set_process_always(true); timer->connect("timeout", callable_mp(this, &self_type::end_effect)); this->active_shake += shake_intensity; ++this->active_effects; get_tree()->set_pause(true); set_process(true); return timer; }