mirror of
https://github.com/orange-cpp/omath.git
synced 2026-02-13 15:03:27 +00:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ea8f3d8d51 | |||
| 08d2ccc03a | |||
| 21ec23d77b | |||
| 2c4ff37062 | |||
| 695a8035b5 | |||
| d12b236e56 | |||
| 7a5090d9f6 | |||
| ec76a7239c | |||
| 2758f549a3 | |||
| 493931ef0f | |||
| 9e1990942b | |||
| f1984fbe46 | |||
| f1fbea21a7 | |||
| 4b44ce0667 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,4 +1,5 @@
|
||||
/cmake-build/
|
||||
/.idea
|
||||
/out
|
||||
*.DS_Store
|
||||
*.DS_Store
|
||||
/extlibs/vcpkg
|
||||
@@ -1,11 +1,11 @@
|
||||
cmake_minimum_required(VERSION 3.26)
|
||||
|
||||
project(omath VERSION 3.0.2 LANGUAGES CXX)
|
||||
project(omath VERSION 3.0.4.1 LANGUAGES CXX)
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
|
||||
option(OMATH_BUILD_TESTS "Build unit tests" OFF)
|
||||
option(OMATH_BUILD_TESTS "Build unit tests" ${PROJECT_IS_TOP_LEVEL})
|
||||
option(OMATH_THREAT_WARNING_AS_ERROR "Set highest level of warnings and force compiler to treat them as errors" ON)
|
||||
option(OMATH_BUILD_AS_SHARED_LIBRARY "Build Omath as .so or .dll" OFF)
|
||||
option(OMATH_USE_AVX2 "Omath will use AVX2 to boost performance" ON)
|
||||
|
||||
32
CONTRIBUTING.md
Normal file
32
CONTRIBUTING.md
Normal file
@@ -0,0 +1,32 @@
|
||||
## 🤝 Contributing to OMath or other Orange's Projects
|
||||
|
||||
### ❕ Prerequisites
|
||||
|
||||
- A working up-to-date OMath installation
|
||||
- C++ knowledge
|
||||
- Git knowledge
|
||||
- Ability to ask for help (Feel free to create empty pull-request or PM a maintainer
|
||||
in [Telegram](https://t.me/orange_cpp))
|
||||
|
||||
### ⏬ Setting up OMath
|
||||
|
||||
Please read INSTALL.md file in repository
|
||||
|
||||
### 🔀 Pull requests and Branches
|
||||
|
||||
In order to send code back to the official OMath repository, you must first create a copy of OMath on your github
|
||||
account ([fork](https://help.github.com/articles/creating-a-pull-request-from-a-fork/)) and
|
||||
then [create a pull request](https://help.github.com/articles/creating-a-pull-request-from-a-fork/) back to OMath.
|
||||
|
||||
OMath developement is performed on multiple branches. Changes are then pull requested into master. By default, changes
|
||||
merged into master will not roll out to stable build users unless the `stable` tag is updated.
|
||||
|
||||
### 📜 Code-Style
|
||||
|
||||
The orange code-style can be found in `.clang-format`.
|
||||
|
||||
### 📦 Building
|
||||
|
||||
OMath has already created the `cmake-build` and `out` directories where cmake/bin files are located. By default, you
|
||||
can build OMath by running `cmake --build cmake-build/build/windows-release --target omath -j 6` in the source
|
||||
directory.
|
||||
@@ -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 <optional>
|
||||
|
||||
namespace omath::projectile_prediction::traits
|
||||
{
|
||||
class IwEngineTrait final
|
||||
{
|
||||
public:
|
||||
constexpr static Vector3<float> 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<float> 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<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& 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};
|
||||
}
|
||||
// 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<float>& origin, const Vector3<float>& 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<float>& origin, const Vector3<float>& 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
|
||||
@@ -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 <optional>
|
||||
|
||||
namespace omath::projectile_prediction::traits
|
||||
{
|
||||
class OpenGlEngineTrait final
|
||||
{
|
||||
public:
|
||||
constexpr static Vector3<float> 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<float> 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<float>& delta) noexcept
|
||||
{
|
||||
return std::sqrt(delta.x * delta.x + delta.z * delta.z);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr static float get_vector_height_coordinate(const Vector3<float>& vec) noexcept
|
||||
{
|
||||
return vec.y;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
static Vector3<float> calc_viewpoint_from_angles(const Projectile& 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 + 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<float>& origin, const Vector3<float>& 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<float>& origin, const Vector3<float>& 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
|
||||
@@ -0,0 +1,80 @@
|
||||
//
|
||||
// Created by Vlad on 8/3/2025.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include "omath/engines/source_engine/formulas.hpp"
|
||||
#include "omath/projectile_prediction/projectile.hpp"
|
||||
#include "omath/projectile_prediction/target.hpp"
|
||||
#include <optional>
|
||||
|
||||
namespace omath::projectile_prediction::traits
|
||||
{
|
||||
class SourceEngineTrait final
|
||||
{
|
||||
public:
|
||||
constexpr static Vector3<float> 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
|
||||
+ 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;
|
||||
}
|
||||
[[nodiscard]]
|
||||
static constexpr Vector3<float> 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<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& 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};
|
||||
}
|
||||
// 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<float>& origin, const Vector3<float>& 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<float>& origin, const Vector3<float>& 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
|
||||
@@ -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 <optional>
|
||||
|
||||
namespace omath::projectile_prediction::traits
|
||||
{
|
||||
class UnityEngineTrait final
|
||||
{
|
||||
public:
|
||||
constexpr static Vector3<float> 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<float> 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<float>& delta) noexcept
|
||||
{
|
||||
return std::sqrt(delta.x * delta.x + delta.z * delta.z);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr static float get_vector_height_coordinate(const Vector3<float>& vec) noexcept
|
||||
{
|
||||
return vec.y;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
static Vector3<float> calc_viewpoint_from_angles(const Projectile& 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 + 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<float>& origin, const Vector3<float>& 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<float>& origin, const Vector3<float>& 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
|
||||
@@ -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
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
namespace omath::projectile_prediction
|
||||
{
|
||||
class ProjPredEngineAvx2 final : public ProjPredEngine
|
||||
class ProjPredEngineAvx2 final : public ProjPredEngineInterface
|
||||
{
|
||||
public:
|
||||
[[nodiscard]] std::optional<Vector3<float>>
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "engine_traits/source_engine_trait.hpp"
|
||||
#include "omath/projectile_prediction/proj_pred_engine.hpp"
|
||||
#include "omath/projectile_prediction/projectile.hpp"
|
||||
#include "omath/projectile_prediction/target.hpp"
|
||||
@@ -12,15 +13,40 @@
|
||||
|
||||
namespace omath::projectile_prediction
|
||||
{
|
||||
class ProjPredEngineLegacy final : public ProjPredEngine
|
||||
template<class EngineTrait = traits::SourceEngineTrait>
|
||||
class ProjPredEngineLegacy final : public ProjPredEngineInterface
|
||||
{
|
||||
public:
|
||||
explicit ProjPredEngineLegacy(float gravity_constant, float simulation_time_step, float maximum_simulation_time,
|
||||
float distance_tolerance);
|
||||
explicit ProjPredEngineLegacy(const float gravity_constant, const float simulation_time_step,
|
||||
const float maximum_simulation_time, const float distance_tolerance)
|
||||
: m_gravity_constant(gravity_constant), m_simulation_time_step(simulation_time_step),
|
||||
m_maximum_simulation_time(maximum_simulation_time), m_distance_tolerance(distance_tolerance)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
std::optional<Vector3<float>> maybe_calculate_aim_point(const Projectile& projectile,
|
||||
const Target& target) const override;
|
||||
const Target& target) const override
|
||||
{
|
||||
for (float time = 0.f; time < m_maximum_simulation_time; time += m_simulation_time_step)
|
||||
{
|
||||
const auto predicted_target_position =
|
||||
EngineTrait::predict_target_position(target, time, m_gravity_constant);
|
||||
|
||||
const auto projectile_pitch =
|
||||
maybe_calculate_projectile_launch_pitch_angle(projectile, predicted_target_position);
|
||||
|
||||
if (!projectile_pitch.has_value()) [[unlikely]]
|
||||
continue;
|
||||
|
||||
if (!is_projectile_reached_target(predicted_target_position, projectile, projectile_pitch.value(),
|
||||
time))
|
||||
continue;
|
||||
|
||||
return EngineTrait::calc_viewpoint_from_angles(projectile, predicted_target_position, projectile_pitch);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
private:
|
||||
const float m_gravity_constant;
|
||||
@@ -28,13 +54,56 @@ namespace omath::projectile_prediction
|
||||
const float m_maximum_simulation_time;
|
||||
const float m_distance_tolerance;
|
||||
|
||||
// Realization of this formula:
|
||||
// https://stackoverflow.com/questions/54917375/how-to-calculate-the-angle-to-shoot-a-bullet-in-order-to-hit-a-moving-target
|
||||
/*
|
||||
\[
|
||||
\theta \;=\; \arctan\!\Biggl(
|
||||
\frac{%
|
||||
v^{2}\;\pm\;\sqrt{\,v^{4}-g\!\left(gx^{2}+2yv^{2}\right)\,}
|
||||
}{%
|
||||
gx
|
||||
}\Biggr)
|
||||
\]
|
||||
*/
|
||||
[[nodiscard]]
|
||||
std::optional<float>
|
||||
maybe_calculate_projectile_launch_pitch_angle(const Projectile& projectile,
|
||||
const Vector3<float>& target_position) const noexcept;
|
||||
const Vector3<float>& target_position) const noexcept
|
||||
{
|
||||
const auto bullet_gravity = m_gravity_constant * projectile.m_gravity_scale;
|
||||
|
||||
if (bullet_gravity == 0.f)
|
||||
return EngineTrait::calc_direct_pitch_angle(projectile.m_origin, target_position);
|
||||
|
||||
const auto delta = target_position - projectile.m_origin;
|
||||
|
||||
const auto distance2d = EngineTrait::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 * EngineTrait::get_vector_height_coordinate(delta) * launch_speed_sqr);
|
||||
|
||||
if (root < 0.0f) [[unlikely]]
|
||||
return std::nullopt;
|
||||
|
||||
root = std::sqrt(root);
|
||||
const float angle = std::atan((launch_speed_sqr - root) / (bullet_gravity * distance2d));
|
||||
|
||||
return angles::radians_to_degrees(angle);
|
||||
}
|
||||
[[nodiscard]]
|
||||
bool is_projectile_reached_target(const Vector3<float>& target_position, const Projectile& projectile,
|
||||
float pitch, float time) const noexcept;
|
||||
const float pitch, const float time) const noexcept
|
||||
{
|
||||
const auto yaw = EngineTrait::calc_direct_yaw_angle(projectile.m_origin, target_position);
|
||||
const auto projectile_position =
|
||||
EngineTrait::predict_projectile_position(projectile, pitch, yaw, time, m_gravity_constant);
|
||||
|
||||
return projectile_position.distance_to(target_position) <= m_distance_tolerance;
|
||||
}
|
||||
};
|
||||
} // namespace omath::projectile_prediction
|
||||
|
||||
@@ -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{};
|
||||
|
||||
@@ -10,17 +10,6 @@ namespace omath::projectile_prediction
|
||||
class Target final
|
||||
{
|
||||
public:
|
||||
[[nodiscard]]
|
||||
constexpr Vector3<float> predict_position(const float time, const float gravity) const noexcept
|
||||
{
|
||||
auto predicted = m_origin + m_velocity * time;
|
||||
|
||||
if (m_is_airborne)
|
||||
predicted.z -= gravity * (time*time) * 0.5f;
|
||||
|
||||
return predicted;
|
||||
}
|
||||
|
||||
Vector3<float> m_origin;
|
||||
Vector3<float> m_velocity;
|
||||
bool m_is_airborne{};
|
||||
|
||||
@@ -142,7 +142,7 @@ namespace omath
|
||||
[[nodiscard]] Vector2 normalized() const noexcept
|
||||
{
|
||||
const Type len = length();
|
||||
return len > 0.f ? *this / len : *this;
|
||||
return len > static_cast<Type>(0) ? *this / len : *this;
|
||||
}
|
||||
#endif
|
||||
[[nodiscard]] constexpr Type length_sqr() const noexcept
|
||||
@@ -153,8 +153,8 @@ namespace omath
|
||||
constexpr Vector2& abs() noexcept
|
||||
{
|
||||
// FIXME: Replace with std::abs, if it will become constexprable
|
||||
x = x < 0 ? -x : x;
|
||||
y = y < 0 ? -y : y;
|
||||
x = x < static_cast<Type>(0) ? -x : x;
|
||||
y = y < static_cast<Type>(0) ? -y : y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -202,6 +202,11 @@ namespace omath
|
||||
{
|
||||
return {static_cast<float>(this->x), static_cast<float>(this->y)};
|
||||
}
|
||||
[[nodiscard]]
|
||||
static Vector3<float> from_im_vec2(const ImVec2& other) noexcept
|
||||
{
|
||||
return {static_cast<Type>(other.x), static_cast<Type>(other.y)};
|
||||
}
|
||||
#endif
|
||||
};
|
||||
} // namespace omath
|
||||
|
||||
@@ -151,7 +151,7 @@ namespace omath
|
||||
{
|
||||
const Type len = this->length();
|
||||
|
||||
return len != 0 ? *this / len : *this;
|
||||
return len != static_cast<Type>(0) ? *this / len : *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] Type length_2d() const noexcept
|
||||
@@ -221,7 +221,7 @@ namespace omath
|
||||
{
|
||||
const auto bottom = length() * other.length();
|
||||
|
||||
if (bottom == 0.f)
|
||||
if (bottom == static_cast<Type>(0))
|
||||
return std::unexpected(Vector3Error::IMPOSSIBLE_BETWEEN_ANGLE);
|
||||
|
||||
return Angle<float, 0.f, 180.f, AngleFlags::Clamped>::from_radians(std::acos(dot(other) / bottom));
|
||||
@@ -230,7 +230,7 @@ namespace omath
|
||||
[[nodiscard]] bool is_perpendicular(const Vector3& other) const noexcept
|
||||
{
|
||||
if (const auto angle = angle_between(other))
|
||||
return angle->as_degrees() == 90.f;
|
||||
return angle->as_degrees() == static_cast<Type>(90);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace omath
|
||||
constexpr Vector4(const Type& x, const Type& y, const Type& z, const Type& w): Vector3<Type>(x, y, z), w(w)
|
||||
{
|
||||
}
|
||||
constexpr Vector4() noexcept : Vector3<Type>(), w(0) {};
|
||||
constexpr Vector4() noexcept: Vector3<Type>(), w(static_cast<Type>(0)) {};
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr bool operator==(const Vector4& other) const noexcept
|
||||
@@ -169,6 +169,12 @@ namespace omath
|
||||
static_cast<float>(w),
|
||||
};
|
||||
}
|
||||
[[nodiscard]]
|
||||
static Vector4<float> from_im_vec4(const ImVec4& other) noexcept
|
||||
{
|
||||
return {static_cast<Type>(other.x), static_cast<Type>(other.y), static_cast<Type>(other.z)};
|
||||
}
|
||||
}
|
||||
#endif
|
||||
};
|
||||
};
|
||||
} // namespace omath
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
#include "omath/projectile_prediction/proj_pred_engine_legacy.hpp"
|
||||
#include <cmath>
|
||||
#include <omath/angles.hpp>
|
||||
|
||||
namespace omath::projectile_prediction
|
||||
{
|
||||
ProjPredEngineLegacy::ProjPredEngineLegacy(const float gravity_constant, const float simulation_time_step,
|
||||
const float maximum_simulation_time, const float distance_tolerance)
|
||||
: m_gravity_constant(gravity_constant), m_simulation_time_step(simulation_time_step),
|
||||
m_maximum_simulation_time(maximum_simulation_time), m_distance_tolerance(distance_tolerance)
|
||||
{
|
||||
}
|
||||
|
||||
std::optional<Vector3<float>> ProjPredEngineLegacy::maybe_calculate_aim_point(const Projectile& projectile,
|
||||
const Target& target) const
|
||||
{
|
||||
for (float time = 0.f; time < m_maximum_simulation_time; time += m_simulation_time_step)
|
||||
{
|
||||
const auto predicted_target_position = target.predict_position(time, m_gravity_constant);
|
||||
|
||||
const auto projectile_pitch =
|
||||
maybe_calculate_projectile_launch_pitch_angle(projectile, predicted_target_position);
|
||||
|
||||
if (!projectile_pitch.has_value()) [[unlikely]]
|
||||
continue;
|
||||
|
||||
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 std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<float> ProjPredEngineLegacy::maybe_calculate_projectile_launch_pitch_angle(
|
||||
const Projectile& projectile, const Vector3<float>& target_position) const noexcept
|
||||
{
|
||||
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_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);
|
||||
|
||||
if (root < 0.0f) [[unlikely]]
|
||||
return std::nullopt;
|
||||
|
||||
root = std::sqrt(root);
|
||||
const float angle = std::atan((launch_speed_sqr - root) / (bullet_gravity * distance2d));
|
||||
|
||||
return angles::radians_to_degrees(angle);
|
||||
}
|
||||
|
||||
bool ProjPredEngineLegacy::is_projectile_reached_target(const Vector3<float>& target_position,
|
||||
const Projectile& projectile, const float pitch,
|
||||
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);
|
||||
|
||||
return projectile_position.distance_to(target_position) <= m_distance_tolerance;
|
||||
}
|
||||
} // namespace omath::projectile_prediction
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user