feat: added running
This commit is contained in:
parent
95375eae4a
commit
32df02855b
25 changed files with 2170 additions and 71 deletions
|
|
@ -6,18 +6,17 @@
|
|||
void Player::_bind_methods() {
|
||||
#define CLASSNAME Player
|
||||
GDFUNCTION(get_input_directions);
|
||||
GDFUNCTION(get_input_fire);
|
||||
}
|
||||
|
||||
void Player::_ready() {
|
||||
if(gd::Engine::get_singleton()->is_editor_hint())
|
||||
return;
|
||||
this->anim_tree = this->get_node<gd::AnimationTree>("%AnimationTree");
|
||||
this->fsm = gd::Object::cast_to<gd::AnimationNodeStateMachinePlayback>(this->anim_tree->get("parameters/Actions/playback"));
|
||||
this->anim_tree = this->get_node<PlayerAnimTree>("%AnimationTree");
|
||||
this->input = this->get_node<utils::PlayerInput>("%PlayerInput");
|
||||
this->input->listen_to(utils::PlayerInput::Listener("dir_left", "dir_right", callable_mp(this, &Player::_on_dir_horizontal)));
|
||||
this->input->listen_to(utils::PlayerInput::Listener("dir_backward", "dir_forward", callable_mp(this, &Player::_on_dir_vertical)));
|
||||
this->input->listen_to(utils::PlayerInput::Listener("fire", callable_mp(this, &Player::_on_fire)));
|
||||
this->input->listen_to(utils::PlayerInput::Listener("run", callable_mp(this, &Player::_on_run)));
|
||||
this->model_node = this->get_node<gd::Node3D>("%CharacterModel");
|
||||
this->camera_parent = this->get_node<gd::Node3D>("%CameraParent");
|
||||
this->camera_parent->set_global_rotation(this->get_global_rotation());
|
||||
|
|
@ -30,41 +29,43 @@ void Player::_process(double delta) {
|
|||
this->input_fire -= delta;
|
||||
this->process_rotate(delta);
|
||||
this->process_transform_camera(delta);
|
||||
}
|
||||
|
||||
void Player::_physics_process(double delta [[maybe_unused]]) {
|
||||
if(gd::Engine::get_singleton()->is_editor_hint())
|
||||
return;
|
||||
// calculate the motion based on model-space motion and global basis
|
||||
gd::Basis const &model_basis{this->model_node->get_global_basis()};
|
||||
this->anim_tree->set_walk_speed(gd::Math::max(0.f, model_basis.get_column(2).dot(this->camera_parent->get_basis().get_column(2))));
|
||||
gd::Vector3 const local_motion{this->anim_tree->get_root_motion_position()};
|
||||
gd::Vector3 const motion {
|
||||
local_motion.x * model_basis.get_column(0) +
|
||||
local_motion.y * model_basis.get_column(1) +
|
||||
local_motion.z * model_basis.get_column(2) +
|
||||
(this->is_on_floor() ? gd::Vector3{} : gd::Vector3{0.f, -1.f, 0.f})
|
||||
(this->is_on_floor() ? gd::Vector3{} : gd::Vector3{0.f, -1.f, 0.f}) // add some gravity if required
|
||||
};
|
||||
// set velocity and move
|
||||
this->set_velocity(motion / delta);
|
||||
}
|
||||
|
||||
void Player::_physics_process(double delta [[maybe_unused]]) {
|
||||
if(gd::Engine::get_singleton()->is_editor_hint())
|
||||
return;
|
||||
this->move_and_slide();
|
||||
}
|
||||
|
||||
void Player::process_transform_camera(double delta) {
|
||||
this->camera_parent->set_global_position(this->get_global_position());
|
||||
float const camera_speed{float(delta) * (this->fsm->get_current_node().contains("[aim]") ? this->AIMING_CAMERA_ROTATION_SPEED : this->CAMERA_ROTATION_SPEED)};
|
||||
float const camera_speed{float(delta) * (this->anim_tree->match_tags(PlayerAnimTree::Aim) ? this->AIMING_CAMERA_ROTATION_SPEED : this->CAMERA_ROTATION_SPEED)};
|
||||
this->camera_parent->rotate_y(this->input_directions.x * -camera_speed);
|
||||
}
|
||||
|
||||
void Player::process_rotate(double delta) {
|
||||
if(this->fsm->get_current_node().contains("[turn")) {
|
||||
if(this->anim_tree->match_tags(PlayerAnimTree::Tags::Turn)) {
|
||||
//! the signed angle difference between the left axes of the camera parent and Player
|
||||
float const diff = -this->camera_parent->get_global_basis().get_column(0).signed_angle_to(this->get_global_basis().get_column(0), {0.f, 1.f, 0.f});
|
||||
float const diff{-this->camera_parent->get_global_basis().get_column(0).signed_angle_to(this->get_global_basis().get_column(0), {0.f, 1.f, 0.f})};
|
||||
float const dir{gd::Math::sign(diff)};
|
||||
//! the maximum rotation to allow for this frame
|
||||
float const speed{float(delta) * this->ROTATION_SPEED};
|
||||
float const actual_speed{speed < gd::Math::abs(diff) ? gd::Math::sign(diff) * speed : diff};
|
||||
float const actual_speed{speed < gd::Math::abs(diff) ? dir * speed : diff};
|
||||
// rotate by max allowed or full difference, whichever has the smaller magnitude
|
||||
this->rotate_y(actual_speed);
|
||||
this->anim_tree->set("parameters/Actions/Stationary [turn]/Turn/blend_position", diff * M_PI_2f);
|
||||
} else {
|
||||
this->anim_tree->set("parameters/Actions/Stationary [turn_animated]/blend_position", 0.f);
|
||||
this->anim_tree->set_target_turn_speed(gd::Math::clamp(diff * 2.f, -1.f, 1.f) * M_PI_2f *0.9f);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -74,20 +75,20 @@ void Player::_on_dir_horizontal(gd::Ref<gd::InputEvent>, float value) {
|
|||
|
||||
void Player::_on_dir_vertical(gd::Ref<gd::InputEvent>, float value) {
|
||||
this->input_directions.y = value;
|
||||
this->anim_tree->set_aim_weapon(value <= -0.9f);
|
||||
this->anim_tree->set_is_walking(value > 0.5f);
|
||||
}
|
||||
|
||||
void Player::_on_fire(gd::Ref<gd::InputEvent>, float value) {
|
||||
if(value > 0.f) {
|
||||
this->input_fire = 0.5;
|
||||
}
|
||||
void Player::_on_fire(gd::Ref<gd::InputEvent> event, float) {
|
||||
if(event->is_pressed())
|
||||
this->anim_tree->set_fire_weapon();
|
||||
}
|
||||
|
||||
void Player::_on_run(gd::Ref<gd::InputEvent> event, float) {
|
||||
if(event->is_pressed())
|
||||
this->anim_tree->set_is_running();
|
||||
}
|
||||
|
||||
gd::Vector2 Player::get_input_directions() const {
|
||||
return this->input_directions;
|
||||
}
|
||||
|
||||
bool Player::get_input_fire() {
|
||||
bool const val = this->input_fire > 0.0;
|
||||
this->input_fire = 0.0;
|
||||
return val;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#define TR_PLAYER_HPP
|
||||
|
||||
#include "utils/player_input.hpp"
|
||||
#include <godot_cpp/classes/animation_tree.hpp>
|
||||
#include "player_anim_tree.hpp"
|
||||
#include <godot_cpp/classes/character_body3d.hpp>
|
||||
#include <godot_cpp/classes/animation_node_state_machine_playback.hpp>
|
||||
namespace gd = godot;
|
||||
|
|
@ -20,20 +20,19 @@ public:
|
|||
|
||||
void _on_dir_horizontal(gd::Ref<gd::InputEvent>, float value);
|
||||
void _on_dir_vertical(gd::Ref<gd::InputEvent>, float value);
|
||||
void _on_fire(gd::Ref<gd::InputEvent>, float value);
|
||||
void _on_fire(gd::Ref<gd::InputEvent> event, float);
|
||||
void _on_run(gd::Ref<gd::InputEvent> event, float);
|
||||
|
||||
gd::Vector2 get_input_directions() const;
|
||||
bool get_input_fire();
|
||||
private:
|
||||
gd::AnimationTree *anim_tree{nullptr};
|
||||
gd::AnimationNodeStateMachinePlayback *fsm{nullptr};
|
||||
PlayerAnimTree *anim_tree{nullptr};
|
||||
gd::Node3D *camera_parent{nullptr};
|
||||
utils::PlayerInput *input{nullptr};
|
||||
gd::Node3D *model_node{nullptr};
|
||||
gd::Vector2 input_directions{0.f, 0.f};
|
||||
double input_fire{0.0};
|
||||
|
||||
float const ROTATION_SPEED{1.5f};
|
||||
float const ROTATION_SPEED{1.8f};
|
||||
float const CAMERA_ROTATION_SPEED{2.f};
|
||||
float const AIMING_CAMERA_ROTATION_SPEED{1.f};
|
||||
};
|
||||
|
|
|
|||
102
src/player_anim_tree.cpp
Normal file
102
src/player_anim_tree.cpp
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
#include "player_anim_tree.hpp"
|
||||
#include "utils/godot_macros.hpp"
|
||||
#include <godot_cpp/variant/utility_functions.hpp>
|
||||
|
||||
void PlayerAnimTree::_bind_methods() {
|
||||
#define CLASSNAME PlayerAnimTree
|
||||
GDPROPERTY(target_turn_speed, gd::Variant::FLOAT);
|
||||
GDPROPERTY(is_walking, gd::Variant::FLOAT);
|
||||
GDPROPERTY(walk_speed, gd::Variant::FLOAT);
|
||||
GDFUNCTION(get_is_running);
|
||||
GDPROPERTY(aim_weapon, gd::Variant::BOOL);
|
||||
GDFUNCTION(get_fire_weapon);
|
||||
}
|
||||
|
||||
void PlayerAnimTree::_ready() {
|
||||
this->fsm = this->get("parameters/Actions/playback");
|
||||
}
|
||||
|
||||
void PlayerAnimTree::_process(double delta) {
|
||||
if(gd::Engine::get_singleton()->is_editor_hint())
|
||||
return;
|
||||
this->turn_speed = gd::Math::move_toward(this->turn_speed, this->target_turn_speed, float(delta * 30.));
|
||||
this->commit_turn_speed();
|
||||
this->update_tags(this->fsm->get_current_node());
|
||||
this->fire_weapon -= delta;
|
||||
this->running_time -= delta;
|
||||
}
|
||||
|
||||
void PlayerAnimTree::set_target_turn_speed(float value) {
|
||||
this->target_turn_speed = value;
|
||||
}
|
||||
|
||||
float PlayerAnimTree::get_target_turn_speed() const {
|
||||
return this->target_turn_speed;
|
||||
}
|
||||
|
||||
void PlayerAnimTree::set_is_walking(bool value) {
|
||||
this->is_walking = value;
|
||||
}
|
||||
|
||||
bool PlayerAnimTree::get_is_walking() const {
|
||||
return this->is_walking;
|
||||
}
|
||||
|
||||
void PlayerAnimTree::set_walk_speed(float value) {
|
||||
this->walk_speed = value;
|
||||
this->commit_walk_speed();
|
||||
}
|
||||
|
||||
float PlayerAnimTree::get_walk_speed() const {
|
||||
return this->walk_speed;
|
||||
}
|
||||
|
||||
void PlayerAnimTree::set_is_running() {
|
||||
this->running_time = 0.25;
|
||||
}
|
||||
|
||||
bool PlayerAnimTree::get_is_running() const {
|
||||
return this->running_time > 0.0;
|
||||
}
|
||||
|
||||
void PlayerAnimTree::set_aim_weapon(bool value) {
|
||||
this->aim_weapon = value;
|
||||
}
|
||||
|
||||
bool PlayerAnimTree::get_aim_weapon() const {
|
||||
return this->aim_weapon;
|
||||
}
|
||||
|
||||
void PlayerAnimTree::set_fire_weapon() {
|
||||
this->fire_weapon = 0.5f;
|
||||
}
|
||||
|
||||
bool PlayerAnimTree::get_fire_weapon() {
|
||||
bool const is_set = this->fire_weapon > 0.f;
|
||||
this->fire_weapon = 0.f;
|
||||
return is_set;
|
||||
}
|
||||
|
||||
bool PlayerAnimTree::match_tags(Tags tags) const {
|
||||
return (this->current_tags & tags) != Tags::None;
|
||||
}
|
||||
|
||||
void PlayerAnimTree::update_tags(gd::StringName const &anim) {
|
||||
if(anim != this->last_known_anim && this->fsm->get_travel_path().size() <= 1) {
|
||||
this->last_known_anim = anim;
|
||||
this->current_tags = Tags::None;
|
||||
if(anim.contains("[turn]"))
|
||||
this->current_tags = Tags(this->current_tags | Tags::Turn);
|
||||
if(anim.contains("[aim]"))
|
||||
this->current_tags = Tags(this->current_tags | Tags::Aim);
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerAnimTree::commit_turn_speed() {
|
||||
this->set("parameters/Actions/Stationary [turn]/Turn/blend_position", this->turn_speed);
|
||||
}
|
||||
|
||||
void PlayerAnimTree::commit_walk_speed() {
|
||||
this->set("parameters/Actions/Walk [turn]/Speed/blend_amount", this->walk_speed);
|
||||
this->set("parameters/Actions/Run/Speed/blend_amount", this->walk_speed);
|
||||
}
|
||||
52
src/player_anim_tree.hpp
Normal file
52
src/player_anim_tree.hpp
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
#ifndef PLAYER_ANIM_TREE_HPP
|
||||
#define PLAYER_ANIM_TREE_HPP
|
||||
|
||||
#include "utils/godot_macros.hpp"
|
||||
#include <godot_cpp/classes/animation_tree.hpp>
|
||||
#include <godot_cpp/classes/animation_node_state_machine_playback.hpp>
|
||||
namespace gd = godot;
|
||||
|
||||
class PlayerAnimTree : public gd::AnimationTree {
|
||||
GDCLASS(PlayerAnimTree, gd::AnimationTree);
|
||||
static void _bind_methods();
|
||||
public:
|
||||
enum Tags : unsigned {
|
||||
None = 0x0,
|
||||
Turn = 0x1,
|
||||
Aim = 0x2
|
||||
};
|
||||
public:
|
||||
virtual void _ready() override;
|
||||
virtual void _process(double delta) override;
|
||||
|
||||
void set_target_turn_speed(float value);
|
||||
float get_target_turn_speed() const;
|
||||
void set_is_walking(bool value);
|
||||
bool get_is_walking() const;
|
||||
void set_walk_speed(float value);
|
||||
float get_walk_speed() const;
|
||||
void set_is_running();
|
||||
bool get_is_running() const;
|
||||
void set_aim_weapon(bool value);
|
||||
bool get_aim_weapon() const;
|
||||
void set_fire_weapon();
|
||||
bool get_fire_weapon();
|
||||
bool match_tags(Tags tags) const;
|
||||
private:
|
||||
void update_tags(gd::StringName const &anim);
|
||||
void commit_turn_speed();
|
||||
void commit_walk_speed();
|
||||
private:
|
||||
gd::Ref<gd::AnimationNodeStateMachinePlayback> fsm;
|
||||
float turn_speed{0.f};
|
||||
float target_turn_speed{0.f};
|
||||
bool is_walking{false};
|
||||
float walk_speed{0.f};
|
||||
double running_time{0.0};
|
||||
bool aim_weapon{false};
|
||||
double fire_weapon{0.0};
|
||||
Tags current_tags{Tags::None};
|
||||
gd::StringName last_known_anim{};
|
||||
};
|
||||
|
||||
#endif // !PLAYER_ANIM_HPP
|
||||
|
|
@ -16,6 +16,7 @@ void initialize_gdextension_types(ModuleInitializationLevel p_level)
|
|||
}
|
||||
utils::godot_cpp_utils_register_types();
|
||||
GDREGISTER_CLASS(Player);
|
||||
GDREGISTER_CLASS(PlayerAnimTree);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue