Some background: The sport I am attempting to implement this code in is Quake 2. Based mostly on posts right here and elsewhere, I discovered and applied the mandatory ballistics code, and it really works… often. For some motive, it tends to overlook the goal when the angle is bigger than 33 levels. Additional, there are a number of weapons which have a better preliminary vertical velocity, and I do not know alter the calculations to cope with this.
This is an instance of a weapon firing operate with the elevated vertical velocity that throws off the ballistics calculations (inflicting the projectile to fly over the goal):
void fire_lance (edict_t *self, vec3_t begin, vec3_t aimdir, int harm, int burn_damage, float velocity, float size) {
edict_t *lance;
// entity made a sound, used to alert monsters
self->lastsound = degree.framenum;
// spawn lance entity
lance = G_Spawn();
VectorCopy (begin, lance->s.origin);
lance->movetype = MOVETYPE_TOSS;
lance->clipmask = MASK_SHOT;
lance->strong = SOLID_BBOX;
lance->s.modelindex = gi.modelindex("fashions/objects/javelin/tris.md2");
VectorSet(lance->minutes, -4, -4, 4);
VectorSet(lance->maxs, 4, 4, 4);
lance->proprietor = self;
lance->assume = lance_think;
lance->contact = lance_touch;
lance->dmg_radius = size;
lance->dmg = harm;
lance->radius_dmg = burn_damage;
lance->classname = "lance";
lance->delay = degree.time + 10.0;
gi.linkentity (lance);
lance->nextthink = degree.time + FRAMETIME;
vectoangles(aimdir, lance->s.angles);
// alter velocity
VectorScale (aimdir, velocity, lance->velocity);
lance->velocity[2] += 300;
}
This is the ballistics code (see under). The primary operate calculates the gap on the horizontal and vertical airplane. I’ve tried two alternative ways of calculating this, and it does not make a lot of a distinction. The second operate returns the perfect pitch to strike the goal.
void CalculateDisplacement(vec3_t startAngles, vec3_t startPos, vec3_t endPos, float *horizontal, float *vertical)
{
vec3_t v, xy_v, up;
VectorSubtract(endPos, startPos, v);
*vertical = v[2];
AngleVectors(startAngles, NULL, NULL, up);
ProjectOnPlane(xy_v, v, up);
*horizontal = VectorLength(xy_v);
}
// returns the perfect pitch angle to hit an enemy with a projectile with a set velocity of v
//FIXME: the calculation tends to overlook the mark when enemy is much away and when the brief angle is >33 levels
// it additionally misses when the vertical projectile velocity is completely different from horizontal velocity
float BOT_DMclass_ThrowingPitch1(edict_t* self, float v)
{
vec3_t offset, ahead, proper, begin;
VectorSet(offset, 8, 8, self->viewheight - 8);
AngleVectors(self->client->v_angle, ahead, proper, NULL);
P_ProjectSource(self->consumer, self->s.origin, offset, ahead, proper, begin);
float g = sv_gravity->worth;
float d;// = Get2dDistance(begin, self->enemy->s.origin);//Horizontal distance to the goal.
float h;// = self->enemy->s.origin[2] - begin[2]; //Vertical distinction between the projectile's preliminary top and the goal top.
CalculateDisplacement(self->s.angles, self->s.origin, self->enemy->s.origin, &d, &h);
double discriminant = pow(v, 4) - g * (g * pow(d, 2) + (2 * h * pow(v, 2)));
if (discriminant <= 0)
{
gi.dprintf("%s: goal cannot be reached @ %fn", __func__, d);
return -999; // goal cannot be reached
}
float angle1 = atan((-pow(v, 2) + sqrt(discriminant)) / (-g * d)) * (180 / M_PI);
float angle2 = atan((-pow(v, 2) - sqrt(discriminant)) / (-g * d)) * (180 / M_PI);
angle1 *= -1;
angle2 *= -1;
if (angle1 < -33)
angle1 -= 3; // small adjustment for far-away targets that have a tendency to return up brief
//if (angle1 < -33) // use excessive angle for far-away targets
// return angle2;//FIXME: have to test vertical clearance earlier than doing this, in any other case we hit the sky!
//else
return angle1;
}
My math abilities aren’t sturdy, so when you’ve got any concepts, please embrace code modifications or pseudocode, thanks!