Make homing projectiles travel at a constant horizontal speed.
Homing projectiles previously behaved like expanding circles, where the projectile was drawn at the closest point on the circle to the target. Which meant that if the target was fast, moving at right angles to the direction of the projectile, the projectile would move fast, too (and would not be travelling in the direction it was facing). Homing projectiles now go at a constant speed towards the target, using target prediction. To test the target prediction, set the projectile speed to something close to 700 (same as a VTOL), and try to get the VTOL to escape.master
parent
01e8e2ebd4
commit
e727873581
|
@ -24,6 +24,9 @@
|
|||
#ifndef _gtime_h
|
||||
#define _gtime_h
|
||||
|
||||
#include "lib/framework/vector.h"
|
||||
|
||||
|
||||
struct NETQUEUE;
|
||||
struct Rational;
|
||||
|
||||
|
@ -173,6 +176,13 @@ static inline int32_t gameTimeAdjustedAverage(int numerator, int denominator)
|
|||
{
|
||||
return quantiseFraction(numerator, GAME_TICKS_PER_SEC*denominator, gameTime + deltaGameTime, gameTime);
|
||||
}
|
||||
/// Returns the numerator/denominator times deltaGameTime, converted to seconds. The return value is rounded up or down, such that it is exactly right on average.
|
||||
static inline Vector3i gameTimeAdjustedAverage(Vector3i numerator, int denominator)
|
||||
{
|
||||
return Vector3i(quantiseFraction(numerator.x, GAME_TICKS_PER_SEC*denominator, gameTime + deltaGameTime, gameTime),
|
||||
quantiseFraction(numerator.y, GAME_TICKS_PER_SEC*denominator, gameTime + deltaGameTime, gameTime),
|
||||
quantiseFraction(numerator.z, GAME_TICKS_PER_SEC*denominator, gameTime + deltaGameTime, gameTime));
|
||||
}
|
||||
|
||||
void sendPlayerGameTime(void); ///< Sends a GAME_GAME_TIME message with gameTime plus latency to our game queues.
|
||||
void recvPlayerGameTime(NETQUEUE queue); ///< Processes a GAME_GAME_TIME message.
|
||||
|
|
|
@ -755,11 +755,26 @@ static void proj_InFlightFunc(PROJECTILE *psProj, bool bIndirect)
|
|||
// If it's homing and has a target (not a miss)...
|
||||
// Home at the centre of the part that was visible when firing.
|
||||
psProj->dst = psProj->psDest->pos + Vector3i(0, 0, establishTargetHeight(psProj->psDest) - psProj->partVisible/2);
|
||||
DROID *targetDroid = castDroid(psProj->psDest);
|
||||
if (targetDroid != NULL)
|
||||
{
|
||||
// Do target prediction.
|
||||
Vector3i delta = psProj->dst - psProj->pos;
|
||||
int flightTime = iHypot(removeZ(delta)) * GAME_TICKS_PER_SEC / psStats->flightSpeed;
|
||||
psProj->dst += Vector3i(iSinCosR(targetDroid->sMove.moveDir, targetDroid->sMove.speed*flightTime / GAME_TICKS_PER_SEC), 0);
|
||||
}
|
||||
Vector3i delta = psProj->dst - psProj->src;
|
||||
}
|
||||
Vector3i delta = psProj->dst - psProj->pos;
|
||||
int targetDistance = std::max(iHypot(removeZ(delta)), 1);
|
||||
if (psProj->psDest == NULL && targetDistance < 10000)
|
||||
{
|
||||
psProj->dst = psProj->pos + delta*10; // Target missing, so just keep going in a straight line.
|
||||
}
|
||||
currentDistance = timeSoFar * psStats->flightSpeed / GAME_TICKS_PER_SEC;
|
||||
psProj->pos = psProj->src + delta * currentDistance/targetDistance;
|
||||
Vector3i step = gameTimeAdjustedAverage(delta * psStats->flightSpeed, targetDistance);
|
||||
psProj->pos += step;
|
||||
psProj->rot.direction = iAtan2(removeZ(delta));
|
||||
psProj->rot.pitch = iAtan2(delta.z, targetDistance);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
Loading…
Reference in New Issue