feat: removed all player state machine code
This commit is contained in:
parent
ac89de735e
commit
b5505d7317
|
@ -1,6 +1,5 @@
|
||||||
#include "player_character.hpp"
|
#include "player_character.hpp"
|
||||||
#include "projectile_pool.hpp"
|
#include "projectile_pool.hpp"
|
||||||
#include "state_machine.hpp"
|
|
||||||
#include "utils/godot_macros.h"
|
#include "utils/godot_macros.h"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <godot_cpp/classes/navigation_agent3d.hpp>
|
#include <godot_cpp/classes/navigation_agent3d.hpp>
|
||||||
|
@ -21,7 +20,6 @@ void PlayerCharacter::_enter_tree() { GDGAMEONLY();
|
||||||
this->target_rotation = this->get_global_transform().get_basis().get_quaternion();
|
this->target_rotation = this->get_global_transform().get_basis().get_quaternion();
|
||||||
this->health = this->get_node<Health>("Health");
|
this->health = this->get_node<Health>("Health");
|
||||||
this->primary_weapon_pool = this->get_node<ProjectilePool>("ProjectilePool");
|
this->primary_weapon_pool = this->get_node<ProjectilePool>("ProjectilePool");
|
||||||
this->state_machine = this->get_node<StateMachine>("StateMachine");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerCharacter::_process(double delta_time) { GDGAMEONLY();
|
void PlayerCharacter::_process(double delta_time) { GDGAMEONLY();
|
||||||
|
@ -50,13 +48,15 @@ void PlayerCharacter::move(Vector3 world_vector) {
|
||||||
void PlayerCharacter::aim(Vector3 at) {
|
void PlayerCharacter::aim(Vector3 at) {
|
||||||
// calculate the forward vector by normalized difference between player character and the target on the XZ plane
|
// calculate the forward vector by normalized difference between player character and the target on the XZ plane
|
||||||
Vector3 const position{this->weapon_muzzle->get_global_position()};
|
Vector3 const position{this->weapon_muzzle->get_global_position()};
|
||||||
Vector3 const forward{(Vector3{at.x, 0.f, at.z} - Vector3{position.x, 0.f, position.z}).normalized()};
|
Vector3 const forward{Vector3{at.x, 0.f, at.z} - Vector3{position.x, 0.f, position.z}};
|
||||||
this->aim_direction(forward);
|
this->aim_direction(forward.normalized());
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerCharacter::aim_direction(Vector3 direction) {
|
void PlayerCharacter::aim_direction(Vector3 direction) {
|
||||||
if(direction.is_zero_approx())
|
if(!direction.is_normalized()) {
|
||||||
return; // there is no situation in which rotation target would be 0
|
UtilityFunctions::push_error("'", this->get_path(), "' Cannot aim along a non-normalized direction vector", direction.length_squared());
|
||||||
|
return;
|
||||||
|
}
|
||||||
// we always want up to be the global unit up
|
// we always want up to be the global unit up
|
||||||
Vector3 const up{0.f, 1.f, 0.f};
|
Vector3 const up{0.f, 1.f, 0.f};
|
||||||
// left is the cross product of the two
|
// left is the cross product of the two
|
||||||
|
@ -84,7 +84,6 @@ void PlayerCharacter::set_manual_mode(bool value) {
|
||||||
ProcessMode const mode = value ? ProcessMode::PROCESS_MODE_DISABLED : ProcessMode::PROCESS_MODE_PAUSABLE;
|
ProcessMode const mode = value ? ProcessMode::PROCESS_MODE_DISABLED : ProcessMode::PROCESS_MODE_PAUSABLE;
|
||||||
//this->nav_agent->set_process_mode(mode);
|
//this->nav_agent->set_process_mode(mode);
|
||||||
this->nav_agent->set_avoidance_priority(value ? 1.f : 0.9f);
|
this->nav_agent->set_avoidance_priority(value ? 1.f : 0.9f);
|
||||||
this->state_machine->set_process_mode(mode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerCharacter::set_rotation_speed_curve(Ref<Curve> curve) {
|
void PlayerCharacter::set_rotation_speed_curve(Ref<Curve> curve) {
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
|
|
||||||
namespace godot {
|
namespace godot {
|
||||||
class NavigationAgent3D;
|
class NavigationAgent3D;
|
||||||
class StateMachine;
|
|
||||||
class TunnelsPlayer;
|
class TunnelsPlayer;
|
||||||
|
|
||||||
class PlayerCharacter : public CharacterBody3D,
|
class PlayerCharacter : public CharacterBody3D,
|
||||||
|
@ -46,7 +45,6 @@ protected:
|
||||||
void try_fire_weapon();
|
void try_fire_weapon();
|
||||||
private:
|
private:
|
||||||
Vector3 velocity_target{0.f,0.f,0.f};
|
Vector3 velocity_target{0.f,0.f,0.f};
|
||||||
StateMachine *state_machine{nullptr};
|
|
||||||
Basis target_rotation{};
|
Basis target_rotation{};
|
||||||
NavigationAgent3D *nav_agent{nullptr};
|
NavigationAgent3D *nav_agent{nullptr};
|
||||||
bool mode_manual{false};
|
bool mode_manual{false};
|
||||||
|
|
|
@ -1,52 +0,0 @@
|
||||||
#include "player_states.hpp"
|
|
||||||
#include "player_character.hpp"
|
|
||||||
#include "tunnels_game_mode.hpp"
|
|
||||||
#include "utils/game_root.hpp"
|
|
||||||
#include <cmath>
|
|
||||||
#include <godot_cpp/variant/utility_functions.hpp>
|
|
||||||
|
|
||||||
namespace godot {
|
|
||||||
void PlayerState::_bind_methods() {
|
|
||||||
#define CLASSNAME PlayerState
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlayerState::init(Node *target, StateMachine *machine) {
|
|
||||||
this->state_machine = machine;
|
|
||||||
this->parent = Object::cast_to<PlayerCharacter>(target);
|
|
||||||
if(!this->parent)
|
|
||||||
UtilityFunctions::push_error("Attempt to apply player state to non-PlayerCharacter node of type '", target->get_class(), "'");
|
|
||||||
Ref<TunnelsGameMode> game_mode = GameRoot::get_singleton()->get_game_mode();
|
|
||||||
this->player = game_mode->get_player_instance();
|
|
||||||
if(!this->player)
|
|
||||||
UtilityFunctions::push_error("Failed to find valid TunnelsPlayer instance in game mode");
|
|
||||||
}
|
|
||||||
|
|
||||||
StringName PlayerState::get_next() const {
|
|
||||||
return this->get_class();
|
|
||||||
}
|
|
||||||
|
|
||||||
PlayerCharacter *PlayerState::get_manual_character() const {
|
|
||||||
return this->player->get_character();
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector3 PlayerState::get_home_position() const {
|
|
||||||
Basis const player_basis = this->get_manual_character()->get_global_transform().basis;
|
|
||||||
Vector3 const player_origin = this->get_manual_character()->get_global_position();
|
|
||||||
Vector3 const offset = this->parent->get_global_position() - player_origin;
|
|
||||||
Vector3 const local = Vector3(0.f, (std::signbit(player_basis.get_column(0).dot(offset)) ? 1.f : -1.f), -1.f).normalized() * 3.f;
|
|
||||||
return player_origin + player_basis.get_column(0) * local.x + player_basis.get_column(2) * local.z;
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef CLASSNAME // PlayerState
|
|
||||||
|
|
||||||
void FollowingPlayer::_bind_methods() {
|
|
||||||
#define CLASSNAME FollowingPlayer
|
|
||||||
}
|
|
||||||
|
|
||||||
void FollowingPlayer::_process(double delta_time) {
|
|
||||||
this->parent->move_to(this->get_home_position(), 1.f);
|
|
||||||
this->parent->aim_direction(this->parent->get_velocity_target());
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef CLASSNAME // FollowingPlayer
|
|
||||||
}
|
|
|
@ -1,37 +0,0 @@
|
||||||
#ifndef PLAYER_STATES_HPP
|
|
||||||
#define PLAYER_STATES_HPP
|
|
||||||
|
|
||||||
#include "state.hpp"
|
|
||||||
|
|
||||||
namespace godot {
|
|
||||||
class PlayerCharacter;
|
|
||||||
class StateMachine;
|
|
||||||
class TunnelsPlayer;
|
|
||||||
|
|
||||||
class PlayerState : public Node,
|
|
||||||
public IState {
|
|
||||||
GDCLASS(PlayerState, Node);
|
|
||||||
static void _bind_methods();
|
|
||||||
public:
|
|
||||||
virtual void init(Node *target, StateMachine *machine) override;
|
|
||||||
virtual StringName get_next() const override;
|
|
||||||
protected:
|
|
||||||
float get_distance_from_player(bool sqr = false) const;
|
|
||||||
PlayerCharacter *get_manual_character() const;
|
|
||||||
Vector3 get_home_position() const;
|
|
||||||
bool in_player_line_of_fire() const;
|
|
||||||
protected:
|
|
||||||
PlayerCharacter *parent{nullptr};
|
|
||||||
StateMachine *state_machine{nullptr};
|
|
||||||
TunnelsPlayer *player{nullptr};
|
|
||||||
};
|
|
||||||
|
|
||||||
class FollowingPlayer : public PlayerState {
|
|
||||||
GDCLASS(FollowingPlayer, PlayerState);
|
|
||||||
static void _bind_methods();
|
|
||||||
public:
|
|
||||||
virtual void _process(double delta_time) override;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // !PLAYER_STATES_HPP
|
|
|
@ -4,10 +4,7 @@
|
||||||
#include "health.hpp"
|
#include "health.hpp"
|
||||||
#include "pellet_projectile.hpp"
|
#include "pellet_projectile.hpp"
|
||||||
#include "player_character.hpp"
|
#include "player_character.hpp"
|
||||||
#include "player_states.hpp"
|
|
||||||
#include "projectile_pool.hpp"
|
#include "projectile_pool.hpp"
|
||||||
#include "state.hpp"
|
|
||||||
#include "state_machine.hpp"
|
|
||||||
#include "tunnels_game_mode.hpp"
|
#include "tunnels_game_mode.hpp"
|
||||||
#include "tunnels_game_state.hpp"
|
#include "tunnels_game_state.hpp"
|
||||||
#include "tunnels_player.hpp"
|
#include "tunnels_player.hpp"
|
||||||
|
@ -54,10 +51,6 @@ void initialize_gdextension_types(ModuleInitializationLevel p_level)
|
||||||
|
|
||||||
ClassDB::register_class<Projectile>();
|
ClassDB::register_class<Projectile>();
|
||||||
ClassDB::register_class<PelletProjectile>();
|
ClassDB::register_class<PelletProjectile>();
|
||||||
|
|
||||||
ClassDB::register_class<StateMachine>();
|
|
||||||
ClassDB::register_class<PlayerState>();
|
|
||||||
ClassDB::register_class<FollowingPlayer>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
#include "state.hpp"
|
|
||||||
#include "state_machine.hpp"
|
|
||||||
|
|
||||||
namespace godot {
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
#ifndef STATE_HPP
|
|
||||||
#define STATE_HPP
|
|
||||||
|
|
||||||
#include "godot_cpp/core/defs.hpp"
|
|
||||||
#include <godot_cpp/classes/node.hpp>
|
|
||||||
|
|
||||||
namespace godot {
|
|
||||||
class StateMachine;
|
|
||||||
|
|
||||||
class IState {
|
|
||||||
friend class StateMachine;
|
|
||||||
public:
|
|
||||||
virtual void init(Node *target, StateMachine *machine) = 0;
|
|
||||||
virtual StringName get_next() const = 0;
|
|
||||||
_ALWAYS_INLINE_ Node *as_node() { return dynamic_cast<Node*>(this); }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // !STATE_HPP
|
|
|
@ -1,62 +0,0 @@
|
||||||
#include "state_machine.hpp"
|
|
||||||
#include "state.hpp"
|
|
||||||
#include "utils/godot_macros.h"
|
|
||||||
#include <godot_cpp/classes/scene_tree.hpp>
|
|
||||||
#include <godot_cpp/variant/string_name.hpp>
|
|
||||||
#include <godot_cpp/variant/utility_functions.hpp>
|
|
||||||
|
|
||||||
namespace godot {
|
|
||||||
void StateMachine::_bind_methods() {
|
|
||||||
#define CLASSNAME StateMachine
|
|
||||||
GDPROPERTY(initial_state, Variant::STRING_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
void StateMachine::_enter_tree() { GDGAMEONLY();
|
|
||||||
this->override_state(this->initial_state);
|
|
||||||
}
|
|
||||||
|
|
||||||
void StateMachine::_exit_tree() { GDGAMEONLY();
|
|
||||||
for(KeyValue<StringName, IState*> kvp : available)
|
|
||||||
if(!kvp.value->as_node()->is_inside_tree())
|
|
||||||
kvp.value->as_node()->queue_free();
|
|
||||||
}
|
|
||||||
|
|
||||||
void StateMachine::_process(double delta_time) { GDGAMEONLY();
|
|
||||||
if(this->state)
|
|
||||||
this->override_state(this->state->get_next());
|
|
||||||
}
|
|
||||||
|
|
||||||
void StateMachine::override_state(StringName next) {
|
|
||||||
// don't change state if target is current
|
|
||||||
if(this->state != nullptr && next == this->state->as_node()->get_class())
|
|
||||||
return;
|
|
||||||
if(this->state)
|
|
||||||
this->remove_child(this->state->as_node());
|
|
||||||
if(next.is_empty()) {
|
|
||||||
this->state = nullptr;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// instantiate new state if this type is not yet available
|
|
||||||
if(!this->available.has(next)) {
|
|
||||||
IState *instance = dynamic_cast<IState*>(Object::cast_to<Node>(ClassDB::instantiate(next)));
|
|
||||||
if(instance == nullptr) {
|
|
||||||
UtilityFunctions::push_error("Failure to instantiate state with class '", next, "'");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this->available.insert(next, instance);
|
|
||||||
instance->init(this->get_parent(), this);
|
|
||||||
instance->as_node()->set_process_mode(ProcessMode::PROCESS_MODE_INHERIT);
|
|
||||||
}
|
|
||||||
// set the new state and add it to the tree
|
|
||||||
this->state = this->available.get(next);
|
|
||||||
this->add_child(this->state->as_node());
|
|
||||||
}
|
|
||||||
|
|
||||||
void StateMachine::set_initial_state(StringName name) {
|
|
||||||
this->initial_state = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringName StateMachine::get_initial_state() const {
|
|
||||||
return this->initial_state;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
#ifndef STATE_MACHINE_HPP
|
|
||||||
#define STATE_MACHINE_HPP
|
|
||||||
|
|
||||||
#include <godot_cpp/variant/string_name.hpp>
|
|
||||||
#include <godot_cpp/classes/node.hpp>
|
|
||||||
#include <godot_cpp/templates/hash_map.hpp>
|
|
||||||
|
|
||||||
namespace godot {
|
|
||||||
class IState;
|
|
||||||
|
|
||||||
class StateMachine : public Node {
|
|
||||||
GDCLASS(StateMachine, Node);
|
|
||||||
static void _bind_methods();
|
|
||||||
public:
|
|
||||||
virtual void _enter_tree() override;
|
|
||||||
virtual void _exit_tree() override;
|
|
||||||
virtual void _process(double delta_time) override;
|
|
||||||
|
|
||||||
void override_state(StringName new_state_class);
|
|
||||||
|
|
||||||
void set_initial_state(StringName name);
|
|
||||||
StringName get_initial_state() const;
|
|
||||||
private:
|
|
||||||
String initial_state{};
|
|
||||||
IState *state{nullptr};
|
|
||||||
HashMap<StringName, IState*> available{};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // !STATE_MACHINE_HPP
|
|
Loading…
Reference in a new issue