Skip to content

Commit a1cafef

Browse files
Nlaw - Update to use Missile Guidance Framework (#10034)
1 parent 2c4c7c2 commit a1cafef

10 files changed

Lines changed: 207 additions & 21 deletions

addons/nlaw/ACE_GuidanceConfig.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,9 @@ class EGVAR(missileguidance,SeekerTypes) {
1212
functionName = QFUNC(seeker);
1313
};
1414
};
15+
class EGVAR(missileguidance,NavigationTypes) {
16+
class GVAR(PLOS) {
17+
functionName = QFUNC(navigation);
18+
onFired = QFUNC(navigation_onFired);
19+
};
20+
};

addons/nlaw/CfgAmmo.hpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,8 @@ class CfgAmmo {
66
class ace_missileguidance {
77
enabled = 1;
88

9-
minDeflection = 0.0005; // Minium flap deflection for guidance
10-
maxDeflection = 0.01; // Maximum flap deflection for guidance
11-
incDeflection = 0.0005; // The incrmeent in which deflection adjusts.
9+
pitchRate = 5; // Minium flap deflection for guidance
10+
yawRate = 10; // Maximum flap deflection for guidance
1211

1312
canVanillaLock = 0; // Can this default vanilla lock? Only applicable to non-cadet mode
1413

@@ -19,6 +18,9 @@ class CfgAmmo {
1918
defaultSeekerLockMode = "LOBL";
2019
seekerLockModes[] = {"LOBL"};
2120

21+
defaultNavigationType = QGVAR(PLOS);
22+
navigationTypes[] = { QGVAR(PLOS) };
23+
2224
seekLastTargetPos = 0; // seek last target position [if seeker loses LOS of target, continue to last known pos]
2325
seekerAngle = 45; // Angle in front of the missile which can be searched
2426
seekerAccuracy = 1; // seeker accuracy multiplier

addons/nlaw/XEH_PREP.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@ PREP(attackProfile);
44
PREP(keyDown);
55
PREP(onFired);
66
PREP(seeker);
7+
PREP(navigation);
8+
PREP(navigation_onFired);

addons/nlaw/XEH_postInit.sqf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,11 @@ GVAR(pitchChange) = 0;
2222

2323
// Visual debuging, idealy used with a moving vehicle called "testTarget"
2424
#ifdef DRAW_NLAW_INFO
25+
GVAR(debug_firedPrediction) = [];
2526
addMissionEventHandler ["Draw3d", {
27+
// BLACK - On fired path prediction
28+
{ drawIcon3D _x; } forEach GVAR(debug_firedPrediction);
29+
2630
// GREEN - Draw an object called "testTarget"'s aim pos and 1 sec aimpos predicted by velocity
2731
if ((!isNil "testTarget") && {!isNull testTarget}) then {
2832
{

addons/nlaw/functions/fnc_attackProfile.sqf

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,13 @@
1818
*/
1919

2020
params ["_seekerTargetPos", "_args", "_attackProfileStateParams"];
21+
22+
#ifdef DRAW_NLAW_INFO
2123
_args params ["_firedEH", "_launchParams"];
2224
_launchParams params ["","_targetLaunchParams", "", "_attackProfile"];
2325
_targetLaunchParams params ["", "", "_launchPos"];
2426
_firedEH params ["","","","","","","_projectile"];
2527

26-
// Use seeker (if terminal)
27-
if (_seekerTargetPos isNotEqualTo [0,0,0]) exitWith {_seekerTargetPos};
28-
2928
_attackProfileStateParams params ["_startTime", "_startLOS", "_yawChange", "_pitchChange"];
3029
(_startLOS call CBA_fnc_vect2Polar) params ["", "_yaw", "_pitch"];
3130

@@ -36,14 +35,6 @@ private _flightTime = CBA_missionTime - _startTime;
3635
private _realYaw = _yaw + _yawChange * _flightTime;
3736
private _realPitch = _pitch + _pitchChange * _flightTime;
3837

39-
private _returnTargetPos = _launchPos vectorAdd ([_distanceFromLaunch, _realYaw, _realPitch] call CBA_fnc_polar2vect);
40-
41-
if (_attackProfile == QGVAR(overflyTopAttack)) then { // Add 2m height in OTA attack mode
42-
_returnTargetPos = _returnTargetPos vectorAdd [0,0,2];
43-
};
44-
45-
46-
#ifdef DRAW_NLAW_INFO
4738
drawIcon3D ["\a3\ui_f\data\IGUI\Cfg\Cursors\selectover_ca.paa", [1,0,1,1], ASLtoAGL _launchPos, 0.75, 0.75, 0, "LAUNCH", 1, 0.025, "TahomaB"];
4839
drawIcon3D ["\a3\ui_f\data\IGUI\Cfg\Cursors\selectover_ca.paa", [0,1,1,1], ASLtoAGL (_launchPos vectorAdd (_startLOS vectorMultiply (_distanceFromLaunch + 50))), 0.75, 0.75, 0, "Original LOS", 1, 0.025, "TahomaB"];
4940
drawIcon3D ["\a3\ui_f\data\IGUI\Cfg\Cursors\selectover_ca.paa", [1,1,0,1], ASLtoAGL (_launchPos vectorAdd ([_distanceFromLaunch + 50, _realYaw, _realPitch] call CBA_fnc_polar2vect)), 0.75, 0.75, 0, format ["Predicted @%1sec",(floor(_flightTime * 10)/10)], 1, 0.025, "TahomaB"];
@@ -56,5 +47,4 @@ if ((count _test) > 0) then {
5647
};
5748
#endif
5849

59-
// TRACE_1("Adjusted target position",_returnTargetPos);
60-
_returnTargetPos;
50+
[0, 0, 1]

addons/nlaw/functions/fnc_keyDown.sqf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ playSound "ACE_Sound_Click";
7474
_args set [1, _yaw];
7575
_args set [2, _pitch];
7676

77-
#ifdef DEBUG_MODE_FULL
77+
#ifdef DRAW_NLAW_INFO
7878
hintSilent format ["Instantaneous\nYaw: %1\n Pitch: %2\nGVAR\nYaw: %3\nPitch: %4", _yawChange, _pitchChange, GVAR(yawChange), GVAR(pitchChange)];
7979
#endif
8080
}, .25, [CBA_missionTime, _yaw, _pitch, true]] call CBA_fnc_addPerFrameHandler;
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#include "..\script_component.hpp"
2+
/*
3+
* Author: tcvm
4+
* Attempts to hold angle as fed to by seeker. Does so with a simple proportional controller
5+
*
6+
* Arguments:
7+
* Guidance Arg Array <ARRAY>
8+
*
9+
* Return Value:
10+
* Commanded acceleration normal to LOS in world space <ARRAY>
11+
*
12+
* Example:
13+
* [] call ace_missileguidance_fnc_navigationType_line
14+
*
15+
* Public: No
16+
*/
17+
// arbitrary constant
18+
#define PROPORTIONALITY_CONSTANT 20
19+
params ["_args", "_timestep", "_seekerTargetPos", "_profileAdjustedTargetPos", "_targetData", "_navigationParams"];
20+
_args params ["_firedEH"];
21+
_firedEH params ["","","","","","","_projectile"];
22+
23+
_navigationParams params ["_yawChange", "_pitchChange", "_lastPitch", "_lastYaw", "_initialPitch", "_pitchUp", "_lastYawRateDifference"];
24+
25+
// for some reason we need to multiply this. I don't know why, but it just works
26+
_pitchChange = _pitchChange * 1.5;
27+
_yawChange = _yawChange * 1.5;
28+
29+
((velocity _projectile) call CBA_fnc_vect2polar) params ["", "_currentYaw", "_currentPitch"];
30+
31+
private _pitchRate = if (_timestep == 0) then {
32+
0
33+
} else {
34+
(_currentPitch - _lastPitch) / _timestep
35+
};
36+
_navigationParams set [2, _currentPitch];
37+
38+
private _pitchModifier = if (_pitchChange == 0) then {
39+
1
40+
} else {
41+
abs (_pitchRate / _pitchChange)
42+
};
43+
private _desiredPitchChange = (_pitchChange - _pitchRate) * PROPORTIONALITY_CONSTANT * _pitchModifier;
44+
_desiredPitchChange = _desiredPitchChange + _pitchUp * (_initialPitch - _currentPitch) * PROPORTIONALITY_CONSTANT * _pitchModifier;
45+
46+
private _yawRate = if (_timestep == 0) then {
47+
0
48+
} else {
49+
(_currentYaw - _lastYaw) / _timestep
50+
};
51+
_navigationParams set [3, _currentYaw];
52+
53+
private _yawModifier = if (_yawChange == 0) then {
54+
1
55+
} else {
56+
abs (_yawRate / _yawChange)
57+
};
58+
59+
private _yawRateDifference = _yawChange - _yawRate;
60+
private _yawChangeDerivative = if (_timestep == 0) then {
61+
0
62+
} else {
63+
(_yawRateDifference - _lastYawRateDifference) / _timestep
64+
};
65+
_navigationParams set [6, _yawRateDifference];
66+
67+
private _desiredYawChange = _yawRateDifference * PROPORTIONALITY_CONSTANT + _yawRateDifference * 2;
68+
69+
#ifdef DRAW_NLAW_INFO
70+
drawIcon3D ["\a3\ui_f\data\IGUI\Cfg\Cursors\selectover_ca.paa", [1,0,1,1], ASLtoAGL getPosASLVisual _projectile, 0.75, 0.75, 0, format ["dP [%1] dY: [%2]", _desiredPitchChange, _desiredYawChange], 1, 0.025, "TahomaB"];
71+
drawIcon3D ["\a3\ui_f\data\IGUI\Cfg\Cursors\selectover_ca.paa", [1,0,1,1], [0, 0, 1] vectorAdd ASLtoAGL getPosASLVisual _projectile, 0.75, 0.75, 0, format ["pitch proportional [%1] yaw proportional [%2]", _pitchModifier, _yawModifier], 1, 0.025, "TahomaB"];
72+
#endif
73+
74+
TRACE_4("nlaw pitch/yaw info",_currentPitch,_lastPitch,_currentYaw,_lastYaw);
75+
TRACE_6("nlaw navigation",_yawChange,_desiredYawChange,_pitchChange,_desiredPitchChange,_yawRate,_pitchRate);
76+
77+
_projectile vectorModelToWorldVisual [_yawChange + _desiredYawChange, 0, _pitchChange + _desiredPitchChange]
78+
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
#include "..\script_component.hpp"
2+
/*
3+
* Author: PabstMirror
4+
* Sets up missile guidance state arrays (called from missileGuidance's onFired).
5+
*
6+
* Arguments:
7+
* Guidance Arg Array <ARRAY>
8+
*
9+
* Return Value:
10+
* Navigation Parameters <ARRAY>
11+
*
12+
* Example:
13+
* [] call ace_nlaw_fnc_onFired
14+
*
15+
* Public: No
16+
*/
17+
18+
params ["_firedEH", "_launchParams", "_flightParams", "_seekerParams", "_stateParams"];
19+
_firedEH params ["_shooter","","","","","","_projectile"];
20+
_launchParams params ["","_targetLaunchParams","","_attackProfile"];
21+
_targetLaunchParams params ["_target"];
22+
_stateParams params ["", "", "", "", "_navigationParams"];
23+
24+
// Reset _launchPos origin as projectile's height instead of player's foot
25+
_targetLaunchParams set [2, getPosASL _projectile];
26+
27+
// Get state params:
28+
TRACE_3("start of attack profile",_attackProfile,_shooter,vectorDir _projectile);
29+
30+
private _firedLOS = _shooter weaponDirection (currentWeapon _shooter);
31+
private _yawChange = 0;
32+
private _pitchChange = 0;
33+
34+
if (_shooter == ACE_player) then {
35+
TRACE_2("isPlayer",GVAR(yawChange),GVAR(pitchChange));
36+
_yawChange = GVAR(yawChange);
37+
_pitchChange = GVAR(pitchChange);
38+
TRACE_1("los check",_firedLOS call CBA_fnc_vect2Polar);
39+
} else {
40+
if ((!isNil "_target") && {!isNull _target}) then {
41+
_firedLOS = (getPosASL _projectile) vectorFromTo (aimPos _target);
42+
(((eyePos _shooter) vectorFromTo (aimPos _target)) call CBA_fnc_vect2Polar) params ["", "_startYaw", "_startPitch"];
43+
// Add some random error to AI's velocity prediction:
44+
private _random = random [(_shooter skillFinal "aimingAccuracy") min 0.9, 1, 2-((_shooter skillFinal "aimingAccuracy") min 0.9)];
45+
(((eyePos _shooter) vectorFromTo ((aimPos _target) vectorAdd ((velocity _target) vectorMultiply (_random)))) call CBA_fnc_vect2Polar) params ["", "_predictedYaw", "_predictedPitch"];
46+
_yawChange = ([_predictedYaw - _startYaw] call CBA_fnc_simplifyAngle180);
47+
_pitchChange = ([_predictedPitch - _startPitch] call CBA_fnc_simplifyAngle180);
48+
TRACE_1("AI",_target);
49+
} else {
50+
TRACE_1("AI - no target",_target);
51+
};
52+
};
53+
54+
// Limit Max Deflection
55+
//_yawChange = -10 max _yawChange min 10;
56+
//_pitchChange = -10 max _pitchChange min 10;
57+
58+
((velocity _projectile) call CBA_fnc_vect2polar) params ["", "_currentYaw", "_currentPitch"];
59+
((ACE_player weaponDirection (currentWeapon ACE_player)) call CBA_fnc_vect2Polar) params ["", "_yaw", "_pitch"];
60+
61+
TRACE_5("attackProfileStateParams",_firedLOS,_yawChange,_pitchChange,_currentPitch,_currentYaw);
62+
_navigationParams set [0, _yawChange];
63+
_navigationParams set [1, _pitchChange];
64+
_navigationParams set [2, _currentPitch]; // last pitch
65+
_navigationParams set [3, _currentYaw]; // last yaw
66+
_navigationParams set [4, _pitch]; // initial pitch
67+
_navigationParams set [5, 0]; // whether or not to zero out the pitch
68+
_navigationParams set [6, 0];
69+
_navigationParams
70+

addons/nlaw/functions/fnc_onFired.sqf

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,15 @@ params ["_firedEH", "_launchParams", "_flightParams", "_seekerParams", "_statePa
1919
_firedEH params ["_shooter","","","","","","_projectile"];
2020
_launchParams params ["","_targetLaunchParams","","_attackProfile"];
2121
_targetLaunchParams params ["_target"];
22-
_stateParams params ["", "", "_attackProfileStateParams"];
22+
_stateParams params ["", "_seekerStateParams", "_attackProfileStateParams"];
2323

2424
// Reset _launchPos origin as projectile's height instead of player's foot
2525
_targetLaunchParams set [2, getPosASL _projectile];
2626

2727
// Get state params:
2828
TRACE_3("start of attack profile",_attackProfile,_shooter,vectorDir _projectile);
2929

30-
private _firedLOS = _shooter weaponDirection (currentWeapon _shooter);
30+
private _firedLOS = vectorDir _projectile;
3131
private _yawChange = 0;
3232
private _pitchChange = 0;
3333

@@ -36,6 +36,23 @@ if (_shooter == ACE_player) then {
3636
_yawChange = GVAR(yawChange);
3737
_pitchChange = GVAR(pitchChange);
3838
TRACE_1("los check",_firedLOS call CBA_fnc_vect2Polar);
39+
40+
#ifdef DRAW_NLAW_INFO
41+
systemChat format ["YAW [%1]", _yawChange];
42+
systemChat format ["PITCH [%1]", _pitchChange];
43+
GVAR(debug_firedPrediction) = [];
44+
private _debugPos = getPosASL _projectile;
45+
((ACE_player weaponDirection (currentWeapon ACE_player)) call CBA_fnc_vect2Polar) params ["", "_debugYaw", "_debugPitch"];
46+
private _distance = 0;
47+
for "_x" from 0 to 6 step 0.1 do {
48+
private _debugAproxVel = linearConversion [0, 1, 5, 40, 170, true];
49+
_distance = _distance + _debugAproxVel * 0.1;
50+
private _debugYaw = _debugYaw + _yawChange * _x;
51+
private _debugPitch = _debugPitch + _pitchChange * _x;
52+
private _debugPos = _debugPos vectorAdd ([_distance, _debugYaw, _debugPitch] call CBA_fnc_polar2vect);
53+
GVAR(debug_firedPrediction) pushBack ["\a3\ui_f\data\IGUI\Cfg\Cursors\selectover_ca.paa", [0,0,0,1], ASLtoAGL _debugPos, 0.5, 0.5, 0, format ["%1", _x], 1, 0.025, "TahomaB"];
54+
};
55+
#endif
3956
} else {
4057
if ((!isNil "_target") && {!isNull _target}) then {
4158
_firedLOS = (getPosASL _projectile) vectorFromTo (aimPos _target);
@@ -55,6 +72,10 @@ if (_shooter == ACE_player) then {
5572
_yawChange = -10 max _yawChange min 10;
5673
_pitchChange = -10 max _pitchChange min 10;
5774

75+
_seekerStateParams set [2, _yawChange];
76+
_seekerStateParams set [3, _pitchChange];
77+
_seekerStateParams set [4, CBA_missionTime];
78+
5879
TRACE_3("attackProfileStateParams",_firedLOS,_yawChange,_pitchChange);
5980
_attackProfileStateParams set [0, CBA_missionTime];
6081
_attackProfileStateParams set [1, _firedLOS];

addons/nlaw/functions/fnc_seeker.sqf

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,27 @@
1616
*
1717
* Public: No
1818
*/
19+
#define PITCH_UP_TIME 1
1920

20-
params ["", "_args", "_seekerStateParams"];
21+
params ["", "_args", "_seekerStateParams", "", "", "_targetData"];
2122
_args params ["_firedEH", "_launchParams", "", "_seekerParams", "_stateParams"];
2223
_firedEH params ["","","","","","","_projectile"];
2324
_launchParams params ["", "_targetLaunchParams", "", "_attackProfile"];
2425
_targetLaunchParams params ["", "", "_launchPos"];
26+
_stateParams params ["", "", "", "", "_navigationParams"];
2527

26-
if (_attackProfile == QGVAR(directAttack)) exitWith {[0,0,0]};
28+
if (_attackProfile == QGVAR(directAttack)) exitWith {
29+
_navigationParams set [5, 1];
30+
[0,0,0]
31+
};
32+
33+
_seekerStateParams params ["", "", "", "_originalPitchRate", "_startTime"];
34+
_navigationParams params ["", "_pitchRate"];
35+
36+
// pitch up for the first second of flight to begin an over-fly trajectory
37+
private _pitchChange = linearConversion [0, PITCH_UP_TIME, CBA_missionTime - _startTime, 2, 0, true];
38+
_navigationParams set [1, _originalPitchRate + _pitchChange];
39+
_navigationParams set [5, ((CBA_missionTime - _startTime) min PITCH_UP_TIME) / PITCH_UP_TIME];
2740

2841
private _projPos = getPosASL _projectile;
2942

0 commit comments

Comments
 (0)