News:

Come Chat with us live! Learn how HERE!

Main Menu

Trapper prediction

Started by Redman, September 18, 2009, 09:51:43 PM

Redman

Hello.

I'm trying to make a little mod for my server. I started with new buildable. It's normal trapper, but it kills.
The problem is I want to remove its prediction. I really don't know how this piece of code works, so i'm asking your for help :)

//==================================================================================

#define ARET_ACCURACY 10 // lower is better

/*
================
Aret_FireOnEnemy

Used by Aret_Think to fire at enemy
================
*/
void Aret_FireOnEnemy( gentity_t *self, int firespeed, float range )
{
 gentity_t *enemy = self->enemy;
 vec3_t    dirToTarget;
 vec3_t    halfAcceleration, thirdJerk;
 float     distanceToTarget = BG_FindRangeForBuildable( self->s.modelindex );
 int       lowMsec = 0;
 int       highMsec = (int)( (
   ( ( distanceToTarget * ARETM_SPEED ) +
     ( distanceToTarget * BG_FindSpeedForClass( enemy->client->ps.stats[ STAT_PCLASS ] ) ) ) /
   ( LOCKBLOB_SPEED * ARETM_SPEED ) ) * 1000.0f );
   
 VectorScale( enemy->acceleration, 1.0f / 2.0f, halfAcceleration );
 VectorScale( enemy->jerk, 1.0f / 3.0f, thirdJerk );

 // highMsec and lowMsec can only move toward
 // one another, so the loop must terminate
 while( highMsec - lowMsec > ARET_ACCURACY )
 {
   int   partitionMsec = ( highMsec + lowMsec ) / 2;
   float time = (float)partitionMsec / 1000.0f;
   float projectileDistance = ARETM_SPEED * time;

   VectorMA( enemy->s.pos.trBase, time, enemy->s.pos.trDelta, dirToTarget );
   VectorMA( dirToTarget, time * time, halfAcceleration, dirToTarget );
   VectorMA( dirToTarget, time * time * time, thirdJerk, dirToTarget );
   VectorSubtract( dirToTarget, self->s.pos.trBase, dirToTarget );
   distanceToTarget = VectorLength( dirToTarget );

   if( projectileDistance < distanceToTarget )
     lowMsec = partitionMsec;
   else if( projectileDistance > distanceToTarget )
     highMsec = partitionMsec;
   else if( projectileDistance == distanceToTarget )
     break; // unlikely to happen
 }

 VectorNormalize( dirToTarget );
 vectoangles( dirToTarget, self->turretAim );

 //fire at target
 FireWeapon( self );
 G_SetBuildableAnim( self, BANIM_ATTACK1, qfalse );
 self->count = level.time + firespeed;
}


(note: ARETM_* means its missile, ARET_* the buildable)

Thanks for reading.

gimhael

#1
The key is the loop. It tries to predict the time and position where the trapper projectile hits the enemy if it keeps moving/accelerating in the same way.
It is basically a binary search which checks how far will the enemy be from the trapper at time <time>. If this distance is larger than the distance of the trapper projectile, try a later time, if it is smaller try an earlier time. If it is equal, we found our target.


  while( highMsec - lowMsec > ARET_ACCURACY )
  {
    // always consider the time in the middle of the interval
    int   partitionMsec = ( highMsec + lowMsec ) / 2;
    float time = (float)partitionMsec / 1000.0f;

    // the projectile moves at constant speed ARETM_SPEED, so it's distance will be ARETM_SPEED * time
    float projectileDistance = ARETM_SPEED * time;

    // the enemy may accelerate, so use the speed, acceleration and jerk to predict it's position in dirToTarget
    VectorMA( enemy->s.pos.trBase, time, enemy->s.pos.trDelta, dirToTarget );
    VectorMA( dirToTarget, time * time, halfAcceleration, dirToTarget );
    VectorMA( dirToTarget, time * time * time, thirdJerk, dirToTarget );

    // Compute the difference vector and calculate it's length to find the distance of the enemy
    VectorSubtract( dirToTarget, self->s.pos.trBase, dirToTarget );
    distanceToTarget = VectorLength( dirToTarget );

    if( projectileDistance < distanceToTarget )
      // the enemy is too far away, we have to find a later time
      lowMsec = partitionMsec;
    else if( projectileDistance > distanceToTarget )
      // the enemy is too near, we have to find an earlier time
      highMsec = partitionMsec;
    else if( projectileDistance == distanceToTarget )
      // GOTCHA!
      break; // unlikely to happen
  }


The rest is just starting the projectile:

  // store the direction for the projectile
  VectorNormalize( dirToTarget );
  vectoangles( dirToTarget, self->turretAim );

  //fire at target
  FireWeapon( self );
  // start the attack animation
  G_SetBuildableAnim( self, BANIM_ATTACK1, qfalse );
  // remember time for next shot
  self->count = level.time + firespeed;


So if you want to change the prediction, just change the 3 VectorMA instructions. If you keep just the first, you get a simple linear prediction, or you could use VectorCopy(enemy->s.pos.trBase, dirToTarget) to have no prediction at all.

Redman

    //VectorMA( enemy->s.pos.trBase, time, enemy->s.pos.trDelta, dirToTarget );
    //VectorMA( dirToTarget, time * time, halfAcceleration, dirToTarget );
    //VectorMA( dirToTarget, time * time * time, thirdJerk, dirToTarget );
   
    VectorSubtract( dirToTarget, self->s.pos.trBase, dirToTarget );
    distanceToTarget = VectorLength( dirToTarget );
    VectorCopy(enemy->s.pos.trBase, dirToTarget);


I think I didn't understand you. In game when it saw me it started shooting somewhere at wall. It killed my egg :( (BTW. How to make projectiles don't damage aliens and their buildings?)