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/config/engine.h"
|
||||||
#include "core/input/input.h"
|
#include "core/input/input.h"
|
||||||
#include "core/math/math_funcs.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/3d/camera_3d.h"
|
||||||
#include "scene/animation/animation_player.h"
|
#include "scene/animation/animation_player.h"
|
||||||
#include "scene/main/viewport.h"
|
#include "scene/main/viewport.h"
|
||||||
#include "macros.h"
|
|
||||||
|
|
||||||
char *const PlayerBody::split_step_action{const_cast<char*>("split_step")};
|
char *const PlayerBody::split_step_action{const_cast<char*>("split_step")};
|
||||||
char *const PlayerBody::move_left_action{const_cast<char*>("move_left")};
|
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() {
|
void PlayerBody::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("get_desired_velocity"), &self_type::get_desired_velocity);
|
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("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, stopping_deceleration);
|
||||||
BIND_PROPERTY(Variant::FLOAT, start_speed);
|
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->anim = Object::cast_to<AnimationPlayer>(this->get_node(NodePath("character/AnimationPlayer")));
|
||||||
this->camera = Object::cast_to<Camera3D>(this->get_node(NodePath("Camera3D")));
|
this->camera = Object::cast_to<Camera3D>(this->get_node(NodePath("Camera3D")));
|
||||||
this->camera->set_fov(this->min_fov);
|
this->camera->set_fov(this->min_fov);
|
||||||
|
this->last_checkpoint = Checkpoint::save_new(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerBody::process(double delta) {
|
void PlayerBody::process(double delta) {
|
||||||
|
@ -74,6 +79,15 @@ void PlayerBody::physics_process(double delta) {
|
||||||
this->move_and_slide();
|
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 {
|
Vector3 PlayerBody::get_desired_direction() const {
|
||||||
Basis const global{this->camera->get_global_basis()};
|
Basis const global{this->camera->get_global_basis()};
|
||||||
Vector3 forward{global.get_column(2)};
|
Vector3 forward{global.get_column(2)};
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
#ifndef PLAYER_BODY_H
|
#ifndef PLAYER_BODY_H
|
||||||
#define PLAYER_BODY_H
|
#define PLAYER_BODY_H
|
||||||
|
|
||||||
|
#include "going/checkpoint.h"
|
||||||
#include "scene/3d/camera_3d.h"
|
#include "scene/3d/camera_3d.h"
|
||||||
#include "scene/3d/physics/character_body_3d.h"
|
#include "scene/3d/physics/character_body_3d.h"
|
||||||
#include "scene/animation/animation_player.h"
|
#include "scene/animation/animation_player.h"
|
||||||
|
class PlayerStateMachine;
|
||||||
|
|
||||||
class PlayerBody : public CharacterBody3D {
|
class PlayerBody : public CharacterBody3D {
|
||||||
GDCLASS(PlayerBody, CharacterBody3D);
|
GDCLASS(PlayerBody, CharacterBody3D);
|
||||||
|
@ -14,6 +16,8 @@ class PlayerBody : public CharacterBody3D {
|
||||||
void physics_process(double delta);
|
void physics_process(double delta);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
void save_checkpoint();
|
||||||
|
void load_checkpoint();
|
||||||
Vector3 get_desired_direction() const;
|
Vector3 get_desired_direction() const;
|
||||||
Vector3 get_desired_velocity() const;
|
Vector3 get_desired_velocity() const;
|
||||||
Vector2 get_movement_input() const;
|
Vector2 get_movement_input() const;
|
||||||
|
@ -71,6 +75,8 @@ private:
|
||||||
float model_lean_speed{0.25f};
|
float model_lean_speed{0.25f};
|
||||||
double game_over_speed{1.0/4.0};
|
double game_over_speed{1.0/4.0};
|
||||||
bool can_jump{false};
|
bool can_jump{false};
|
||||||
|
Ref<Checkpoint> last_checkpoint{nullptr};
|
||||||
|
PlayerStateMachine *state{nullptr};
|
||||||
public:
|
public:
|
||||||
static char *const split_step_action;
|
static char *const split_step_action;
|
||||||
static char *const move_left_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();
|
this->game_over_timer += delta * this->get_body()->get_game_over_speed();
|
||||||
if(this->game_over_timer > 1.0) {
|
if(this->game_over_timer > 1.0) {
|
||||||
RenderingServer::get_singleton()->global_shader_parameter_set(this->game_over_param, 0.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 {
|
} else {
|
||||||
RenderingServer::get_singleton()->global_shader_parameter_set(this->game_over_param, float(this->game_over_timer));
|
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);
|
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 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};
|
Vector3 const forward{current.x, 0.f, current.z};
|
||||||
if(!forward.is_zero_approx()) {
|
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() {
|
void RunningState::state_exited() {
|
||||||
Vector3 const velocity{this->get_body()->get_velocity()};
|
Vector3 const velocity{this->get_body()->get_velocity()};
|
||||||
Vector3 const velocity_flat{velocity.x, 0.f, velocity.z};
|
Vector3 velocity_flat{velocity.x, 0.f, velocity.z};
|
||||||
if(!velocity_flat.is_zero_approx()) {
|
if(velocity_flat.is_zero_approx()) {
|
||||||
this->get_body()->get_model()->look_at(this->get_body()->get_global_position() - velocity_flat);
|
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;
|
this->lean_modifier = 0.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerState::StateID SplitStepState::get_next_state() const {
|
PlayerState::StateID SplitStepState::get_next_state() const {
|
||||||
if(!this->get_body()->is_on_floor()) {
|
bool const jump_input{this->get_body()->get_can_jump() && this->jump};
|
||||||
return FallingState::get_class_static();
|
if(jump_input && (this->timer <= 0.0 || !this->get_body()->is_on_floor())) {
|
||||||
} else if(this->get_body()->get_can_jump() && this->jump && this->timer <= 0.0) {
|
|
||||||
return JumpingState::get_class_static();
|
return JumpingState::get_class_static();
|
||||||
|
} else if(!this->get_body()->is_on_floor()) {
|
||||||
|
return FallingState::get_class_static();
|
||||||
} else if(this->timer <= 0.0) {
|
} else if(this->timer <= 0.0) {
|
||||||
return RunningState::get_class_static();
|
return RunningState::get_class_static();
|
||||||
} else {
|
} else {
|
||||||
|
@ -169,7 +171,7 @@ void FallingState::process(double delta) {
|
||||||
this->game_over_timer += delta * this->get_body()->get_game_over_speed();
|
this->game_over_timer += delta * this->get_body()->get_game_over_speed();
|
||||||
if(this->game_over_timer > 1.0) {
|
if(this->game_over_timer > 1.0) {
|
||||||
RenderingServer::get_singleton()->global_shader_parameter_set(this->game_over_param, 0.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 {
|
} else {
|
||||||
RenderingServer::get_singleton()->global_shader_parameter_set(this->game_over_param, float(this->game_over_timer));
|
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);
|
this->game_over_timer = MIN(this->game_over_timer, 1.f);
|
||||||
|
|
|
@ -92,7 +92,10 @@ class PlayerStateMachine : public Node {
|
||||||
void try_transition();
|
void try_transition();
|
||||||
template <class TState>
|
template <class TState>
|
||||||
void add_state();
|
void add_state();
|
||||||
|
public:
|
||||||
|
template <class TState>
|
||||||
|
void force_state();
|
||||||
|
private:
|
||||||
PlayerBody *body{nullptr};
|
PlayerBody *body{nullptr};
|
||||||
PlayerState *current_state{nullptr};
|
PlayerState *current_state{nullptr};
|
||||||
HashMap<PlayerState::StateID, PlayerState*> states;
|
HashMap<PlayerState::StateID, PlayerState*> states;
|
||||||
|
@ -100,7 +103,7 @@ class PlayerStateMachine : public Node {
|
||||||
|
|
||||||
template <class TState>
|
template <class TState>
|
||||||
void PlayerStateMachine::add_state() {
|
void PlayerStateMachine::add_state() {
|
||||||
PlayerState *state{new TState()};
|
PlayerState *state{memnew(TState)};
|
||||||
state->body = this->body;
|
state->body = this->body;
|
||||||
this->states.insert(TState::get_class_static(), state);
|
this->states.insert(TState::get_class_static(), state);
|
||||||
if(this->current_state == nullptr) {
|
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
|
#endif // !PLAYER_STATES_H
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "register_types.h"
|
#include "register_types.h"
|
||||||
|
|
||||||
#include "core/object/class_db.h"
|
#include "core/object/class_db.h"
|
||||||
|
#include "going/checkpoint.h"
|
||||||
#include "going/game_ui.h"
|
#include "going/game_ui.h"
|
||||||
#include "going/player_body.h"
|
#include "going/player_body.h"
|
||||||
#include "going/player_states.h"
|
#include "going/player_states.h"
|
||||||
|
@ -18,6 +19,8 @@ void initialize_going_module(ModuleInitializationLevel p_level) {
|
||||||
ClassDB::register_class<JumpingState>();
|
ClassDB::register_class<JumpingState>();
|
||||||
ClassDB::register_class<PlayerStateMachine>();
|
ClassDB::register_class<PlayerStateMachine>();
|
||||||
ClassDB::register_class<GameUI>();
|
ClassDB::register_class<GameUI>();
|
||||||
|
ClassDB::register_class<Checkpoint>();
|
||||||
|
ClassDB::register_class<CheckpointArea>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void uninitialize_going_module(ModuleInitializationLevel p_level) {
|
void uninitialize_going_module(ModuleInitializationLevel p_level) {
|
||||||
|
|
Loading…
Reference in a new issue