feat: player character can now fire projectiles using a projectile pool
This commit is contained in:
parent
cd9260871e
commit
f1646118ea
|
@ -1,6 +1,8 @@
|
||||||
#include "player_character.hpp"
|
#include "player_character.hpp"
|
||||||
|
#include "projectile_pool.hpp"
|
||||||
#include "utils/godot_macros.h"
|
#include "utils/godot_macros.h"
|
||||||
#include <godot_cpp/classes/navigation_agent3d.hpp>
|
#include <godot_cpp/classes/navigation_agent3d.hpp>
|
||||||
|
#include <godot_cpp/classes/time.hpp>
|
||||||
#include <godot_cpp/variant/utility_functions.hpp>
|
#include <godot_cpp/variant/utility_functions.hpp>
|
||||||
|
|
||||||
namespace godot {
|
namespace godot {
|
||||||
|
@ -13,13 +15,15 @@ void PlayerCharacter::_enter_tree() { GDGAMEONLY();
|
||||||
this->nav_agent = this->get_node<NavigationAgent3D>("NavigationAgent3D");
|
this->nav_agent = this->get_node<NavigationAgent3D>("NavigationAgent3D");
|
||||||
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");
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerCharacter::_process(double delta_time) { GDGAMEONLY();
|
void PlayerCharacter::_process(double delta_time) { GDGAMEONLY();
|
||||||
this->process_rotation(delta_time);
|
this->process_rotation(delta_time);
|
||||||
if(!this->mode_manual) {
|
if(!this->mode_manual)
|
||||||
this->process_ai(delta_time);
|
this->process_ai(delta_time);
|
||||||
}
|
if(this->firing)
|
||||||
|
this->try_fire_weapon();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerCharacter::_physics_process(double delta_time) { GDGAMEONLY();
|
void PlayerCharacter::_physics_process(double delta_time) { GDGAMEONLY();
|
||||||
|
@ -37,8 +41,8 @@ void PlayerCharacter::move(Vector3 world_vector) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerCharacter::aim(Vector3 at) {
|
void PlayerCharacter::aim(Vector3 at) {
|
||||||
// calculate the forward vector by normalized difference between this node and the target
|
// calculate the forward vector by normalized difference between player character and the target
|
||||||
Vector3 const position{this->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}).normalized()};
|
||||||
// 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};
|
||||||
|
@ -46,6 +50,10 @@ void PlayerCharacter::aim(Vector3 at) {
|
||||||
this->target_rotation = Basis{up.cross(forward), up, forward};
|
this->target_rotation = Basis{up.cross(forward), up, forward};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PlayerCharacter::set_firing(bool firing) {
|
||||||
|
this->firing = firing;
|
||||||
|
}
|
||||||
|
|
||||||
void PlayerCharacter::set_manual_mode(bool value) {
|
void PlayerCharacter::set_manual_mode(bool value) {
|
||||||
this->mode_manual = value;
|
this->mode_manual = value;
|
||||||
this->nav_agent->set_process_mode(value ? ProcessMode::PROCESS_MODE_PAUSABLE : ProcessMode::PROCESS_MODE_DISABLED);
|
this->nav_agent->set_process_mode(value ? ProcessMode::PROCESS_MODE_PAUSABLE : ProcessMode::PROCESS_MODE_DISABLED);
|
||||||
|
@ -67,6 +75,19 @@ Health const *PlayerCharacter::get_health() const {
|
||||||
return this->health;
|
return this->health;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PlayerCharacter::set_character_data(Ref<CharacterData> data) {
|
||||||
|
this->data = data;
|
||||||
|
UtilityFunctions::print("PlayerCharacter::set_character_data");
|
||||||
|
UtilityFunctions::print(" - data: ", data->get_path());
|
||||||
|
UtilityFunctions::print(" - weapon: ", data->get_weapon()->get_path());
|
||||||
|
this->fire_interval = 1.f / this->data->get_weapon()->get_rounds_per_second();
|
||||||
|
this->primary_weapon_pool->set_data(this->data->get_weapon());
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerCharacter::set_weapon_muzzle(Node3D *node) {
|
||||||
|
this->weapon_muzzle = node;
|
||||||
|
}
|
||||||
|
|
||||||
void PlayerCharacter::process_ai(double delta_time) {
|
void PlayerCharacter::process_ai(double delta_time) {
|
||||||
this->velocity_target = this->nav_agent->get_velocity();
|
this->velocity_target = this->nav_agent->get_velocity();
|
||||||
}
|
}
|
||||||
|
@ -85,11 +106,22 @@ void PlayerCharacter::process_rotation(double delta_time) {
|
||||||
float const angle_step{float(this->rotation_speed_curve->sample(angle) * PlayerCharacter::ROTATION_SPEED * delta_time)};
|
float const angle_step{float(this->rotation_speed_curve->sample(angle) * PlayerCharacter::ROTATION_SPEED * delta_time)};
|
||||||
// update this object's global transform with the new rotation
|
// update this object's global transform with the new rotation
|
||||||
basis.set_quaternion(angle < angle_step ? target_quaternion // to avoid overshooting, check if the max step is smaller than the angle distance
|
basis.set_quaternion(angle < angle_step ? target_quaternion // to avoid overshooting, check if the max step is smaller than the angle distance
|
||||||
: current_quaternion.slerp(target_quaternion, angle_step / angle)); // convert the angle step to a lerp t value between current and target rotations
|
: current_quaternion.slerp(target_quaternion, angle_step / angle)); // convert the angle step to a lerp t value between current and target rotations
|
||||||
trans.set_basis(basis);
|
trans.set_basis(basis);
|
||||||
this->set_global_transform(trans);
|
this->set_global_transform(trans);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PlayerCharacter::try_fire_weapon() {
|
||||||
|
if(float(Time::get_singleton()->get_ticks_msec()) / 1000.f < this->fire_timer)
|
||||||
|
return;
|
||||||
|
if(!this->data->get_weapon()->get_allow_automatic())
|
||||||
|
this->set_firing(false);
|
||||||
|
this->fire_timer = float(Time::get_singleton()->get_ticks_msec()) / 1000.f + this->fire_interval;
|
||||||
|
Node3D *node = this->primary_weapon_pool->claim_projectile();
|
||||||
|
if(node != nullptr)
|
||||||
|
node->set_global_transform(this->weapon_muzzle->get_global_transform());
|
||||||
|
}
|
||||||
|
|
||||||
float const PlayerCharacter::ACCELERATION{100.f};
|
float const PlayerCharacter::ACCELERATION{100.f};
|
||||||
float const PlayerCharacter::WALK_SPEED{3.f};
|
float const PlayerCharacter::WALK_SPEED{3.f};
|
||||||
float const PlayerCharacter::SPRINT_SPEED{5.f};
|
float const PlayerCharacter::SPRINT_SPEED{5.f};
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
#ifndef PLAYER_CHARACTER_HPP
|
#ifndef PLAYER_CHARACTER_HPP
|
||||||
#define PLAYER_CHARACTER_HPP
|
#define PLAYER_CHARACTER_HPP
|
||||||
|
|
||||||
#include "godot_cpp/classes/curve.hpp"
|
#include "character_data.hpp"
|
||||||
#include "health.hpp"
|
#include "health.hpp"
|
||||||
|
#include "projectile_pool.hpp"
|
||||||
#include <godot_cpp/classes/character_body3d.hpp>
|
#include <godot_cpp/classes/character_body3d.hpp>
|
||||||
|
#include <godot_cpp/classes/curve.hpp>
|
||||||
|
|
||||||
namespace godot {
|
namespace godot {
|
||||||
class NavigationAgent3D;
|
class NavigationAgent3D;
|
||||||
|
@ -18,6 +20,7 @@ public:
|
||||||
virtual void _physics_process(double delta_time) override;
|
virtual void _physics_process(double delta_time) override;
|
||||||
void move(Vector3 world_vector);
|
void move(Vector3 world_vector);
|
||||||
void aim(Vector3 at);
|
void aim(Vector3 at);
|
||||||
|
void set_firing(bool firing);
|
||||||
void set_manual_mode(bool value);
|
void set_manual_mode(bool value);
|
||||||
|
|
||||||
void set_rotation_speed_curve(Ref<Curve> curve);
|
void set_rotation_speed_curve(Ref<Curve> curve);
|
||||||
|
@ -25,15 +28,26 @@ public:
|
||||||
|
|
||||||
virtual Health *get_health() override;
|
virtual Health *get_health() override;
|
||||||
virtual Health const *get_health() const override;
|
virtual Health const *get_health() const override;
|
||||||
|
|
||||||
|
void set_character_data(Ref<CharacterData> data);
|
||||||
|
|
||||||
|
void set_weapon_muzzle(Node3D *node);
|
||||||
protected:
|
protected:
|
||||||
void process_ai(double delta_time);
|
void process_ai(double delta_time);
|
||||||
void process_rotation(double delta_time);
|
void process_rotation(double delta_time);
|
||||||
|
void try_fire_weapon();
|
||||||
private:
|
private:
|
||||||
Vector3 velocity_target{0.f,0.f,0.f};
|
Vector3 velocity_target{0.f,0.f,0.f};
|
||||||
Basis target_rotation{};
|
Basis target_rotation{};
|
||||||
NavigationAgent3D *nav_agent{nullptr};
|
NavigationAgent3D *nav_agent{nullptr};
|
||||||
bool mode_manual{false};
|
bool mode_manual{false};
|
||||||
Health *health{nullptr};
|
Health *health{nullptr};
|
||||||
|
ProjectilePool *primary_weapon_pool{nullptr};
|
||||||
|
Ref<CharacterData> data;
|
||||||
|
float fire_interval{0.f};
|
||||||
|
bool firing{false};
|
||||||
|
float fire_timer{0.f};
|
||||||
|
Node3D *weapon_muzzle{nullptr};
|
||||||
|
|
||||||
Ref<Curve> rotation_speed_curve{};
|
Ref<Curve> rotation_speed_curve{};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue