#include "player_body.h" #include "health_status.h" #include "macros.h" #include "player_input.h" #include "weapon_base.h" #include "weapon_inventory.h" PlayerBody *PlayerBody::singleton_instance{ nullptr }; void PlayerBody::_bind_methods() { } void PlayerBody::on_child_entered(Node *node) { if (PlayerInput * input{ cast_to(node) }) { input->connect(PlayerInput::sig_movement_input, callable_mp(this, &self_type::set_movement_input)); input->connect(PlayerInput::sig_look_input, callable_mp(this, &self_type::on_look_input)); input->connect(PlayerInput::sig_jump, callable_mp(this, &self_type::on_jump_input)); input->connect(PlayerInput::sig_run, callable_mp(this, &self_type::on_run_input)); } if (WeaponInventory * inventory{ cast_to(node) }) { this->weapons = inventory; } if (HealthStatus * health{ cast_to(node) }) { this->health = health; } } void PlayerBody::physics_process(double delta) { GETSET(velocity, { Vector2 input{ this->movement_input.normalized() }; if (get_is_running()) { input.y *= this->run_speed; input.x *= this->walk_speed; } else { input *= this->walk_speed; } velocity = velocity.move_toward(Vector3{ input.y * get_global_basis().get_column(2) + input.x * get_global_basis().get_column(0) } + Vector3{ 0.f, velocity.y, 0.f }, delta * this->acceleration); velocity += get_gravity() * delta; }); move_and_slide(); } void PlayerBody::set_movement_input(Vector2 state) { this->movement_input = state; } void PlayerBody::on_look_input(Vector2 look) { rotate_y(look.x); } void PlayerBody::on_jump_input() { if (this->is_on_floor()) { GETSET(velocity, { velocity.y = this->jump_strength; }); } } void PlayerBody::on_run_input(bool run) { this->try_running = run; } void PlayerBody::_notification(int what) { if (Engine::get_singleton()->is_editor_hint()) { return; // don't run in editor } switch (what) { default: return; case NOTIFICATION_ENTER_TREE: singleton_instance = this; connect("child_entered_tree", callable_mp(this, &self_type::on_child_entered)); return; case NOTIFICATION_EXIT_TREE: singleton_instance = nullptr; return; case NOTIFICATION_READY: set_process(true); set_physics_process(true); return; case NOTIFICATION_PHYSICS_PROCESS: physics_process(get_physics_process_delta_time()); return; } } PackedStringArray PlayerBody::get_configuration_warnings() const { PackedStringArray warnings{ super_type::get_configuration_warnings() }; if (find_children("*", HealthStatus::get_class_static()).is_empty()) { warnings.push_back("This node has no health status and will cause crashes.\nConsider adding HealthStatus node as a child."); } if (find_children("*", PlayerInput::get_class_static()).is_empty()) { warnings.push_back("This node has no input dispatcher and will cause crashes.\nConsider adding a PlayerInput node as a child."); } if (find_children("*", WeaponInventory::get_class_static()).is_empty()) { warnings.push_back("This node has no inventory and will cause crashes.\nConsider adding a WeaponInventory node as a child."); } return warnings; } PlayerBody *PlayerBody::get_singleton() { return singleton_instance; } bool PlayerBody::get_is_running() const { return get_wants_to_run() && this->weapons->get_current_weapon()->allows_running(); } bool PlayerBody::get_wants_to_run() const { return this->try_running && this->movement_input.y > 0.f && this->is_on_floor(); } HealthStatus *PlayerBody::get_health() const { return this->health; }