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
	
	 Sara
						Sara