mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-11 07:12:02 +00:00
Added VelIntercept.
- Uses the same code as Thing_ProjectileIntercept to aim and move the projectile. - targ: The actor the caller will aim at. - speed: Used for calculating the new angle/pitch and adjusts the speed accordingly. Default is -1 (current speed). - aimpitch: If true, aims the pitch in the travelling direction. Default is true. - oldvel: If true, does not replace the velocity with the specified speed. Default is false. - Split the code from Thing_ProjectileIntercept and have that function call VelIntercept.
This commit is contained in:
parent
849d110f10
commit
6a8b0df4ba
2 changed files with 83 additions and 50 deletions
132
src/p_things.cpp
132
src/p_things.cpp
|
@ -163,6 +163,85 @@ bool P_Thing_Move (int tid, AActor *source, int mapspot, bool fog)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// [MC] Was part of P_Thing_Projectile, now its own function for use in ZScript.
|
||||||
|
// Aims mobj at targ based on speed and targ's velocity.
|
||||||
|
void VelIntercept(AActor *targ, AActor *mobj, double speed, bool aimpitch = false, bool oldvel = false)
|
||||||
|
{
|
||||||
|
if (targ == nullptr || mobj == nullptr) return;
|
||||||
|
|
||||||
|
if (speed > 0 && !targ->Vel.isZero())
|
||||||
|
{
|
||||||
|
DVector3 aim = mobj->Vec3To(targ);
|
||||||
|
aim.Z += targ->Height / 2;
|
||||||
|
// Aiming at the target's position some time in the future
|
||||||
|
// is basically just an application of the law of sines:
|
||||||
|
// a/sin(A) = b/sin(B)
|
||||||
|
// Thanks to all those on the notgod phorum for helping me
|
||||||
|
// with the math. I don't think I would have thought of using
|
||||||
|
// trig alone had I been left to solve it by myself.
|
||||||
|
|
||||||
|
bool nolead = false;
|
||||||
|
DVector3 tvel = targ->Vel;
|
||||||
|
if (!(targ->flags & MF_NOGRAVITY) && targ->waterlevel < 3)
|
||||||
|
{ // If the target is subject to gravity and not underwater,
|
||||||
|
// assume that it isn't moving vertically. Thanks to gravity,
|
||||||
|
// even if we did consider the vertical component of the target's
|
||||||
|
// velocity, we would still miss more often than not.
|
||||||
|
tvel.Z = 0.0;
|
||||||
|
nolead = !!(targ->Vel.X == 0 && targ->Vel.Y == 0);
|
||||||
|
}
|
||||||
|
if (!nolead)
|
||||||
|
{
|
||||||
|
double dist = aim.Length();
|
||||||
|
double targspeed = tvel.Length();
|
||||||
|
double ydotx = -aim | tvel;
|
||||||
|
double a = g_acos(clamp(ydotx / targspeed / dist, -1.0, 1.0));
|
||||||
|
double multiplier = double(pr_leadtarget.Random2())*0.1 / 255 + 1.1;
|
||||||
|
double sinb = -clamp(targspeed*multiplier * g_sin(a) / speed, -1.0, 1.0);
|
||||||
|
DVector3 prevel = mobj->Vel;
|
||||||
|
// Use the cross product of two of the triangle's sides to get a
|
||||||
|
// rotation vector.
|
||||||
|
DVector3 rv(tvel ^ aim);
|
||||||
|
// The vector must be normalized.
|
||||||
|
rv.MakeUnit();
|
||||||
|
// Now combine the rotation vector with angle b to get a rotation matrix.
|
||||||
|
DMatrix3x3 rm(rv, g_cos(g_asin(sinb)), sinb);
|
||||||
|
// And multiply the original aim vector with the matrix to get a
|
||||||
|
// new aim vector that leads the target.
|
||||||
|
DVector3 aimvec = rm * aim;
|
||||||
|
// And make the projectile follow that vector at the desired speed.
|
||||||
|
mobj->Vel = aimvec * (speed / dist);
|
||||||
|
mobj->AngleFromVel();
|
||||||
|
if (oldvel)
|
||||||
|
{
|
||||||
|
mobj->Vel = prevel;
|
||||||
|
}
|
||||||
|
if (aimpitch) // [MC] Ripped right out of A_FaceMovementDirection
|
||||||
|
{
|
||||||
|
const DVector2 velocity = mobj->Vel.XY();
|
||||||
|
mobj->Angles.Pitch = -VecToAngle(velocity.Length(), mobj->Vel.Z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mobj->Angles.Yaw = mobj->AngleTo(targ);
|
||||||
|
mobj->Vel = aim.Resized(speed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(AActor, VelIntercept)
|
||||||
|
{
|
||||||
|
PARAM_SELF_PROLOGUE(AActor);
|
||||||
|
PARAM_OBJECT_NOT_NULL(targ, AActor);
|
||||||
|
PARAM_FLOAT_DEF(speed);
|
||||||
|
PARAM_BOOL_DEF(aimpitch);
|
||||||
|
PARAM_BOOL_DEF(oldvel);
|
||||||
|
if (speed < 0) speed = self->Speed;
|
||||||
|
VelIntercept(targ, self, speed, aimpitch, oldvel);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool P_Thing_Projectile (int tid, AActor *source, int type, const char *type_name, DAngle angle,
|
bool P_Thing_Projectile (int tid, AActor *source, int type, const char *type_name, DAngle angle,
|
||||||
double speed, double vspeed, int dest, AActor *forcedest, int gravity, int newtid,
|
double speed, double vspeed, int dest, AActor *forcedest, int gravity, int newtid,
|
||||||
bool leadTarget)
|
bool leadTarget)
|
||||||
|
@ -244,58 +323,11 @@ bool P_Thing_Projectile (int tid, AActor *source, int type, const char *type_nam
|
||||||
}
|
}
|
||||||
mobj->target = spot;
|
mobj->target = spot;
|
||||||
|
|
||||||
if (targ != NULL)
|
if (targ != nullptr)
|
||||||
{
|
{
|
||||||
DVector3 aim = mobj->Vec3To(targ);
|
if (leadTarget)
|
||||||
aim.Z += targ->Height / 2;
|
|
||||||
|
|
||||||
if (leadTarget && speed > 0 && !targ->Vel.isZero())
|
|
||||||
{
|
{
|
||||||
// Aiming at the target's position some time in the future
|
VelIntercept(targ, mobj, speed);
|
||||||
// is basically just an application of the law of sines:
|
|
||||||
// a/sin(A) = b/sin(B)
|
|
||||||
// Thanks to all those on the notgod phorum for helping me
|
|
||||||
// with the math. I don't think I would have thought of using
|
|
||||||
// trig alone had I been left to solve it by myself.
|
|
||||||
|
|
||||||
DVector3 tvel = targ->Vel;
|
|
||||||
if (!(targ->flags & MF_NOGRAVITY) && targ->waterlevel < 3)
|
|
||||||
{ // If the target is subject to gravity and not underwater,
|
|
||||||
// assume that it isn't moving vertically. Thanks to gravity,
|
|
||||||
// even if we did consider the vertical component of the target's
|
|
||||||
// velocity, we would still miss more often than not.
|
|
||||||
tvel.Z = 0.0;
|
|
||||||
if (targ->Vel.X == 0 && targ->Vel.Y == 0)
|
|
||||||
{
|
|
||||||
goto nolead;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
double dist = aim.Length();
|
|
||||||
double targspeed = tvel.Length();
|
|
||||||
double ydotx = -aim | tvel;
|
|
||||||
double a = g_acos (clamp (ydotx / targspeed / dist, -1.0, 1.0));
|
|
||||||
double multiplier = double(pr_leadtarget.Random2())*0.1/255+1.1;
|
|
||||||
double sinb = -clamp (targspeed*multiplier * g_sin(a) / speed, -1.0, 1.0);
|
|
||||||
|
|
||||||
// Use the cross product of two of the triangle's sides to get a
|
|
||||||
// rotation vector.
|
|
||||||
DVector3 rv(tvel ^ aim);
|
|
||||||
// The vector must be normalized.
|
|
||||||
rv.MakeUnit();
|
|
||||||
// Now combine the rotation vector with angle b to get a rotation matrix.
|
|
||||||
DMatrix3x3 rm(rv, g_cos(g_asin(sinb)), sinb);
|
|
||||||
// And multiply the original aim vector with the matrix to get a
|
|
||||||
// new aim vector that leads the target.
|
|
||||||
DVector3 aimvec = rm * aim;
|
|
||||||
// And make the projectile follow that vector at the desired speed.
|
|
||||||
mobj->Vel = aimvec * (speed / dist);
|
|
||||||
mobj->AngleFromVel();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
nolead:
|
|
||||||
mobj->Angles.Yaw = mobj->AngleTo(targ);
|
|
||||||
mobj->Vel = aim.Resized (speed);
|
|
||||||
}
|
}
|
||||||
if (mobj->flags2 & MF2_SEEKERMISSILE)
|
if (mobj->flags2 & MF2_SEEKERMISSILE)
|
||||||
{
|
{
|
||||||
|
|
|
@ -685,6 +685,7 @@ class Actor : Thinker native
|
||||||
native clearscope vector2 Vec2Angle(double length, double angle, bool absolute = false) const;
|
native clearscope vector2 Vec2Angle(double length, double angle, bool absolute = false) const;
|
||||||
native clearscope vector2 Vec2Offset(double x, double y, bool absolute = false) const;
|
native clearscope vector2 Vec2Offset(double x, double y, bool absolute = false) const;
|
||||||
native clearscope vector3 Vec2OffsetZ(double x, double y, double atz, bool absolute = false) const;
|
native clearscope vector3 Vec2OffsetZ(double x, double y, double atz, bool absolute = false) const;
|
||||||
|
native void VelIntercept(Actor targ, double speed = -1, bool aimpitch = true, bool oldvel = false);
|
||||||
native void VelFromAngle(double speed = 0, double angle = 0);
|
native void VelFromAngle(double speed = 0, double angle = 0);
|
||||||
native void Vel3DFromAngle(double speed, double angle, double pitch);
|
native void Vel3DFromAngle(double speed, double angle, double pitch);
|
||||||
native void Thrust(double speed = 0, double angle = 0);
|
native void Thrust(double speed = 0, double angle = 0);
|
||||||
|
|
Loading…
Reference in a new issue