Skip to content

Commit

Permalink
Make homing projectiles travel at a constant horizontal speed.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Cyp committed Dec 25, 2011
1 parent 01e8e2e commit e727873
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 2 deletions.
10 changes: 10 additions & 0 deletions lib/gamelib/gtime.h
Expand Up @@ -24,6 +24,9 @@
#ifndef _gtime_h
#define _gtime_h

#include "lib/framework/vector.h"


struct NETQUEUE;
struct Rational;

Expand Down Expand Up @@ -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.
Expand Down
19 changes: 17 additions & 2 deletions src/projectile.cpp
Expand Up @@ -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:
Expand Down

0 comments on commit e727873

Please sign in to comment.