135 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			135 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#include "player_body.h"
 | 
						|
#include "health_status.h"
 | 
						|
#include "macros.h"
 | 
						|
#include "player_camera.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) {
 | 
						|
	node->connect("child_entered_tree", callable_mp(this, &self_type::on_child_entered));
 | 
						|
	if (PlayerInput * input{ cast_to<PlayerInput>(node) }) {
 | 
						|
		input->connect(PlayerInput::sig_movement_input, callable_mp(this, &self_type::set_movement_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<WeaponInventory>(node) }) {
 | 
						|
		this->weapons = inventory;
 | 
						|
	}
 | 
						|
	if (HealthStatus * health{ cast_to<HealthStatus>(node) }) {
 | 
						|
		this->health = health;
 | 
						|
	}
 | 
						|
	if (PlayerCamera * camera{ cast_to<PlayerCamera>(node) }) {
 | 
						|
		this->camera = camera;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void PlayerBody::process(double delta) {
 | 
						|
	float const target_fov{ get_is_running() ? 1.1f : 1.0f };
 | 
						|
	fov = Math::move_toward(fov, target_fov, float(delta * 2.0));
 | 
						|
	this->camera->set_fov_factor(fov);
 | 
						|
}
 | 
						|
 | 
						|
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;
 | 
						|
		}
 | 
						|
		Basis const basis{ this->camera->get_global_basis() };
 | 
						|
		Vector3 forward{ -basis.get_column(2) };
 | 
						|
		forward.y = 0.f;
 | 
						|
		forward.normalize();
 | 
						|
		Vector3 left{ -basis.get_column(0) };
 | 
						|
		left.y = 0.f;
 | 
						|
		left.normalize();
 | 
						|
		velocity = velocity.move_toward(Vector3{ input.y * forward + input.x * left } + 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_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_PROCESS:
 | 
						|
			process(get_process_delta_time());
 | 
						|
			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.");
 | 
						|
	}
 | 
						|
	if (find_children("*", PlayerCamera::get_class_static()).is_empty()) {
 | 
						|
		warnings.push_back("This node has no camera of type PlayerCamera, expect crashes.\nConsider adding a PlayerCamera 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;
 | 
						|
}
 | 
						|
 | 
						|
HealthStatus *PlayerBody::get_health() const {
 | 
						|
	return this->health;
 | 
						|
}
 |