break-utopia/modules/break_utopia/player_body.cpp
2026-01-14 22:37:53 +01:00

154 lines
4.1 KiB
C++

#include "player_body.h"
#include "break_utopia/level_status.h"
#include "break_utopia/player_camera.h"
#include "core/config/engine.h"
#include "core/input/input.h"
#include "scene/3d/camera_3d.h"
#include "scene/main/node.h"
#include "scene/main/viewport.h"
void PlayerBody::_bind_methods() {
}
void PlayerBody::physics_process(double delta) {
move_and_slide();
}
void PlayerBody::on_child_entered(Node *node) {
if (CharacterState * state{ cast_to<CharacterState>(node) }) {
if (!this->default_state) {
this->default_state = state;
}
}
}
void PlayerBody::_notification(int what) {
if (Engine::get_singleton()->is_editor_hint()) {
return;
}
switch (what) {
default:
return;
case NOTIFICATION_ENTER_TREE:
singleton = this;
set_process_unhandled_input(true);
set_physics_process(true);
if (!is_ready()) {
connect("child_entered_tree", callable_mp(this, &self_type::on_child_entered));
}
Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_CAPTURED);
return;
case NOTIFICATION_READY:
if (this->default_state) {
this->default_state->set_state_active(true);
}
return;
case NOTIFICATION_PHYSICS_PROCESS:
physics_process(get_physics_process_delta_time());
return;
case NOTIFICATION_PAUSED:
this->movement_input = {};
return;
case NOTIFICATION_EXIT_TREE:
singleton = nullptr;
return;
}
}
void PlayerBody::process_movement_input() {
this->movement_input = {
Input::get_singleton()->get_axis("move_left", "move_right"),
Input::get_singleton()->get_axis("move_forward", "move_backward")
};
this->movement_input.normalize();
}
void PlayerBody::unhandled_input(Ref<InputEvent> const &what) {
if (what->is_action("move_forward") || what->is_action("move_backward") || what->is_action("move_left") || what->is_action("move_right")) {
process_movement_input();
}
}
PlayerBody *PlayerBody::get_singleton() {
return singleton;
}
void PlayerBody::deal_damage(double damage) {
double health{ LevelStatus::get_instance()->get_player_health() };
LevelStatus::get_instance()->set_player_health(health - damage);
for (Variant var : get_children()) {
if (CharacterState * as_state{ cast_to<CharacterState>(var) }) {
if (as_state->get_state_active()) {
as_state->set_state_active(false);
}
}
}
Node *node{ get_node(NodePath("PlayerHurtState")) };
if (CharacterState * as_state{ cast_to<CharacterState>(node) }) {
as_state->set_state_active(true);
}
}
Vector3 PlayerBody::get_transformed_movement_input() const {
Basis const basis{ get_viewport()->get_camera_3d()->get_global_basis() };
Vector3 forward{ basis.get_column(2) };
Vector3 left{ basis.get_column(0) };
forward.y = left.y = 0;
return forward.normalized() * this->movement_input.y + left.normalized() * this->movement_input.x;
}
PlayerBody *PlayerBody::singleton{ nullptr };
String const CharacterState::sig_state_entered{ "state_entered" };
String const CharacterState::sig_state_exited{ "state_exited" };
void CharacterState::_bind_methods() {
ADD_SIGNAL(MethodInfo(sig_state_entered));
ADD_SIGNAL(MethodInfo(sig_state_exited));
}
void CharacterState::_notification(int what) {
if (Engine::get_singleton()->is_editor_hint()) {
return;
}
switch (what) {
default:
return;
case NOTIFICATION_ENTER_TREE:
// turn these off just in case
set_process(false);
set_physics_process(false);
set_process_input(false);
set_process_unhandled_input(false);
Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_CAPTURED);
return;
}
}
void CharacterState::switch_state(NodePath path) {
this->set_state_active(false);
stack_state(path);
}
void CharacterState::stack_state(NodePath path) {
if (CharacterState * new_state{ cast_to<CharacterState>(get_node(path)) }) {
new_state->set_state_active(true);
}
}
void CharacterState::state_entered() {}
void CharacterState::state_exited() {}
void CharacterState::set_state_active(bool active) {
if (active != this->active_state) {
if (active) {
state_entered();
emit_signal(sig_state_entered);
} else {
state_exited();
emit_signal(sig_state_exited);
}
}
this->active_state = active;
}