From 92f5378a70141793b84cb103a98ff4dbd2c5d521 Mon Sep 17 00:00:00 2001 From: Orange Date: Wed, 3 Jun 2026 15:32:53 +0300 Subject: [PATCH] stage --- .../rage_engine/traits/pred_engine_trait.hpp | 76 +++++++++++++ .../proj_pred_engine_legacy.hpp | 102 +++++++++++++++++- .../projectile_prediction/projectile.hpp | 3 +- 3 files changed, 176 insertions(+), 5 deletions(-) create mode 100644 include/omath/engines/rage_engine/traits/pred_engine_trait.hpp diff --git a/include/omath/engines/rage_engine/traits/pred_engine_trait.hpp b/include/omath/engines/rage_engine/traits/pred_engine_trait.hpp new file mode 100644 index 0000000..8fb2e71 --- /dev/null +++ b/include/omath/engines/rage_engine/traits/pred_engine_trait.hpp @@ -0,0 +1,76 @@ +// +// Created by Codex on 6/3/2026. +// + +#pragma once +#include "omath/engines/rage_engine/formulas.hpp" +#include "omath/projectile_prediction/projectile.hpp" +#include "omath/projectile_prediction/target.hpp" +#include + +namespace omath::rage_engine +{ + class PredEngineTrait final + { + public: + constexpr static Vector3 + predict_projectile_position(const projectile_prediction::Projectile& projectile, const float pitch, + const float yaw, const float time, const float gravity) noexcept + { + const auto launch_pos = projectile.m_origin + projectile.m_launch_offset; + auto current_pos = launch_pos + + forward_vector({PitchAngle::from_degrees(-pitch), YawAngle::from_degrees(yaw), + RollAngle::from_degrees(0)}) + * projectile.m_launch_speed * time; + current_pos.z -= (gravity * projectile.m_gravity_scale) * (time * time) * 0.5f; + + return current_pos; + } + [[nodiscard]] + static constexpr Vector3 predict_target_position(const projectile_prediction::Target& target, + const float time, const float gravity) noexcept + { + auto predicted = target.m_origin + target.m_velocity * time; + + if (target.m_is_airborne) + predicted.z -= gravity * (time * time) * 0.5f; + + return predicted; + } + [[nodiscard]] + static float calc_vector_2d_distance(const Vector3& delta) noexcept + { + return std::sqrt(delta.x * delta.x + delta.y * delta.y); + } + + [[nodiscard]] + constexpr static float get_vector_height_coordinate(const Vector3& vec) noexcept + { + return vec.z; + } + + [[nodiscard]] + static Vector3 calc_viewpoint_from_angles(const projectile_prediction::Projectile& projectile, + Vector3 predicted_target_position, + const std::optional projectile_pitch) noexcept + { + 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}; + } + [[nodiscard]] + static float calc_direct_pitch_angle(const Vector3& origin, const Vector3& view_to) noexcept + { + const auto direction = (view_to - origin).normalized(); + return angles::radians_to_degrees(std::asin(direction.z)); + } + [[nodiscard]] + static float calc_direct_yaw_angle(const Vector3& origin, const Vector3& view_to) noexcept + { + const auto direction = (view_to - origin).normalized(); + + return angles::radians_to_degrees(-std::atan2(direction.x, direction.y)); + }; + }; +} // namespace omath::rage_engine diff --git a/include/omath/projectile_prediction/proj_pred_engine_legacy.hpp b/include/omath/projectile_prediction/proj_pred_engine_legacy.hpp index 0800a44..3e1d698 100644 --- a/include/omath/projectile_prediction/proj_pred_engine_legacy.hpp +++ b/include/omath/projectile_prediction/proj_pred_engine_legacy.hpp @@ -9,6 +9,7 @@ #include "omath/projectile_prediction/proj_pred_engine.hpp" #include "omath/projectile_prediction/projectile.hpp" #include "omath/projectile_prediction/target.hpp" +#include #include namespace omath::projectile_prediction @@ -96,7 +97,7 @@ namespace omath::projectile_prediction EngineTrait::predict_target_position(target, time, m_gravity_constant); const auto projectile_pitch = - maybe_calculate_projectile_launch_pitch_angle(projectile, predicted_target_position); + maybe_calculate_projectile_launch_pitch_angle(projectile, predicted_target_position, time); if (!projectile_pitch.has_value()) [[unlikely]] continue; @@ -130,7 +131,20 @@ namespace omath::projectile_prediction [[nodiscard]] std::optional maybe_calculate_projectile_launch_pitch_angle(const Projectile& projectile, - const Vector3& target_position) const noexcept + const Vector3& target_position, + const ArithmeticType time) const noexcept + { + if (projectile.m_air_friction > ArithmeticType{0}) + return maybe_calculate_projectile_launch_pitch_angle_with_air_friction(projectile, target_position, + time); + + return maybe_calculate_projectile_launch_pitch_angle_without_air_friction(projectile, target_position); + } + + [[nodiscard]] + std::optional maybe_calculate_projectile_launch_pitch_angle_without_air_friction( + const Projectile& projectile, + const Vector3& target_position) const noexcept { const auto bullet_gravity = m_gravity_constant * projectile.m_gravity_scale; @@ -160,6 +174,31 @@ namespace omath::projectile_prediction return angles::radians_to_degrees(angle); } + [[nodiscard]] + std::optional + maybe_calculate_projectile_launch_pitch_angle_with_air_friction(const Projectile& projectile, + const Vector3& target_position, + const ArithmeticType time) const noexcept + { + if (time <= ArithmeticType{0}) + return std::nullopt; + + const auto launch_origin = projectile.m_origin + projectile.m_launch_offset; + const auto velocity_factor = calculate_air_friction_velocity_factor(projectile.m_air_friction, time); + + if (velocity_factor == ArithmeticType{0}) [[unlikely]] + return std::nullopt; + + const auto gravity_acceleration = calculate_projectile_gravity_acceleration(projectile); + const auto gravity_displacement = + gravity_acceleration * ((time - velocity_factor) / projectile.m_air_friction); + const auto required_velocity = (target_position - launch_origin - gravity_displacement) / velocity_factor; + const auto horizontal_speed = EngineTrait::calc_vector_2d_distance(required_velocity); + const auto vertical_speed = EngineTrait::get_vector_height_coordinate(required_velocity); + + return angles::radians_to_degrees(std::atan2(vertical_speed, horizontal_speed)); + } + [[nodiscard]] bool is_projectile_reached_target(const Vector3& target_position, const Projectile& projectile, @@ -167,10 +206,65 @@ namespace omath::projectile_prediction { const auto yaw = EngineTrait::calc_direct_yaw_angle( projectile.m_origin + projectile.m_launch_offset, target_position); - const auto projectile_position = - EngineTrait::predict_projectile_position(projectile, pitch, yaw, time, m_gravity_constant); + const auto projectile_position = predict_projectile_position(projectile, pitch, yaw, time); return projectile_position.distance_to(target_position) <= m_distance_tolerance; } + + [[nodiscard]] + Vector3 predict_projectile_position(const Projectile& projectile, + const ArithmeticType pitch, const ArithmeticType yaw, + const ArithmeticType time) const noexcept + { + if (projectile.m_air_friction <= ArithmeticType{0}) + return EngineTrait::predict_projectile_position(projectile, pitch, yaw, time, m_gravity_constant); + + const auto launch_origin = projectile.m_origin + projectile.m_launch_offset; + const auto launch_velocity = calculate_projectile_launch_velocity(projectile, pitch, yaw); + const auto gravity_acceleration = calculate_projectile_gravity_acceleration(projectile); + const auto velocity_factor = calculate_air_friction_velocity_factor(projectile.m_air_friction, time); + const auto gravity_factor = (time - velocity_factor) / projectile.m_air_friction; + + return launch_origin + launch_velocity * velocity_factor + gravity_acceleration * gravity_factor; + } + + [[nodiscard]] + static ArithmeticType calculate_air_friction_velocity_factor(const ArithmeticType air_friction, + const ArithmeticType time) noexcept + { + return -std::expm1(-air_friction * time) / air_friction; + } + + [[nodiscard]] + Vector3 calculate_projectile_launch_velocity(const Projectile& projectile, + const ArithmeticType pitch, + const ArithmeticType yaw) const noexcept + { + const auto launch_origin = projectile.m_origin + projectile.m_launch_offset; + auto projectile_without_air_friction = projectile; + projectile_without_air_friction.m_air_friction = ArithmeticType{0}; + + return EngineTrait::predict_projectile_position(projectile_without_air_friction, pitch, yaw, + ArithmeticType{1}, ArithmeticType{0}) + - launch_origin; + } + + [[nodiscard]] + Vector3 + calculate_projectile_gravity_acceleration(const Projectile& projectile) const noexcept + { + constexpr ArithmeticType test_time = ArithmeticType{1}; + constexpr ArithmeticType acceleration_multiplier = ArithmeticType{2}; + auto projectile_without_air_friction = projectile; + projectile_without_air_friction.m_air_friction = ArithmeticType{0}; + const auto no_gravity_position = EngineTrait::predict_projectile_position( + projectile_without_air_friction, ArithmeticType{0}, ArithmeticType{0}, test_time, + ArithmeticType{0}); + const auto with_gravity_position = EngineTrait::predict_projectile_position( + projectile_without_air_friction, ArithmeticType{0}, ArithmeticType{0}, test_time, + m_gravity_constant); + + return (with_gravity_position - no_gravity_position) * acceleration_multiplier; + } }; } // namespace omath::projectile_prediction diff --git a/include/omath/projectile_prediction/projectile.hpp b/include/omath/projectile_prediction/projectile.hpp index 841ea50..8b81653 100644 --- a/include/omath/projectile_prediction/projectile.hpp +++ b/include/omath/projectile_prediction/projectile.hpp @@ -15,5 +15,6 @@ namespace omath::projectile_prediction Vector3 m_launch_offset{}; ArithmeticType m_launch_speed{}; ArithmeticType m_gravity_scale{}; + ArithmeticType m_air_friction{}; }; -} // namespace omath::projectile_prediction \ No newline at end of file +} // namespace omath::projectile_prediction