Jump to content
Sign in to follow this  
DrBobcat

More Math Woes

Recommended Posts

Although there are many artillery scripts out there that either utilize AI or clever "createVehicle"-ing, I believe it would be far more entertaining for the player if he or she was actually in the gunner's seat. I have been working non-stop on a script that does just that. A hint box offers the gunner data such as his current heading and angle, as well as the heading he'd need to take to be aiming at his target, the distance to his target, and the height difference between himself and the target. Obviously, the next thing needed is the angle at which the barrel must be in order for the shell to strike the target accurately.

My problem: I would like the shell to travel along a "perfect" parabola and strike a certain distance at a given angle. For example, at a thirty degree angle, I want the shell to land x meters away every single time. What kind of formula would I use? How would I go about this? The consideration of height can be dealt with at a later time.

I have already looked at many websites but have not been able to discover a solution to my specific problem. Here is a list of some of those sites....

Wikipedia

JBM

Formularium

Hyperphysics

Measurements Converter

An alternative solution may be to specify strict velocities based on the launch angle. Anyway, here is a copy of the main script...<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">if (!(local (_this select 0))) exitWith {};

_info =

{

_gun = _this select 0;

while {(alive _gun) && ((typeOf (vehicle player)) == "M119")} do

{

_xVec = (_gun weaponDirection "M119") select 0;

_yVec = (_gun weaponDirection "M119") select 1;

_zVec = (_gun weaponDirection "M119") select 2;

_tHead = ((getPos _gun select 0) - (getPos targ select 0)) atan2 ((getPos _gun select 1) - (getPos targ select 1));

_cHead = (_xVec atan2 _yVec);

if (_tHead < 0) then {_tHead = (180 - (abs _tHead))} else {_tHead = (180 + _tHead)};

if (_cHead < 0) then {_cHead = _cHead + 360};

_dist = ([getPos _gun select 0, getpos _gun select 1, 0] distance [getPos targ select 0, getPos targ select 1, 0]);

_hDiff = ((getPosASL _gun select 2) - (getPosASL targ select 2));

_ang = (asin ((9.8 * _dist) / 275000));

hint format ["Current Heading: %1 degrees\nCurrent Elevation: %2 degrees\n\nDistance-to-Target: %3 meters\nHeading-to-Target: %4 degrees\nElevation-to-target: %5 degrees\nHeight difference: %6 meters",_cHead,(_zVec * 90),_dist,_tHead,_ang,_hDiff];

sleep 0.01;

};

};

DRB_Art_Fired =

