break-utopia/modules/break_utopia/player_camera.cpp

86 lines
2.9 KiB
C++

#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<SceneTreeTimer> 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<SceneTreeTimer> 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;
}