mirror of
https://github.com/orange-cpp/omath.git
synced 2026-06-08 16:24:35 +00:00
stage
This commit is contained in:
@@ -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 <optional>
|
||||
|
||||
namespace omath::rage_engine
|
||||
{
|
||||
class PredEngineTrait final
|
||||
{
|
||||
public:
|
||||
constexpr static Vector3<float>
|
||||
predict_projectile_position(const projectile_prediction::Projectile<float>& 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<float> predict_target_position(const projectile_prediction::Target<float>& 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<float>& delta) noexcept
|
||||
{
|
||||
return std::sqrt(delta.x * delta.x + delta.y * delta.y);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr static float get_vector_height_coordinate(const Vector3<float>& vec) noexcept
|
||||
{
|
||||
return vec.z;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
static Vector3<float> calc_viewpoint_from_angles(const projectile_prediction::Projectile<float>& projectile,
|
||||
Vector3<float> predicted_target_position,
|
||||
const std::optional<float> 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<float>& origin, const Vector3<float>& 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<float>& origin, const Vector3<float>& 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
|
||||
@@ -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 <cmath>
|
||||
#include <optional>
|
||||
|
||||
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,6 +131,19 @@ namespace omath::projectile_prediction
|
||||
[[nodiscard]]
|
||||
std::optional<ArithmeticType>
|
||||
maybe_calculate_projectile_launch_pitch_angle(const Projectile<ArithmeticType>& projectile,
|
||||
const Vector3<ArithmeticType>& 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<ArithmeticType> maybe_calculate_projectile_launch_pitch_angle_without_air_friction(
|
||||
const Projectile<ArithmeticType>& projectile,
|
||||
const Vector3<ArithmeticType>& 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<ArithmeticType>
|
||||
maybe_calculate_projectile_launch_pitch_angle_with_air_friction(const Projectile<ArithmeticType>& projectile,
|
||||
const Vector3<ArithmeticType>& 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<ArithmeticType>& target_position,
|
||||
const Projectile<ArithmeticType>& 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<ArithmeticType> predict_projectile_position(const Projectile<ArithmeticType>& 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<ArithmeticType> calculate_projectile_launch_velocity(const Projectile<ArithmeticType>& 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<ArithmeticType>
|
||||
calculate_projectile_gravity_acceleration(const Projectile<ArithmeticType>& 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
|
||||
|
||||
@@ -15,5 +15,6 @@ namespace omath::projectile_prediction
|
||||
Vector3<ArithmeticType> m_launch_offset{};
|
||||
ArithmeticType m_launch_speed{};
|
||||
ArithmeticType m_gravity_scale{};
|
||||
ArithmeticType m_air_friction{};
|
||||
};
|
||||
} // namespace omath::projectile_prediction
|
||||
Reference in New Issue
Block a user