feat: implemented initial checkpoint mechanic
This commit is contained in:
parent
4ef4212d26
commit
37b7b94566
65
modules/going/checkpoint.cpp
Normal file
65
modules/going/checkpoint.cpp
Normal file
|
@ -0,0 +1,65 @@
|
|||
#include "checkpoint.h"
|
||||
#include "core/config/engine.h"
|
||||
#include "going/player_body.h"
|
||||
#include "macros.h"
|
||||
|
||||
void Checkpoint::_bind_methods() {
|
||||
BIND_PROPERTY(Variant::VECTOR3, location);
|
||||
BIND_PROPERTY(Variant::BOOL, can_jump);
|
||||
BIND_PROPERTY(Variant::BOOL, can_bash);
|
||||
}
|
||||
|
||||
void Checkpoint::set_location(Transform3D location) {
|
||||
this->location = location;
|
||||
}
|
||||
|
||||
Transform3D Checkpoint::get_location() const {
|
||||
return this->location;
|
||||
}
|
||||
|
||||
void Checkpoint::set_can_jump(bool can_jump) {
|
||||
this->can_jump = can_jump;
|
||||
}
|
||||
|
||||
bool Checkpoint::get_can_jump() const {
|
||||
return this->can_jump;
|
||||
}
|
||||
|
||||
void Checkpoint::set_can_bash(bool can_bash) {
|
||||
this->can_bash = can_bash;
|
||||
}
|
||||
|
||||
bool Checkpoint::get_can_bash() const {
|
||||
return this->can_bash;
|
||||
}
|
||||
|
||||
void Checkpoint::load(PlayerBody *body) const {
|
||||
body->set_global_transform(this->location);
|
||||
body->set_can_jump(this->can_jump);
|
||||
// body->set_can_bash(this->can_bash);
|
||||
}
|
||||
|
||||
void Checkpoint::save(PlayerBody *body) {
|
||||
this->set_location(body->get_global_transform_interpolated());
|
||||
this->set_can_jump(body->get_can_jump());
|
||||
// self->set_can_bash(body->get_can_bash());
|
||||
}
|
||||
|
||||
Ref<Checkpoint> Checkpoint::save_new(PlayerBody *body) {
|
||||
Ref<Checkpoint> self{memnew(Checkpoint)};
|
||||
self->save(body);
|
||||
return self;
|
||||
}
|
||||
|
||||
void CheckpointArea::_notification(int what) {
|
||||
if(!Engine::get_singleton()->is_editor_hint() && what == NOTIFICATION_READY) {
|
||||
this->connect(this->body_entered, callable_mp(this, &self_type::on_body_entered));
|
||||
}
|
||||
}
|
||||
|
||||
void CheckpointArea::on_body_entered(Node3D *body) {
|
||||
if(PlayerBody *player{Object::cast_to<PlayerBody>(body)}) {
|
||||
player->save_checkpoint();
|
||||
}
|
||||
}
|
||||
|
37
modules/going/checkpoint.h
Normal file
37
modules/going/checkpoint.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
#ifndef CHECKPOINT_H
|
||||
#define CHECKPOINT_H
|
||||
|
||||
#include "core/io/resource.h"
|
||||
#include "core/math/transform_3d.h"
|
||||
#include "scene/3d/node_3d.h"
|
||||
#include "scene/3d/physics/area_3d.h"
|
||||
class PlayerBody;
|
||||
|
||||
class Checkpoint : public Resource {
|
||||
GDCLASS(Checkpoint, Resource);
|
||||
static void _bind_methods();
|
||||
public:
|
||||
void set_location(Transform3D location);
|
||||
Transform3D get_location() const;
|
||||
void set_can_jump(bool can_jump);
|
||||
bool get_can_jump() const;
|
||||
void set_can_bash(bool can_bash);
|
||||
bool get_can_bash() const;
|
||||
|
||||
void load(PlayerBody *body) const;
|
||||
void save(PlayerBody *body);
|
||||
static Ref<Checkpoint> save_new(PlayerBody *body);
|
||||
private:
|
||||
Transform3D location{};
|
||||
bool can_jump{false}, can_bash{false};
|
||||
};
|
||||
|
||||
class CheckpointArea : public Area3D {
|
||||
GDCLASS(CheckpointArea, Area3D);
|
||||
static void _bind_methods() {}
|
||||
void _notification(int what);
|
||||
void on_body_entered(Node3D *body);
|
||||
StringName body_entered{"body_entered"};
|
||||
};
|
||||
|
||||
#endif // !CHECKPOINT_H
|
|
@ -2,10 +2,12 @@
|
|||
#include "core/config/engine.h"
|
||||
#include "core/input/input.h"
|
||||
#include "core/math/math_funcs.h"
|
||||
#include "core/object/class_db.h"
|
||||
#include "macros.h"
|
||||
#include "player_states.h"
|
||||
#include "scene/3d/camera_3d.h"
|
||||
#include "scene/animation/animation_player.h"
|
||||
#include "scene/main/viewport.h"
|
||||
#include "macros.h"
|
||||
|
||||
char *const PlayerBody::split_step_action{const_cast<char*>("split_step")};
|
||||
char *const PlayerBody::move_left_action{const_cast<char*>("move_left")};
|
||||
|
@ -16,6 +18,8 @@ char *const PlayerBody::move_back_action{const_cast<char*>("move_back")};
|
|||
void PlayerBody::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("get_desired_velocity"), &self_type::get_desired_velocity);
|
||||
ClassDB::bind_method(D_METHOD("get_desired_direction"), &self_type::get_desired_direction);
|
||||
ClassDB::bind_method(D_METHOD("save_checkpoint"), &self_type::save_checkpoint);
|
||||
ClassDB::bind_method(D_METHOD("load_checkpoint"), &self_type::load_checkpoint);
|
||||
|
||||
BIND_PROPERTY(Variant::FLOAT, stopping_deceleration);
|
||||
BIND_PROPERTY(Variant::FLOAT, start_speed);
|
||||
|
@ -58,6 +62,7 @@ void PlayerBody::enter_tree() {
|
|||
this->anim = Object::cast_to<AnimationPlayer>(this->get_node(NodePath("character/AnimationPlayer")));
|
||||
this->camera = Object::cast_to<Camera3D>(this->get_node(NodePath("Camera3D")));
|
||||
this->camera->set_fov(this->min_fov);
|
||||
this->last_checkpoint = Checkpoint::save_new(this);
|
||||
}
|
||||
|
||||
void PlayerBody::process(double delta) {
|
||||
|
@ -74,6 +79,15 @@ void PlayerBody::physics_process(double delta) {
|
|||
this->move_and_slide();
|
||||
}
|
||||
|
||||
void PlayerBody::save_checkpoint() {
|
||||
this->last_checkpoint->save(this);
|
||||
}
|
||||
|
||||
void PlayerBody::load_checkpoint() {
|
||||
this->last_checkpoint->load(this);
|
||||
this->state->force_state<FallingState>();
|
||||
}
|
||||
|
||||
Vector3 PlayerBody::get_desired_direction() const {
|
||||
Basis const global{this->camera->get_global_basis()};
|
||||
Vector3 forward{global.get_column(2)};
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
#ifndef PLAYER_BODY_H
|
||||
#define PLAYER_BODY_H
|
||||
|
||||
#include "going/checkpoint.h"
|
||||
#include "scene/3d/camera_3d.h"
|
||||
#include "scene/3d/physics/character_body_3d.h"
|
||||
#include "scene/animation/animation_player.h"
|
||||
class PlayerStateMachine;
|
||||
|
||||
class PlayerBody : public CharacterBody3D {
|
||||
GDCLASS(PlayerBody, CharacterBody3D);
|
||||
|
@ -14,6 +16,8 @@ class PlayerBody : public CharacterBody3D {
|
|||
void physics_process(double delta);
|
||||
|
||||
public:
|
||||
void save_checkpoint();
|
||||
void load_checkpoint();
|
||||
Vector3 get_desired_direction() const;
|
||||
Vector3 get_desired_velocity() const;
|
||||
Vector2 get_movement_input() const;
|
||||
|
@ -71,6 +75,8 @@ private:
|
|||
float model_lean_speed{0.25f};
|
||||
double game_over_speed{1.0/4.0};
|
||||
bool can_jump{false};
|
||||
Ref<Checkpoint> last_checkpoint{nullptr};
|
||||
PlayerStateMachine *state{nullptr};
|
||||
public:
|
||||
static char *const split_step_action;
|
||||
static char *const move_left_action;
|
||||
|
|
|
@ -30,7 +30,7 @@ void StandingState::process(double delta) {
|
|||
this->game_over_timer += delta * this->get_body()->get_game_over_speed();
|
||||
if(this->game_over_timer > 1.0) {
|
||||
RenderingServer::get_singleton()->global_shader_parameter_set(this->game_over_param, 0.0);
|
||||
SceneTree::get_singleton()->reload_current_scene();
|
||||
this->get_body()->load_checkpoint();
|
||||
} else {
|
||||
RenderingServer::get_singleton()->global_shader_parameter_set(this->game_over_param, float(this->game_over_timer));
|
||||
this->game_over_timer = MIN(this->game_over_timer, 1.f);
|
||||
|
@ -78,7 +78,7 @@ void RunningState::process_lean(double delta) {
|
|||
Vector3 const up{Vector3{0.0, 1.0, 0.0} + Vector3{cross.x, 0.f, cross.y} * this->lean_modifier};
|
||||
Vector3 const forward{current.x, 0.f, current.z};
|
||||
if(!forward.is_zero_approx()) {
|
||||
this->get_body()->get_model()->look_at(this->get_body()->get_global_position() - current, up);
|
||||
this->get_body()->get_model()->look_at(this->get_body()->get_global_position() - forward, up);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -100,18 +100,20 @@ void RunningState::physics_process(double delta) {
|
|||
|
||||
void RunningState::state_exited() {
|
||||
Vector3 const velocity{this->get_body()->get_velocity()};
|
||||
Vector3 const velocity_flat{velocity.x, 0.f, velocity.z};
|
||||
if(!velocity_flat.is_zero_approx()) {
|
||||
this->get_body()->get_model()->look_at(this->get_body()->get_global_position() - velocity_flat);
|
||||
Vector3 velocity_flat{velocity.x, 0.f, velocity.z};
|
||||
if(velocity_flat.is_zero_approx()) {
|
||||
velocity_flat = this->get_body()->get_model()->get_global_basis().get_column(2);
|
||||
}
|
||||
this->get_body()->get_model()->look_at(this->get_body()->get_global_position() - velocity_flat);
|
||||
this->lean_modifier = 0.f;
|
||||
}
|
||||
|
||||
PlayerState::StateID SplitStepState::get_next_state() const {
|
||||
if(!this->get_body()->is_on_floor()) {
|
||||
return FallingState::get_class_static();
|
||||
} else if(this->get_body()->get_can_jump() && this->jump && this->timer <= 0.0) {
|
||||
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())) {
|
||||
return JumpingState::get_class_static();
|
||||
} else if(!this->get_body()->is_on_floor()) {
|
||||
return FallingState::get_class_static();
|
||||
} else if(this->timer <= 0.0) {
|
||||
return RunningState::get_class_static();
|
||||
} else {
|
||||
|
@ -169,7 +171,7 @@ void FallingState::process(double delta) {
|
|||
this->game_over_timer += delta * this->get_body()->get_game_over_speed();
|
||||
if(this->game_over_timer > 1.0) {
|
||||
RenderingServer::get_singleton()->global_shader_parameter_set(this->game_over_param, 0.0);
|
||||
SceneTree::get_singleton()->reload_current_scene();
|
||||
this->get_body()->load_checkpoint();
|
||||
} else {
|
||||
RenderingServer::get_singleton()->global_shader_parameter_set(this->game_over_param, float(this->game_over_timer));
|
||||
this->game_over_timer = MIN(this->game_over_timer, 1.f);
|
||||
|
|
|
@ -92,7 +92,10 @@ class PlayerStateMachine : public Node {
|
|||
void try_transition();
|
||||
template <class TState>
|
||||
void add_state();
|
||||
|
||||
public:
|
||||
template <class TState>
|
||||
void force_state();
|
||||
private:
|
||||
PlayerBody *body{nullptr};
|
||||
PlayerState *current_state{nullptr};
|
||||
HashMap<PlayerState::StateID, PlayerState*> states;
|
||||
|
@ -100,7 +103,7 @@ class PlayerStateMachine : public Node {
|
|||
|
||||
template <class TState>
|
||||
void PlayerStateMachine::add_state() {
|
||||
PlayerState *state{new TState()};
|
||||
PlayerState *state{memnew(TState)};
|
||||
state->body = this->body;
|
||||
this->states.insert(TState::get_class_static(), state);
|
||||
if(this->current_state == nullptr) {
|
||||
|
@ -109,4 +112,9 @@ void PlayerStateMachine::add_state() {
|
|||
}
|
||||
}
|
||||
|
||||
template <class TState>
|
||||
void PlayerStateMachine::force_state() {
|
||||
this->states[TState::get_class_static()];
|
||||
}
|
||||
|
||||
#endif // !PLAYER_STATES_H
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "register_types.h"
|
||||
|
||||
#include "core/object/class_db.h"
|
||||
#include "going/checkpoint.h"
|
||||
#include "going/game_ui.h"
|
||||
#include "going/player_body.h"
|
||||
#include "going/player_states.h"
|
||||
|
@ -18,6 +19,8 @@ void initialize_going_module(ModuleInitializationLevel p_level) {
|
|||
ClassDB::register_class<JumpingState>();
|
||||
ClassDB::register_class<PlayerStateMachine>();
|
||||
ClassDB::register_class<GameUI>();
|
||||
ClassDB::register_class<Checkpoint>();
|
||||
ClassDB::register_class<CheckpointArea>();
|
||||
}
|
||||
|
||||
void uninitialize_going_module(ModuleInitializationLevel p_level) {
|
||||
|
|
Loading…
Reference in a new issue