Skip to content

Refactors projectile prediction engine #51

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions include/omath/projectile_prediction/proj_pred_engine.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@

namespace omath::projectile_prediction
{
class ProjPredEngine
class ProjPredEngineInterface
{
public:
[[nodiscard]]
virtual std::optional<Vector3<float>> maybe_calculate_aim_point(const Projectile& projectile,
const Target& target) const = 0;
virtual ~ProjPredEngine() = default;
virtual ~ProjPredEngineInterface() = default;
};
} // namespace omath::projectile_prediction
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace omath::projectile_prediction
{
class ProjPredEngineAvx2 final : public ProjPredEngine
class ProjPredEngineAvx2 final : public ProjPredEngineInterface
{
public:
[[nodiscard]] std::optional<Vector3<float>>
Expand Down
23 changes: 22 additions & 1 deletion include/omath/projectile_prediction/proj_pred_engine_legacy.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@

namespace omath::projectile_prediction
{
class ProjPredEngineLegacy final : public ProjPredEngine
// ReSharper disable once CppClassCanBeFinal
class ProjPredEngineLegacy : public ProjPredEngineInterface
{
public:
explicit ProjPredEngineLegacy(float gravity_constant, float simulation_time_step, float maximum_simulation_time,
Expand Down Expand Up @@ -48,5 +49,25 @@ namespace omath::projectile_prediction
[[nodiscard]]
bool is_projectile_reached_target(const Vector3<float>& target_position, const Projectile& projectile,
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
3 changes: 0 additions & 3 deletions include/omath/projectile_prediction/projectile.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@ namespace omath::projectile_prediction
class Projectile final
{
public:
[[nodiscard]]
Vector3<float> predict_position(float pitch, float yaw, float time, float gravity) const noexcept;

Vector3<float> m_origin;
float m_launch_speed{};
float m_gravity_scale{};
Expand Down
45 changes: 38 additions & 7 deletions source/projectile_prediction/proj_pred_engine_legacy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,7 @@ namespace omath::projectile_prediction
if (!is_projectile_reached_target(predicted_target_position, projectile, projectile_pitch.value(), time))
continue;

const auto delta2d = (predicted_target_position - projectile.m_origin).length_2d();
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 calc_viewpoint_from_angles(projectile, predicted_target_position, projectile_pitch);
}
return std::nullopt;
}
Expand All @@ -41,12 +38,14 @@ namespace omath::projectile_prediction
const auto bullet_gravity = m_gravity_constant * projectile.m_gravity_scale;
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 launch_speed_sqr = projectile.m_launch_speed * projectile.m_launch_speed;

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]]
return std::nullopt;
Expand All @@ -62,8 +61,40 @@ namespace omath::projectile_prediction
const float time) const noexcept
{
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;
}

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
12 changes: 0 additions & 12 deletions source/projectile_prediction/projectile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,4 @@

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
Loading