feat: final bits

This commit is contained in:
Sara 2025-06-16 00:14:02 +02:00
parent d64c8d2b61
commit cebae80b5c
34 changed files with 1827 additions and 373 deletions

View file

@ -29,11 +29,14 @@ void PlayerBody::_bind_methods() {
BIND_PROPERTY(Variant::FLOAT, target_speed);
BIND_PROPERTY(Variant::FLOAT, split_step_time);
BIND_PROPERTY(Variant::FLOAT, split_step_stop_time);
BIND_PROPERTY(Variant::FLOAT, bash_speed);
BIND_PROPERTY(Variant::FLOAT, bash_time);
BIND_PROPERTY(Variant::VECTOR2, jump_impulse);
BIND_PROPERTY(Variant::FLOAT, model_lean);
BIND_PROPERTY(Variant::FLOAT, model_lean_speed);
BIND_PROPERTY(Variant::FLOAT, game_over_speed);
BIND_PROPERTY(Variant::BOOL, can_jump);
BIND_PROPERTY(Variant::BOOL, can_bash);
}
void PlayerBody::_notification(int what) {
@ -191,6 +194,22 @@ double PlayerBody::get_split_step_stop_time() const {
return this->split_step_stop_time;
}
void PlayerBody::set_bash_speed(float value) {
this->bash_speed = value;
}
float PlayerBody::get_bash_speed() const {
return this->bash_speed;
}
void PlayerBody::set_bash_time(double value) {
this->bash_time = value;
}
double PlayerBody::get_bash_time() const {
return this->bash_time;
}
void PlayerBody::set_jump_impulse(Vector2 value) {
this->jump_impulse = value;
}
@ -230,3 +249,11 @@ void PlayerBody::set_can_jump(bool value) {
bool PlayerBody::get_can_jump() const {
return this->can_jump;
}
void PlayerBody::set_can_bash(bool value) {
this->can_bash = value;
}
bool PlayerBody::get_can_bash() const {
return this->can_bash;
}

View file

@ -43,6 +43,10 @@ public:
double get_split_step_time() const;
void set_split_step_stop_time(double value);
double get_split_step_stop_time() const;
void set_bash_speed(float value);
float get_bash_speed() const;
void set_bash_time(double value);
double get_bash_time() const;
void set_jump_impulse(Vector2 value);
Vector2 get_jump_impulse() const;
void set_model_lean(float value);
@ -53,6 +57,8 @@ public:
float get_game_over_speed() const;
void set_can_jump(bool value);
bool get_can_jump() const;
void set_can_bash(bool value);
bool get_can_bash() const;
private:
Vector2 movement{0.f, 0.f};
@ -68,6 +74,8 @@ private:
float target_speed{30.f};
double split_step_time{0.5};
double split_step_stop_time{0.5};
float bash_speed{100.f};
double bash_time{0.25};
Vector2 jump_impulse{5.f, 5.f};
float max_speed_fov{100.f};
float min_fov{80.f};
@ -75,6 +83,7 @@ private:
float model_lean{0.25f};
float model_lean_speed{0.25f};
double game_over_speed{1.0/4.0};
bool can_bash{false};
bool can_jump{false};
Ref<Checkpoint> last_checkpoint{nullptr};
PlayerStateMachine *state{nullptr};

View file

@ -1,6 +1,7 @@
#include "player_states.h"
#include "core/config/engine.h"
#include "core/math/math_funcs.h"
#include "core/object/class_db.h"
#include "core/typedefs.h"
#include "going/player_body.h"
#include "scene/main/scene_tree.h"
@ -109,9 +110,10 @@ void RunningState::state_exited() {
}
PlayerState::StateID SplitStepState::get_next_state() const {
bool const jump_input{this->get_body()->get_can_jump() && this->jump};
if(jump_input && (this->timer <= 0.0 || !this->get_body()->is_on_floor())) {
if(this->next == Jump && (this->timer <= 0.0 || !this->get_body()->is_on_floor())) {
return JumpingState::get_class_static();
} else if(this->next == Bash && (this->timer <= 0.0 || !this->get_body()->is_on_floor())) {
return BashState::get_class_static();
} else if(!this->get_body()->is_on_floor()) {
return FallingState::get_class_static();
} else if(this->timer <= 0.0) {
@ -122,7 +124,7 @@ PlayerState::StateID SplitStepState::get_next_state() const {
}
void SplitStepState::state_entered() {
this->jump = false;
this->next = Run;
this->last_velocity = this->get_body()->get_velocity();
this->timer = this->get_body()->get_split_step_time();
this->get_body()->set_velocity(last_velocity.normalized() * this->get_body()->get_target_speed() * 0.75f);
@ -131,7 +133,12 @@ void SplitStepState::state_entered() {
void SplitStepState::process(double delta) {
this->timer -= delta;
this->jump |= Input::get_singleton()->is_action_pressed("jump");
if(this->get_body()->get_can_jump() && Input::get_singleton()->is_action_pressed("jump")) {
this->next = Jump;
}
if(this->get_body()->get_can_bash() && Input::get_singleton()->is_action_pressed("bash")) {
this->next = Bash;
}
}
void SplitStepState::physics_process(double delta) {
@ -141,12 +148,21 @@ void SplitStepState::physics_process(double delta) {
void SplitStepState::state_exited() {
Vector3 desired_direction{0.f, 0.f, 0.f};
if(this->jump) {
switch(this->next) {
case Jump:
desired_direction = Vector3{last_velocity.x, 0.f, last_velocity.z}.normalized();
} else if(this->get_body()->is_on_floor()) {
desired_direction = this->get_body()->get_desired_direction();
break;
case Bash:
default:
if(this->get_body()->is_on_floor()) {
desired_direction = this->get_body()->get_desired_direction();
}
break;
}
float const dot{this->last_velocity.normalized().dot(desired_direction)};
float const dot{this->last_velocity
.normalized()
.dot(desired_direction)
};
this->get_body()->set_velocity(dot > -0.8f
? desired_direction * MAX(last_velocity.length(), this->get_body()->get_step_boost())
: Vector3()
@ -162,7 +178,7 @@ PlayerState::StateID FallingState::get_next_state() const {
}
void FallingState::state_entered() {
this->get_body()->get_anim()->play("falling", 0.1);
this->get_body()->get_anim()->play("falling", 0.25);
}
void FallingState::physics_process(double delta) {
@ -194,7 +210,48 @@ void JumpingState::physics_process(double delta) {
this->get_body()->set_velocity((flattened - (flattened * 0.015f)) + Vector3{0.f, current.y - float(9.8 * delta), 0.f});
}
PlayerState::StateID BashState::get_next_state() const {
if(!this->get_body()->is_on_floor()) {
return FallingState::get_class_static();
} else if (this->timer < 0.0) {
return StandingState::get_class_static();
}
return this->get_class();
}
void BashState::state_entered() {
this->get_body()->get_anim()->play("bash");
this->timer = this->get_body()->get_bash_time();
this->speed = this->get_body()->get_bash_speed();
(this->vfx = Object::cast_to<Node3D>(this->get_body()->get_node(this->vfx_path)))->set_visible(true);
}
void BashState::process(double delta) {
this->timer -= delta;
}
void BashState::physics_process(double delta) {
double const progress{1.0 - this->timer / this->get_body()->get_bash_time()};
this->get_body()->set_velocity(
Math::lerp(
this->get_body()->get_bash_speed(),
this->get_body()->get_target_speed(),
float(progress)
) * this->get_body()->get_model()->get_global_basis().get_column(2).normalized()
+ Vector3{0, float(-2.0 / delta), 0}
);
}
void BashState::state_exited() {
this->vfx->set_visible(false);
if(!this->get_body()->is_on_floor()) {
this->get_body()->set_velocity(this->get_body()->get_velocity() / 2.f);
}
}
void PlayerStateMachine::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_current_state"), &self_type::get_current_state);
}
void PlayerStateMachine::_notification(int what) {
@ -226,6 +283,7 @@ void PlayerStateMachine::ready() {
this->add_state<RunningState>();
this->add_state<SplitStepState>();
this->add_state<JumpingState>();
this->add_state<BashState>();
}
void PlayerStateMachine::try_transition() {
@ -236,3 +294,7 @@ void PlayerStateMachine::try_transition() {
this->current_state->state_entered();
}
}
StringName PlayerStateMachine::get_current_state() const {
return this->current_state->get_class();
}

View file

@ -59,9 +59,12 @@ public:
virtual void physics_process(double delta) override;
virtual void state_exited() override;
private:
enum NextAction {
Run, Bash, Jump
};
Vector3 last_velocity{0.f, 0.f, 0.f};
double timer{0.0};
bool jump{false};
NextAction next{Run};
};
class FallingState : public PlayerState {
@ -80,6 +83,21 @@ public:
virtual void physics_process(double delta) override;
};
class BashState : public PlayerState {
GDCLASS(BashState, PlayerState);
public:
virtual StateID get_next_state() const override;
virtual void state_entered() override;
virtual void process(double delta) override;
virtual void physics_process(double delta) override;
virtual void state_exited() override;
private:
NodePath vfx_path{"character/bash_attack"};
Node3D *vfx{nullptr};
double timer{0.0};
float speed{0.f};
};
class PlayerStateMachine : public Node {
GDCLASS(PlayerStateMachine, Node);
static void _bind_methods();
@ -89,6 +107,7 @@ class PlayerStateMachine : public Node {
template <class TState>
void add_state();
public:
StringName get_current_state() const;
template <class TState>
void force_state();
private:

View file

@ -17,6 +17,7 @@ void initialize_going_module(ModuleInitializationLevel p_level) {
ClassDB::register_class<SplitStepState>();
ClassDB::register_class<FallingState>();
ClassDB::register_class<JumpingState>();
ClassDB::register_class<BashState>();
ClassDB::register_class<PlayerStateMachine>();
ClassDB::register_class<GameUI>();
ClassDB::register_class<Checkpoint>();