{

_gun = _this select 0;

_ammo = _this select 1;

_wAng = ((_gun weaponDirection "M119") select 0) atan2 ((_gun weaponDirection "M119") select 1);

_rounds = (_gun nearObjects [_ammo,1000]);

_round = objNull;

_located = false;

for [{_i = 0},{_i != (count _rounds)},{_i = _i + 1}] do

{

_round = _rounds select _i;

_rAng = (((vectorDir _round) select 0) atan2 ((vectorDir _round) select 1));

if ((abs (_wAng - _rAng)) <= 2) exitWith {_located = true};

sleep 0.001;

};

if (!(_located)) exitWith {};

switch (_gun getVariable "DRB_Art_Round_Type") do

{

case "he":

{

_he =

{

_round = _this select 0;

_spd = 275;

while {!(isNull _round)} do

{

_round setVelocity [_spd * (sin (getDir _round)),_spd * (cos (getDir _round)),(velocity _round select 2)];

sleep 0.01;

};

};

[_round] spawn _he;

};

case "illum":

{

_illum =

{

_round = _this select 0;

_time = 0;

_spd = 275;

_create = false;

_flare = objNull;

while {!(isNull _round)} do

{

_time = _time + 0.01;

_round setVelocity [_spd * (sin (getDir _round)),_spd * (cos (getDir _round)),(velocity _round select 2)];

if (((getPos _round select 2) <= 300) && (_time >= 2) && (!(_create))) then

{

_flare = "F_40mm_White" createVehicle [0,0,5000];

_create = true;

};

if (((getPos _round select 2) <= 150) && (_time >= 2) && (_create)) then

{

_rPos = (getPos _round);

deleteVehicle _round;

_burst = "weaponHolder" createVehicle [0,0,5000];

_burstB = "G_40mm_HE" createVehicle [0,0,5000];

{_x setPos _rPos} forEach [_burst,_burstB];

sleep 0.25;

_flare setPos _rPos;

{deleteVehicle _x} forEach [_burst,_burstB];

};

sleep 0.01;

};

};

[_round] spawn _illum;

};

case "prox":

{

_prox =

{

_round = _this select 0;

_time = 0;

_spd = 275;

_burst = "weaponHolder" createVehicle [0,0,5000];

while {!(isNull _round)} do

{

_time = _time + 0.01;

_round setVelocity [_spd * (sin (getDir _round)),_spd * (cos (getDir _round)),(velocity _round select 2)];

if (((getPos _round select 2) <= 50) && (_time >= 2)) then

{

_round setVelocity [0,0,0];

_rPos = getPos _round;

{_x setPos _rPos} forEach [_burst,_round];

sleep 0.25;

{deleteVehicle _x} forEach [_burst,_round];

};

sleep 0.01;

};

};

[_round] spawn _prox;

};

case "smoke":

{

_smoke =

{

_round = _this select 0;

_time = 0;

_spd = 275;

_create = false;

_burst = objNull;

_smokeA = objNull;

_smokeB = objNull;

_smokeC = objNull;

_smokeD = objNull;

_smokeE = objNull;

_smokeF = objNull;

_smokeG = objNull;

_smokeH = objNull;

_smokeI = objNull;

_smokeJ = objNull;

_smokeK = objNull;

_smokeL = objNull;

_smokeM = objNull;

_smokeN = objNull;

_smokeO = objNull;

_smokeP = objNull;

_smokeQ = objNull;

while {!(isNull _round)} do

{

_time = _time + 0.01;

_round setVelocity [_spd * (sin (getDir _round)),_spd * (cos (getDir _round)),(velocity _round select 2)];

if (((getPos _round select 2) <= 100) && (_time >= 2) && (!(_create))) then

{

_burst = "G_40mm_HE" createVehicle [0,0,5000];

_smokeA = "SmokeShell" createVehicle [0,0,5000];

_smokeB = "SmokeShell" createVehicle [0,0,5000];

_smokeC = "SmokeShell" createVehicle [0,0,5000];

_smokeD = "SmokeShell" createVehicle [0,0,5000];

_smokeE = "SmokeShell" createVehicle [0,0,5000];

_smokeF = "SmokeShell" createVehicle [0,0,5000];

_smokeG = "SmokeShell" createVehicle [0,0,5000];

_smokeH = "SmokeShell" createVehicle [0,0,5000];

_smokeI = "SmokeShell" createVehicle [0,0,5000];

_smokeJ = "SmokeShell" createVehicle [0,0,5000];

_smokeK = "SmokeShell" createVehicle [0,0,5000];

_smokeL = "SmokeShell" createVehicle [0,0,5000];

_smokeM = "SmokeShell" createVehicle [0,0,5000];

_smokeN = "SmokeShell" createVehicle [0,0,5000];

_smokeO = "SmokeShell" createVehicle [0,0,5000];

_smokeP = "SmokeShell" createVehicle [0,0,5000];

_smokeQ = "SmokeShell" createVehicle [0,0,5000];

_create = true;

};

if (((getPos _round select 2) <= 5) && (_time >= 2) && (_create)) then

{

_rPos = (getPos _round);

deleteVehicle _round;

_burst setPos [(_rPos select 0),(_rPos select 1),0];

_smokeA setPos [(_rPos select 0) + 5,(_rPos select 1),0];

_smokeB setPos [(_rPos select 0) - 5,(_rPos select 1),0];

_smokeC setPos [(_rPos select 0),(_rPos select 1) + 5,0];

_smokeD setPos [(_rPos select 0),(_rPos select 1) - 5,0];

_smokeE setPos [(_rPos select 0) + 3.75,(_rPos select 1) + 3.75,0];

_smokeF setPos [(_rPos select 0) + 3.75,(_rPos select 1) - 3.75,0];

_smokeG setPos [(_rPos select 0) - 3.75,(_rPos select 1) + 3.75,0];

_smokeH setPos [(_rPos select 0) - 3.75,(_rPos select 1) - 3.75,0];

_smokeI setPos [(_rPos select 0) + 10,(_rPos select 1),0];

_smokeJ setPos [(_rPos select 0) - 10,(_rPos select 1),0];

_smokeK setPos [(_rPos select 0),(_rPos select 1) + 10,0];

_smokeL setPos [(_rPos select 0),(_rPos select 1) - 10,0];

_smokeM setPos [(_rPos select 0) + 7.5,(_rPos select 1) + 7.5,0];

_smokeN setPos [(_rPos select 0) + 7.5,(_rPos select 1) - 7.5,0];

_smokeO setPos [(_rPos select 0) - 7.5,(_rPos select 1) + 7.5,0];

_smokeP setPos [(_rPos select 0) - 7.5,(_rPos select 1) - 7.5,0];

_smokeQ setPos [(_rPos select 0),(_rPos select 1),0];

};

sleep 0.01;

};

};

[_round] spawn _smoke;

};

};

_cam = "camera" camCreate (getPos _gun);

_cam cameraEffect ["INTERNAL","BACK"];

_cam camSetTarget _round;

_cam camCommit 0;

_time = 0;

_dist = 0;

while {!(isNull _round)} do

{

_time = _time + 0.01;

_dist = _gun distance _round;

titleText [(format ["%1 kmh \n%2 seconds \n%3 meters traveled \n%4 z velocity", speed _round, _time, _dist, (velocity _round select 2)]),"PLAIN DOWN"];

_cam camSetRelPos [0,-40,20];

_cam camCommit 0;

sleep 0.01;

};

sleep 5;

_cam cameraEffect ["TERMINATE","BACK"];

camDestroy _cam;

};

