break-utopia/modules/break_utopia/player_states.cpp

174 lines
4.6 KiB
C++

#include "player_states.h"
#include "scene/animation/animation_tree.h"
#include "scene/main/viewport.h"
void PlayerState::_bind_methods() {}
void PlayerState::ready() {
this->anim = cast_to<AnimationTree>(get_node(NodePath("%AnimationTree")));
this->anim_fsm = this->anim->get("parameters/playback");
}
void PlayerState::_notification(int what) {
if (Engine::get_singleton()->is_editor_hint()) {
return;
}
switch (what) {
default:
return;
case NOTIFICATION_READY:
ready();
return;
}
}
void PlayerState::apply_root_motion(double delta) {
PlayerBody *body{ get_body() };
Basis basis{ body->get_global_basis() };
Vector3 root_motion{ this->anim->get_root_motion_position() };
body->set_velocity((root_motion.x * basis.get_column(0) + root_motion.z * basis.get_column(2)) / delta);
}
void PlayerState::input_trigger_entry_actions(Ref<InputEvent> const &what) {
if (what->is_action_pressed("light_attack")) {
switch_state("LightAttack");
}
}
void PlayerIdleState::_bind_methods() {}
void PlayerIdleState::_notification(int what) {
if (Engine::get_singleton()->is_editor_hint()) {
return;
}
switch (what) {
default:
return;
case NOTIFICATION_PROCESS:
get_body()->set_velocity(get_body()->get_velocity().move_toward(Vector3(), get_process_delta_time() * 50.f));
return;
}
}
void PlayerIdleState::state_entered() {
set_process_unhandled_input(true);
set_process(true);
get_anim_fsm()->travel("idle");
}
void PlayerIdleState::state_exited() {
set_process_unhandled_input(false);
set_process(false);
}
void PlayerIdleState::unhandled_input(Ref<InputEvent> const &what) {
if (what->is_action("move_left") || what->is_action("move_right") || what->is_action("move_forward") || what->is_action("move_backward")) {
switch_state<PlayerRunState>();
} else {
input_trigger_entry_actions(what);
}
}
void PlayerRunState::_bind_methods() {
}
void PlayerRunState::process(double delta) {
apply_root_motion(delta);
if (get_body()->get_transformed_movement_input().is_zero_approx()) {
switch_state<PlayerIdleState>();
} else {
double angle{ get_body()->get_basis().get_column(2).signed_angle_to(get_body()->get_transformed_movement_input(), { 0.f, 1.f, 0.f }) };
get_body()->rotate_y(angle * delta * 5.f);
}
}
void PlayerRunState::_notification(int what) {
if (Engine::get_singleton()->is_editor_hint()) {
return;
}
switch (what) {
default:
return;
case NOTIFICATION_PROCESS:
process(get_process_delta_time());
return;
}
}
void PlayerRunState::unhandled_input(Ref<InputEvent> const &what) {
input_trigger_entry_actions(what);
}
void PlayerRunState::state_entered() {
set_process(true);
get_anim_fsm()->travel("run");
}
void PlayerRunState::state_exited() {
set_process(false);
}
void PlayerBasicAttackState::_bind_methods() {
BIND_PROPERTY(Variant::STRING, animation_name);
BIND_HPROPERTY(Variant::NODE_PATH, next_light_attack_state, PROPERTY_HINT_NODE_PATH_VALID_TYPES, "CharacterState");
BIND_PROPERTY(Variant::FLOAT, trigger_next_margin);
BIND_PROPERTY(Variant::FLOAT, input_next_margin);
}
void PlayerBasicAttackState::process(double delta) {
apply_root_motion(delta);
if (!this->animation_started) {
if (get_anim_fsm()->get_current_node() == this->animation_name) {
this->animation_started = true;
this->anim_length = get_anim_fsm()->get_current_length();
} else {
return;
}
}
delta_since_start += delta;
float const trigger_next_progress{ this->anim_length - this->trigger_next_margin };
if (this->next_queued && this->delta_since_start > trigger_next_progress && !this->next_light_attack_state.is_empty()) {
switch_state(this->next_light_attack_state);
}
if (get_anim_fsm()->get_current_node() != this->animation_name) {
switch_state<PlayerIdleState>();
}
}
void PlayerBasicAttackState::_notification(int what) {
if (Engine::get_singleton()->is_editor_hint()) {
return;
}
switch (what) {
default:
return;
case NOTIFICATION_PROCESS:
process(get_process_delta_time());
return;
}
}
void PlayerBasicAttackState::unhandled_input(Ref<InputEvent> const &what) {
float const input_next_progress{ get_anim_fsm()->get_current_length() - this->input_next_margin };
if (this->delta_since_start > input_next_progress && what->is_action_pressed("light_attack")) {
this->next_queued = true;
get_viewport()->set_input_as_handled();
}
}
void PlayerBasicAttackState::state_entered() {
set_process(true);
set_process_unhandled_input(true);
this->next_queued = false;
this->animation_started = false;
this->delta_since_start = 0.0;
get_anim_fsm()->start(this->animation_name);
}
void PlayerBasicAttackState::state_exited() {
set_process(false);
set_process_unhandled_input(false);
}