Refactors projectile prediction engine

Refactors the projectile prediction engine by introducing an interface
and making the legacy implementation more flexible.

The legacy engine is updated to allow for coordinate system customization
through virtual methods, enabling usage in different game environments.

Also introduces vcpkg support for easier dependency management and adds boost-asio as a dependency.
This commit is contained in:
2025-08-03 17:33:22 +03:00
parent 4b44ce0667
commit f1fbea21a7
6 changed files with 63 additions and 26 deletions

View File

@@ -8,12 +8,12 @@
namespace omath::projectile_prediction namespace omath::projectile_prediction
{ {
class ProjPredEngine class ProjPredEngineInterface
{ {
public: public:
[[nodiscard]] [[nodiscard]]
virtual std::optional<Vector3<float>> maybe_calculate_aim_point(const Projectile& projectile, virtual std::optional<Vector3<float>> maybe_calculate_aim_point(const Projectile& projectile,
const Target& target) const = 0; const Target& target) const = 0;
virtual ~ProjPredEngine() = default; virtual ~ProjPredEngineInterface() = default;
}; };
} // namespace omath::projectile_prediction } // namespace omath::projectile_prediction

View File

@@ -6,7 +6,7 @@
namespace omath::projectile_prediction namespace omath::projectile_prediction
{ {
class ProjPredEngineAvx2 final : public ProjPredEngine class ProjPredEngineAvx2 final : public ProjPredEngineInterface
{ {
public: public:
[[nodiscard]] std::optional<Vector3<float>> [[nodiscard]] std::optional<Vector3<float>>

View File

@@ -12,7 +12,8 @@
namespace omath::projectile_prediction namespace omath::projectile_prediction
{ {
class ProjPredEngineLegacy final : public ProjPredEngine // ReSharper disable once CppClassCanBeFinal
class ProjPredEngineLegacy : public ProjPredEngineInterface
{ {
public: public:
explicit ProjPredEngineLegacy(float gravity_constant, float simulation_time_step, float maximum_simulation_time, explicit ProjPredEngineLegacy(float gravity_constant, float simulation_time_step, float maximum_simulation_time,
@@ -48,5 +49,25 @@ namespace omath::projectile_prediction
[[nodiscard]] [[nodiscard]]
bool is_projectile_reached_target(const Vector3<float>& target_position, const Projectile& projectile, bool is_projectile_reached_target(const Vector3<float>& target_position, const Projectile& projectile,
float pitch, float time) const noexcept; float pitch, float time) const noexcept;
protected:
// NOTE: Override this if you need to use engine with different coordinate system
// Like where Z is not height coordinate
// ===============================================================================================
[[nodiscard]]
virtual float calc_vector_2d_distance(const Vector3<float>& delta) const;
[[nodiscard]]
virtual float get_vector_height_coordinate(const Vector3<float>& vec) const;
[[nodiscard]]
virtual Vector3<float> calc_viewpoint_from_angles(const Projectile& projectile,
Vector3<float> predicted_target_position,
std::optional<float> projectile_pitch) const;
[[nodiscard]]
virtual Vector3<float> predict_projectile_position(const Projectile& projectile, float pitch, float yaw,
float time, float gravity) const;
// ===============================================================================================
}; };
} // namespace omath::projectile_prediction } // namespace omath::projectile_prediction

View File

@@ -10,9 +10,6 @@ namespace omath::projectile_prediction
class Projectile final class Projectile final
{ {
public: public:
[[nodiscard]]
Vector3<float> predict_position(float pitch, float yaw, float time, float gravity) const noexcept;
Vector3<float> m_origin; Vector3<float> m_origin;
float m_launch_speed{}; float m_launch_speed{};
float m_gravity_scale{}; float m_gravity_scale{};

View File

@@ -27,10 +27,7 @@ namespace omath::projectile_prediction
if (!is_projectile_reached_target(predicted_target_position, projectile, projectile_pitch.value(), time)) if (!is_projectile_reached_target(predicted_target_position, projectile, projectile_pitch.value(), time))
continue; continue;
const auto delta2d = (predicted_target_position - projectile.m_origin).length_2d(); return calc_viewpoint_from_angles(projectile, predicted_target_position, projectile_pitch);
const auto height = delta2d * std::tan(angles::degrees_to_radians(projectile_pitch.value()));
return Vector3(predicted_target_position.x, predicted_target_position.y, projectile.m_origin.z + height);
} }
return std::nullopt; return std::nullopt;
} }
@@ -41,12 +38,14 @@ namespace omath::projectile_prediction
const auto bullet_gravity = m_gravity_constant * projectile.m_gravity_scale; const auto bullet_gravity = m_gravity_constant * projectile.m_gravity_scale;
const auto delta = target_position - projectile.m_origin; const auto delta = target_position - projectile.m_origin;
const auto distance2d = delta.length_2d(); const auto distance2d = calc_vector_2d_distance(delta);
const auto distance2d_sqr = distance2d * distance2d; const auto distance2d_sqr = distance2d * distance2d;
const auto launch_speed_sqr = projectile.m_launch_speed * projectile.m_launch_speed; const auto launch_speed_sqr = projectile.m_launch_speed * projectile.m_launch_speed;
float root = launch_speed_sqr * launch_speed_sqr float root = launch_speed_sqr * launch_speed_sqr
- bullet_gravity * (bullet_gravity * distance2d_sqr + 2.0f * delta.z * launch_speed_sqr); - bullet_gravity
* (bullet_gravity * distance2d_sqr
+ 2.0f * get_vector_height_coordinate(delta) * launch_speed_sqr);
if (root < 0.0f) [[unlikely]] if (root < 0.0f) [[unlikely]]
return std::nullopt; return std::nullopt;
@@ -62,8 +61,40 @@ namespace omath::projectile_prediction
const float time) const noexcept const float time) const noexcept
{ {
const auto yaw = projectile.m_origin.view_angle_to(target_position).y; const auto yaw = projectile.m_origin.view_angle_to(target_position).y;
const auto projectile_position = projectile.predict_position(pitch, yaw, time, m_gravity_constant); const auto projectile_position = predict_projectile_position(projectile, pitch, yaw, time, m_gravity_constant);
return projectile_position.distance_to(target_position) <= m_distance_tolerance; return projectile_position.distance_to(target_position) <= m_distance_tolerance;
} }
float ProjPredEngineLegacy::calc_vector_2d_distance(const Vector3<float>& delta) const
{
return std::sqrt(delta.x * delta.x + delta.y * delta.y);
}
float ProjPredEngineLegacy::get_vector_height_coordinate(const Vector3<float>& vec) const
{
return vec.z;
}
Vector3<float> ProjPredEngineLegacy::calc_viewpoint_from_angles(const Projectile& projectile,
const Vector3<float> predicted_target_position,
const std::optional<float> projectile_pitch) const
{
const auto delta2d = calc_vector_2d_distance(predicted_target_position - projectile.m_origin);
const auto height = delta2d * std::tan(angles::degrees_to_radians(projectile_pitch.value()));
return {predicted_target_position.x, predicted_target_position.y, projectile.m_origin.z + height};
}
Vector3<float> ProjPredEngineLegacy::predict_projectile_position(const Projectile& projectile, const float pitch,
const float yaw, const float time,
const float gravity) const
{
auto current_pos = projectile.m_origin
+ source_engine::forward_vector({source_engine::PitchAngle::from_degrees(-pitch),
source_engine::YawAngle::from_degrees(yaw),
source_engine::RollAngle::from_degrees(0)})
* projectile.m_launch_speed * time;
current_pos.z -= (gravity * projectile.m_gravity_scale) * (time * time) * 0.5f;
return current_pos;
}
} // namespace omath::projectile_prediction } // namespace omath::projectile_prediction

View File

@@ -7,16 +7,4 @@
namespace omath::projectile_prediction namespace omath::projectile_prediction
{ {
Vector3<float> Projectile::predict_position(const float pitch, const float yaw, const float time,
const float gravity) const noexcept
{
auto current_pos = m_origin
+ source_engine::forward_vector({source_engine::PitchAngle::from_degrees(-pitch),
source_engine::YawAngle::from_degrees(yaw),
source_engine::RollAngle::from_degrees(0)})
* m_launch_speed * time;
current_pos.z -= (gravity * m_gravity_scale) * (time * time) * 0.5f;
return current_pos;
}
} // namespace omath::projectile_prediction } // namespace omath::projectile_prediction