while {true} do

{

waitUntil {((typeOf (vehicle player)) == "M119")};

_gun = (vehicle player);

[_gun] spawn _info;

_fired = _gun addEventHandler ["fired","[_this select 0,_this select 4] spawn DRB_Art_Fired"];

_act1 = _gun addAction ["Change Type (HE)","DRB_ChangeRoundType.sqf","he",-1,false,true,""];

_act2 = _gun addAction ["Change Type (Illum)","DRB_ChangeRoundType.sqf","illum",-2,false,true,""];

_act3 = _gun addAction ["Change Type (Prox)","DRB_ChangeRoundType.sqf","prox",-3,false,true,""];

_act4 = _gun addAction ["Change Type (Smoke)","DRB_ChangeRoundType.sqf","smoke",-4,false,true,""];

waitUntil {((typeOf (vehicle player)) != "M119") || !(alive player)};

_gun removeEventHandler ["fired",_fired];

_gun removeAction _act1;

_gun removeAction _act2;

_gun removeAction _act3;

_gun removeAction _act4;

};

My thanks,

- dRb

Share this post


Link to post
Share on other sites

I think what you want is ballistic trajectories from the sound of it.  

Check out this website on ballistic trajectories.  About a third of the way down it starts a tutorial on General Ballistic Trajectories.  I would go through the entire page though just so you have a good idea as to what its talking about in the ballistic trajectories tutorial.

