From 695a8035b5ff54e750f0aca4002384f34cba1fd8 Mon Sep 17 00:00:00 2001 From: Orange Date: Wed, 6 Aug 2025 05:45:37 +0300 Subject: [PATCH] Adds engine traits for projectile prediction Implements engine-specific traits for projectile and target position prediction. Each trait encapsulates logic tailored to a specific game engine (IW, OpenGL, Unity), accounting for engine-specific coordinate systems and calculations. This allows for accurate projectile prediction across different game environments. --- .../engine_traits/iw_engine_trait.hpp | 80 +++++++++++++++++++ .../engine_traits/opengl_engine_trait.hpp | 79 ++++++++++++++++++ .../engine_traits/unity_engine_trait.hpp | 79 ++++++++++++++++++ 3 files changed, 238 insertions(+) create mode 100644 include/omath/projectile_prediction/engine_traits/iw_engine_trait.hpp create mode 100644 include/omath/projectile_prediction/engine_traits/opengl_engine_trait.hpp create mode 100644 include/omath/projectile_prediction/engine_traits/unity_engine_trait.hpp diff --git a/include/omath/projectile_prediction/engine_traits/iw_engine_trait.hpp b/include/omath/projectile_prediction/engine_traits/iw_engine_trait.hpp new file mode 100644 index 0000000..0361e3b --- /dev/null +++ b/include/omath/projectile_prediction/engine_traits/iw_engine_trait.hpp @@ -0,0 +1,80 @@ +// +// Created by Vlad on 8/6/2025. +// +#pragma once + +#include "omath/engines/iw_engine/formulas.hpp" +#include "omath/projectile_prediction/projectile.hpp" +#include "omath/projectile_prediction/target.hpp" +#include + +namespace omath::projectile_prediction::traits +{ + class IwEngineTrait final + { + public: + constexpr static Vector3 predict_projectile_position(const Projectile& projectile, const float pitch, + const float yaw, const float time, + const float gravity) noexcept + { + auto current_pos = projectile.m_origin + + iw_engine::forward_vector({iw_engine::PitchAngle::from_degrees(-pitch), + iw_engine::YawAngle::from_degrees(yaw), + iw_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; + } + [[nodiscard]] + static constexpr Vector3 predict_target_position(const 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& 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}; + } + // Due to specification of maybe_calculate_projectile_launch_pitch_angle, pitch angle must be: + // 89 look up, -89 look down + [[nodiscard]] + static float calc_direct_pitch_angle(const Vector3& origin, const Vector3& view_to) noexcept + { + const auto distance = origin.distance_to(view_to); + const auto delta = view_to - origin; + + return angles::radians_to_degrees(std::asin(delta.z / distance)); + } + [[nodiscard]] + static float calc_direct_yaw_angle(const Vector3& origin, const Vector3& view_to) noexcept + { + const auto delta = view_to - origin; + + return angles::radians_to_degrees(std::atan2(delta.y, delta.x)); + }; + }; +} // namespace omath::projectile_prediction::traits \ No newline at end of file diff --git a/include/omath/projectile_prediction/engine_traits/opengl_engine_trait.hpp b/include/omath/projectile_prediction/engine_traits/opengl_engine_trait.hpp new file mode 100644 index 0000000..3241842 --- /dev/null +++ b/include/omath/projectile_prediction/engine_traits/opengl_engine_trait.hpp @@ -0,0 +1,79 @@ +// +// Created by Vlad on 8/6/2025. +// +#pragma once +#include "omath/engines/opengl_engine/formulas.hpp" +#include "omath/projectile_prediction/projectile.hpp" +#include "omath/projectile_prediction/target.hpp" +#include + +namespace omath::projectile_prediction::traits +{ + class OpenGlEngineTrait final + { + public: + constexpr static Vector3 predict_projectile_position(const Projectile& projectile, const float pitch, + const float yaw, const float time, + const float gravity) noexcept + { + auto current_pos = projectile.m_origin + + opengl_engine::forward_vector({opengl_engine::PitchAngle::from_degrees(-pitch), + opengl_engine::YawAngle::from_degrees(yaw), + opengl_engine::RollAngle::from_degrees(0)}) + * projectile.m_launch_speed * time; + current_pos.y -= (gravity * projectile.m_gravity_scale) * (time * time) * 0.5f; + + return current_pos; + } + [[nodiscard]] + static constexpr Vector3 predict_target_position(const Target& target, const float time, + const float gravity) noexcept + { + auto predicted = target.m_origin + target.m_velocity * time; + + if (target.m_is_airborne) + predicted.y -= 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.z * delta.z); + } + + [[nodiscard]] + constexpr static float get_vector_height_coordinate(const Vector3& vec) noexcept + { + return vec.z; + } + + [[nodiscard]] + static Vector3 calc_viewpoint_from_angles(const 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 + height, projectile.m_origin.z}; + } + // Due to specification of maybe_calculate_projectile_launch_pitch_angle, pitch angle must be: + // 89 look up, -89 look down + [[nodiscard]] + static float calc_direct_pitch_angle(const Vector3& origin, const Vector3& view_to) noexcept + { + const auto distance = origin.distance_to(view_to); + const auto delta = view_to - origin; + + return angles::radians_to_degrees(std::asin(delta.y / distance)); + } + [[nodiscard]] + static float calc_direct_yaw_angle(const Vector3& origin, const Vector3& view_to) noexcept + { + const auto delta = view_to - origin; + + return angles::radians_to_degrees(std::atan2(delta.z, delta.x)); + }; + }; +} // namespace omath::projectile_prediction::traits diff --git a/include/omath/projectile_prediction/engine_traits/unity_engine_trait.hpp b/include/omath/projectile_prediction/engine_traits/unity_engine_trait.hpp new file mode 100644 index 0000000..4246ba0 --- /dev/null +++ b/include/omath/projectile_prediction/engine_traits/unity_engine_trait.hpp @@ -0,0 +1,79 @@ +// +// Created by Vlad on 8/6/2025. +// +#pragma once +#include "omath/engines/unity_engine/formulas.hpp" +#include "omath/projectile_prediction/projectile.hpp" +#include "omath/projectile_prediction/target.hpp" +#include + +namespace omath::projectile_prediction::traits +{ + class UnityEngineTrait final + { + public: + constexpr static Vector3 predict_projectile_position(const Projectile& projectile, const float pitch, + const float yaw, const float time, + const float gravity) noexcept + { + auto current_pos = projectile.m_origin + + unity_engine::forward_vector({unity_engine::PitchAngle::from_degrees(-pitch), + unity_engine::YawAngle::from_degrees(yaw), + unity_engine::RollAngle::from_degrees(0)}) + * projectile.m_launch_speed * time; + current_pos.y -= (gravity * projectile.m_gravity_scale) * (time * time) * 0.5f; + + return current_pos; + } + [[nodiscard]] + static constexpr Vector3 predict_target_position(const Target& target, const float time, + const float gravity) noexcept + { + auto predicted = target.m_origin + target.m_velocity * time; + + if (target.m_is_airborne) + predicted.y -= 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.z * delta.z); + } + + [[nodiscard]] + constexpr static float get_vector_height_coordinate(const Vector3& vec) noexcept + { + return vec.z; + } + + [[nodiscard]] + static Vector3 calc_viewpoint_from_angles(const 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 + height, projectile.m_origin.z}; + } + // Due to specification of maybe_calculate_projectile_launch_pitch_angle, pitch angle must be: + // 89 look up, -89 look down + [[nodiscard]] + static float calc_direct_pitch_angle(const Vector3& origin, const Vector3& view_to) noexcept + { + const auto distance = origin.distance_to(view_to); + const auto delta = view_to - origin; + + return angles::radians_to_degrees(std::asin(delta.y / distance)); + } + [[nodiscard]] + static float calc_direct_yaw_angle(const Vector3& origin, const Vector3& view_to) noexcept + { + const auto delta = view_to - origin; + + return angles::radians_to_degrees(std::atan2(delta.z, delta.x)); + }; + }; +} // namespace omath::projectile_prediction::traits