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