EDIT: I'm an idiot.  I totally missed that you already linked to this page.  Do you need some help understanding the math behind ballistics? You're going to need to set a velocity, and if I were you I would disregard friction for the most part. IIRC friction calculations require you to use calculus, so it may not be worth it unless you're good at that sort of thing. On the page I linked I would suggest using the Range and Time-of-Flight formulas, you should be able to make a decent model with just that data.

Share this post


Link to post
Share on other sites

@weegee_101

Lol..I nearly did the same thing smile_o.gif It is a good site. I only wish they provided the source code for the online calculations. Would make it much easier to understand, at least for me.

@DrBobCat

The trouble with using parabolas is, your going to have either very high or low elevations:

traj.jpg

The yellow plot uses an Arma round, the red is a standard parabola. Ok, so you won't always have to worry about a 600 meter high mountain between you and the target, most of the time. But the angle of attack, at the point of impact, compared to Arma, is considerable. Which increases the chances that your going to hit something else, before you reach your target?

You can go the opposite route, and fire at +45 degrees. But then the time of flight is dramatically increased. You could cheat. Half through the time to live of your shell. You could teleport it into position, so it reached the point of impact in good time, with the correct angle of attack.

I have a spreadsheet that plots a parabola over time, if you want that? I found that to be easy enough to transfer into Arma scripts. Although its nothing special.

But as for calculating time of flight, range and elevation e.t.c before plotting, I can't really help. I decided that parabolas were not suitable for what I wanted. So I never looked into it further. From what little I understood on hyperphysics, I think you have to use a combination of those equations, to obtain all the info you require.

For example. If you know the range, then you can calculate the time it takes. With both the range and the time, you can calculate the required elevation. But don't quote me of that, maths has never come easy to me sad_o.gif

Share this post


Link to post
Share on other sites

One artillery mod, released on these forums, actually fired shells from the guns using AI in a correct trajectory. To figure ou tthe correct angle the author had to calculate arma's air friction coefficient.

http://www.flashpoint1985.com/cgi-bin....t=68597

I believe that was the arty addon. You might have to poke around in the scripts for the math but maybe it'll give you some ideas.

EDIT: This other arty addon includes a superb tutorial on using linear regression parabolas to create indirect fire: http://www.armedassault.info/index.php?cat=addons&id=180

Share this post


Link to post
Share on other sites

Actually, and its been a while since I've done any of this, but the key is to know the angle and velocity you're firing at. If you know the angle and velocity (gravity is a constant 9.8m/s^2) you can some dirt simple trigonometry to find the range and the time to live. The equations are on that page, but I'll put them here:

Where R is range, v is the initial velocity, and a is angle,

R = (v^2 * sin2a)/9.8

and

Where T is time-to-live and v.sub.y is the initial horizontal velocity,

T = 2v.sub.y/9.8

To find v.sub.y, where v.sub.y is the initial horizontal velocity, v is the initial velocity, and a is the angle,

v.sub.y = v * sin(a)

Let me know if you have any questions.

Share this post


Link to post
Share on other sites

Doesn't work mate, you've got a huge air friction (drag) in ArmA, so regardless it won't be a parabola.

whistle.gif

Share this post


Link to post
Share on other sites
Quote[/b] ]One artillery mod, released on these forums, actually fired shells from the guns using AI in a correct trajectory.

There were a couple like that for OFP to.

Quote[/b] ]The equations are on that page, but I'll put them here

Thanks, it all helps.

Quote[/b] ]but the key is to know the angle and velocity you're firing at

Can't speak for DrBobcat, I'm not exactly sure what he wants. But most of the time, range and velocity are the only things you do know. You’re looking to find the correct elevation and time of flight.

Quote[/b] ] Doesn't work mate, you've got a huge air friction (drag) in ArmA, so regardless it won't be a parabola.

I think DrBobcat was talking about moving the object along the parabola using scripts, not the Arma engine. At least, that should be assumed, when talking about parabolas and Arma.

Share this post


Link to post
Share on other sites

