Files
omath/source/ProjectilePredictor.cpp
2023-11-23 05:03:54 +03:00

74 lines
2.3 KiB
C++

//
// Created by vlad on 11/6/23.
//
#include "uml/ProjectilePredictor.h"
#include "uml/Vector3.h"
#include "uml/angles.h"
#include <cmath>
namespace uml::prediction
{
std::optional<Vector3>
ProjectilePredictor::CalculateViewAngles(const Vector3 &origin,
const Vector3 &target,
const Vector3 &targetVelocity,
float gravity,
float bulletSpeed,
float bulletGravity,
bool inAir)
{
constexpr float maxTime = 3.0f;
constexpr float timeStep = 0.01f;
for (float time = 0.0f; time <= maxTime; time += timeStep)
{
auto predPos = target + targetVelocity * time;
if (inAir)
predPos -= Vector3(0, 0, gravity * (time * time) * 0.5);
const auto angle = CalculateAimPitch(origin, predPos, bulletSpeed, bulletGravity);
if (!angle.has_value())
return std::nullopt;
const auto timeToHit = ProjectileTravelTime((predPos - origin).Length2D(), *angle, bulletSpeed);
if (timeToHit > time)
continue;
auto viewAngles = origin.ViewAngleTo(predPos);
viewAngles.x = angle.value();
return viewAngles;
}
return std::nullopt;
}
std::optional<float>
ProjectilePredictor::CalculateAimPitch(const Vector3 &origin, const Vector3 &target,
float bulletSpeed, float bulletGravity)
{
const auto delta = target - origin;
const auto distance = delta.Length2D();
float root = powf(bulletSpeed, 4) - bulletGravity * (bulletGravity * distance * distance + 2.0f * delta.z * powf(bulletSpeed, 2));
if (root < 0.0f) {
return std::nullopt;
}
root = sqrt(root);
float angle = atanf((powf(bulletSpeed, 2) - root) / (bulletGravity * distance)) * 180.f / (float)M_PI;
return -angle;
}
float ProjectilePredictor::ProjectileTravelTime(float distance, float angle, float speed)
{
return std::abs(distance / (std::cos(angles::DegToRad(angle)) * speed));
}
}