allow custom orbit rotations directions
This commit is contained in:
@@ -5,41 +5,76 @@
|
||||
#include <QVector2D>
|
||||
|
||||
// Orbit movement helper (REQ-SHP-ORBIT). Behaviors that keep a ship circling a
|
||||
// target (attack, repair, salvage, rally) feed the result of this function as the
|
||||
// movement intent destination instead of the target's center.
|
||||
// target (attack, repair, salvage, rally) supply an orbit center and radius via
|
||||
// the movement intent; MovementIntentSystem resolves the orbit direction and
|
||||
// destination using these helpers.
|
||||
namespace OrbitMath
|
||||
{
|
||||
// Lead angle (radians) by which the radial direction is rotated to produce
|
||||
// tangential motion. The fixed positive (counter-clockwise) sense makes the
|
||||
// orbit direction stable for the duration of orbiting a given target.
|
||||
// tangential motion. The orbit direction (sign of the rotation) is chosen
|
||||
// per ship by resolveOrbitSign from the ship's current velocity, so ships
|
||||
// approaching a target from different sides circle it in different senses
|
||||
// instead of all bunching on one side.
|
||||
constexpr float kOrbitLeadAngle_rad = 0.6f;
|
||||
|
||||
// Returns a destination on the orbit circle of `radius` around `target`. The
|
||||
// result always lies exactly `radius` from `target`, so steering toward it
|
||||
// both corrects the standoff distance and advances the ship tangentially.
|
||||
// A radius of zero or less falls back to the target center (legacy "approach
|
||||
// the target" behavior), e.g. when the ship has no tool range to orbit at.
|
||||
inline QVector2D computeOrbitDestination(const QVector2D& shipPos,
|
||||
const QVector2D& target, float radius)
|
||||
// Returns the orbit sense (+1 counter-clockwise, -1 clockwise) that matches
|
||||
// the ship's current movement around `center`, so steering reinforces the
|
||||
// motion the ship already has. When the velocity is nearly radial or near
|
||||
// zero (e.g. a head-on approach or a freshly spawned ship) the sense is
|
||||
// ill-defined; this is an unstable point the ship leaves within a tick or
|
||||
// two, so a deterministic fallback of +1 is returned.
|
||||
inline float resolveOrbitSign(const QVector2D& shipPos, const QVector2D& center,
|
||||
const QVector2D& velocity)
|
||||
{
|
||||
if (radius <= 0.0f) { return target; }
|
||||
const QVector2D radial = shipPos - center;
|
||||
const float radialLength = radial.length();
|
||||
const float velocityLength = velocity.length();
|
||||
if (radialLength < 1.0e-4f || velocityLength < 1.0e-4f)
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
QVector2D radial = shipPos - target;
|
||||
// z-component of radial x velocity, normalised to sin(angle) between them.
|
||||
const float cross = radial.x() * velocity.y() - radial.y() * velocity.x();
|
||||
const float sinAngle = cross / (radialLength * velocityLength);
|
||||
|
||||
constexpr float kRadialEpsilon = 1.0e-3f;
|
||||
if (std::abs(sinAngle) < kRadialEpsilon)
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
return (sinAngle > 0.0f) ? 1.0f : -1.0f;
|
||||
}
|
||||
|
||||
// Returns a destination on the orbit circle of `radius` around `center`. The
|
||||
// result always lies exactly `radius` from `center`, so steering toward it
|
||||
// both corrects the standoff distance and advances the ship tangentially.
|
||||
// `sign` selects the orbit sense (+1 counter-clockwise, -1 clockwise). A
|
||||
// radius of zero or less falls back to the center (legacy "approach the
|
||||
// target" behavior), e.g. when the ship has no tool range to orbit at.
|
||||
inline QVector2D computeOrbitDestination(const QVector2D& shipPos,
|
||||
const QVector2D& center, float radius,
|
||||
float sign = 1.0f)
|
||||
{
|
||||
if (radius <= 0.0f) { return center; }
|
||||
|
||||
QVector2D radial = shipPos - center;
|
||||
float length = radial.length();
|
||||
if (length < 1.0e-4f)
|
||||
{
|
||||
// Ship sits on the target; pick an arbitrary radial direction.
|
||||
// Ship sits on the center; pick an arbitrary radial direction.
|
||||
radial = QVector2D(1.0f, 0.0f);
|
||||
length = 1.0f;
|
||||
}
|
||||
const QVector2D radialDirection = radial / length;
|
||||
|
||||
const float cosLead = std::cos(kOrbitLeadAngle_rad);
|
||||
const float sinLead = std::sin(kOrbitLeadAngle_rad);
|
||||
const float leadAngle = sign * kOrbitLeadAngle_rad;
|
||||
const float cosLead = std::cos(leadAngle);
|
||||
const float sinLead = std::sin(leadAngle);
|
||||
const QVector2D leadDirection(
|
||||
radialDirection.x() * cosLead - radialDirection.y() * sinLead,
|
||||
radialDirection.x() * sinLead + radialDirection.y() * cosLead);
|
||||
|
||||
return target + radius * leadDirection;
|
||||
return center + radius * leadDirection;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user