Yes, I had thought of eliminating air drag entirely by using a formula similar to this...

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">forwardSpeedConstant = 285;

_zVel = (velocity round select 2);

while {!(isNull round)} do

{

    round setVelocity [(forwardSpeedConstant * (sin (getDir round))), (forwardSpeedConstant * (cos (getDir round))),_zVel];

    _zVel = _zVel - 0.35;

    sleep 0.01;

};

Note that 285 and 0.35 are arbitrary numbers that I have found comfortable. I believe this will force the round to drop at constant rate depending on its initial velocity, making a clean, smooth parabola, and will bypass air resistance altogether. However, this is not very realistic because the round will often accelerate past terminal velocity when launched from high angles. Additionally, the mathematical calculations needed to predict the launch angle of the shell will have to be different because gravity is ultimately being ignored as well.

Thoughts, anyone?

-dRb

Share this post


Link to post
Share on other sites
Can't speak for DrBobcat, I'm not exactly sure what he wants. But most of the time, range and velocity are the only things you do know. You’re looking to find the correct elevation and time of flight.

As long as you have two of the three you can find your required angle. Just use a right triangle and a cosine equation to find your proper firing angle.

Where a is the angle to fire, and b is the range and, c is the velocity,

a = cos(b/c)

Another thought is are you trying to actually have a visible round fly through the air? Why not just let the ArmA physics engine take over then? You'll get a more realistic shot with drag.

If you don't need to have a visible round, just take the time to live for the round and count down until you get to the impact time, and use the range calculations (with the heading) to select where the impact occurs.

Share this post


Link to post
Share on other sites
Quote[/b] ]Thoughts, anyone?

It might be better to use something that takes into account, the time passed between each cycle of the loop. If the game slows down at any point, it might throw your impact point off?

Quote[/b] ]Where a is the angle to fire, and b is the range and, c is the velocity,

a = cos(b/c)

Gaahh...I guess it was as simple as that, cheers. Makes sense now you mention it, given gravity as a constant. Not that it would have ever occurred to me sad_o.gif

Quote[/b] ]Another thought is are you trying to actually have a visible round fly through the air?  Why not just let the ArmA physics engine take over then?  You'll get a more realistic shot with drag.

As soon as you introduce drag. It becomes far more complex, when calculating a firing solution. There were always two problems; The time taken to determine the correct elevation and the amount of processing required.

My thoughts were to look for a compromise. Something that would give you a trajectory that resembles a real round, but only requires a few lines of scripts (like parabolas) to determine the required elevation to hit the target. Like I said, it would mean you have to handle the flight of each round yourself though.

Share this post


Link to post
Share on other sites
As soon as you introduce drag. It becomes far more complex, when calculating a firing solution. There were always two problems; The time taken to determine the correct elevation and the amount of processing required.

Very true. Since we don't know the actual drag coefficient in the ArmA engine it becomes even more difficult.

Share this post


Link to post
Share on other sites

The author of the script I posted above estimated the drag coefficient to be about -500 / 1000000 when plugged into the simplified deceleration equation of 'a = v^2 * k', k being the drag coefficient for an artillery shell (k/mass of shell). The actual implementation is in his readme file and is very helpful for making your own artillery calculations.

Share this post


Link to post
Share on other sites
Quote[/b] ]Very true.  Since we don't know the actual drag coefficient in the ArmA engine it becomes even more difficult.

I was sure that individual coefficients have been introduced in Arma, perhaps in one of the patches? But in OFP, I had to spend many hours using trial and error, to find something close enough to be of use.

@The_Captain

The point is, it still doesn’t offer a practical solution for things like AI Forward Observers. COC's Unified Artillery in OFP, used a neural network to calculate the impact point. Which so far, seems to be the best solution anyone has come up with for both OFP and Arma. Although the network had to be trained for each type of round, so it wasn't exactly open to everyone.

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
Sign in to follow this  

×