Move the mechanics of turning out of the derived classes into AIPlane. The user-visible effect is that AI planes no longer suddenly change direction without turning properly.
This commit is contained in:
parent
cb8db7725a
commit
9773ba5542
4 changed files with 67 additions and 56 deletions
|
@ -84,7 +84,8 @@ bool FGAIGAVFRTraffic::Init(Point3D pt, string destID, const string& callsign) {
|
|||
_pos.setelev(_cruise_alt);
|
||||
// initially set waypoint as airport location
|
||||
_wp = _destPos;
|
||||
_hdg = GetHeadingFromTo(_pos, _wp);
|
||||
//_hdg = GetHeadingFromTo(_pos, _wp);
|
||||
SetTrack(GetHeadingFromTo(_pos, _wp));
|
||||
_roll = 0.0;
|
||||
_pitch = 0.0;
|
||||
slope = 0.0;
|
||||
|
@ -201,7 +202,8 @@ void FGAIGAVFRTraffic::FlyPlane(double dt) {
|
|||
_straightIn = true;
|
||||
_incoming = true;
|
||||
_wp = GetPatternApproachPos();
|
||||
_hdg = GetHeadingFromTo(_pos, _wp); // TODO - turn properly!
|
||||
//_hdg = GetHeadingFromTo(_pos, _wp); // TODO - turn properly!
|
||||
SetTrack(GetHeadingFromTo(_pos, _wp));
|
||||
slope = atan((_wp.elev() - _pos.elev()) / dclGetHorizontalSeparation(_wp, _pos)) * DCL_RADIANS_TO_DEGREES;
|
||||
double thesh_offset = 0.0;
|
||||
Point3D opos = ortho.ConvertToLocal(_pos);
|
||||
|
@ -221,7 +223,7 @@ void FGAIGAVFRTraffic::FlyPlane(double dt) {
|
|||
_downwindEntry = true;
|
||||
_incoming = true;
|
||||
_wp = GetPatternApproachPos();
|
||||
_hdg = GetHeadingFromTo(_pos, _wp); // TODO - turn properly!
|
||||
SetTrack(GetHeadingFromTo(_pos, _wp));
|
||||
slope = atan((_wp.elev() - _pos.elev()) / dclGetHorizontalSeparation(_wp, _pos)) * DCL_RADIANS_TO_DEGREES;
|
||||
//cout << "slope = " << slope << '\n';
|
||||
pending_transmission = "Report ";
|
||||
|
@ -247,7 +249,7 @@ void FGAIGAVFRTraffic::FlyPlane(double dt) {
|
|||
if(_straightIn) {
|
||||
//cout << "A " << flush;
|
||||
if(fabs(orthopos.x()) < 10.0 && !_established) {
|
||||
_hdg = rwy.hdg; // MEGA MEGA HACK - FIXME!!!!!!!
|
||||
SetTrack(rwy.hdg);
|
||||
_established = true;
|
||||
//cout << "Established at " << orthopos << '\n';
|
||||
}
|
||||
|
@ -279,15 +281,8 @@ void FGAIGAVFRTraffic::FlyPlane(double dt) {
|
|||
if(_entering) {
|
||||
//cout << "C" << flush;
|
||||
if(_turning) {
|
||||
double tgt_hdg = rwy.hdg + 180.0;
|
||||
while((tgt_hdg - _hdg) > 180.0) _hdg += 360.0;
|
||||
while((_hdg - tgt_hdg) > 180.0) _hdg -= 360.0;
|
||||
double turn_time = 60.0;
|
||||
_hdg += (360.0 / turn_time) * dt * (tgt_hdg > _hdg ? 1.0 : -1.0);
|
||||
Bank(25.0 * (tgt_hdg > _hdg ? 1.0 : -1.0));
|
||||
if(fabs(_hdg - tgt_hdg) < 2.0) {
|
||||
if(fabs(_hdg - (rwy.hdg + 180)) < 2.0) { // TODO - use track instead of _hdg?
|
||||
//cout << "Going Local...\n";
|
||||
_hdg = rwy.hdg + 180.0; // TODO - FIX THIS UGLY HACK!!!!!!!
|
||||
leg = DOWNWIND;
|
||||
_local = true;
|
||||
_aip.setVisible(true); // HACK
|
||||
|
@ -300,6 +295,7 @@ void FGAIGAVFRTraffic::FlyPlane(double dt) {
|
|||
if(fabs(orthopos.x() - (patternDirection == 1 ? 1000 : -1000)) < (_e45 ? 175 : 550)) { // Caution - hardwired turn clearances.
|
||||
//cout << "_turning...\n";
|
||||
_turning = true;
|
||||
SetTrack(rwy.hdg + 180.0);
|
||||
} // TODO - need to check for other traffic in the pattern and enter much more integilently than that!!!
|
||||
} else {
|
||||
//cout << "D" << flush;
|
||||
|
@ -318,12 +314,14 @@ void FGAIGAVFRTraffic::FlyPlane(double dt) {
|
|||
slope = 0.0;
|
||||
ConditionalTransmit(30);
|
||||
if(_e45) {
|
||||
_hdg = (patternDirection == 1 ? rwy.hdg - 135.0 : rwy.hdg + 135.0);
|
||||
SetTrack(patternDirection == 1 ? rwy.hdg - 135.0 : rwy.hdg + 135.0);
|
||||
} else {
|
||||
_hdg = (patternDirection == 1 ? rwy.hdg + 90.0 : rwy.hdg - 90.0);
|
||||
SetTrack(patternDirection == 1 ? rwy.hdg + 90.0 : rwy.hdg - 90.0);
|
||||
}
|
||||
if(_hdg < 0.0) _hdg += 360.0;
|
||||
//if(_hdg < 0.0) _hdg += 360.0;
|
||||
_entering = true;
|
||||
} else {
|
||||
SetTrack(GetHeadingFromTo(_pos, _wp));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -332,8 +330,8 @@ void FGAIGAVFRTraffic::FlyPlane(double dt) {
|
|||
slope = 0.0;
|
||||
}
|
||||
// FIXME - lots of hackery in the next six lines!!!!
|
||||
double track = _hdg;
|
||||
double crab = 0.0;
|
||||
//double track = _hdg;
|
||||
double crab = 0.0; // This is a placeholder for when we take wind into account.
|
||||
_hdg = track + crab;
|
||||
double vel = _cruise_ias;
|
||||
double dist = vel * 0.514444 * dt;
|
||||
|
@ -410,7 +408,6 @@ int FGAIGAVFRTraffic::GetQuadrangleAltitude(int dir, int des_alt) {
|
|||
// 3/ At and appropriate point on non-circuit side of rwy at take-off end for perpendicular entry to circuit overflying end-of-rwy.
|
||||
Point3D FGAIGAVFRTraffic::GetPatternApproachPos() {
|
||||
//cout << "\n\n";
|
||||
//cout << "PPPPPPPPPPPPPPPPPPPPPPPppppppppppppppp\n";
|
||||
//cout << "Calculating pattern approach pos for " << plane.callsign << '\n';
|
||||
Point3D orthopos = ortho.ConvertToLocal(_pos);
|
||||
Point3D tmp;
|
||||
|
|
|
@ -164,6 +164,10 @@ void FGAILocalTraffic::GetRwyDetails(string id) {
|
|||
//cout << "GetRwyDetails called" << endl;
|
||||
|
||||
rwy.rwyID = tower->GetActiveRunway();
|
||||
//cout << "id = " << id << '\n';
|
||||
//cout << "Returned id is " << tower->get_ident() << '\n';
|
||||
//cout << "Returned name is " << tower->get_name() << '\n';
|
||||
//cout << "rwy.rwyID = " << rwy.rwyID << '\n';
|
||||
|
||||
// Now we need to get the threshold position and rwy heading
|
||||
|
||||
|
@ -201,7 +205,7 @@ void FGAILocalTraffic::GetRwyDetails(string id) {
|
|||
rwy.end1ortho = ortho.ConvertToLocal(rwy.threshold_pos); // should come out as zero
|
||||
rwy.end2ortho = ortho.ConvertToLocal(takeoff_end);
|
||||
} else {
|
||||
SG_LOG(SG_ATC, SG_ALERT, "Help - can't get good runway in FGAILocalTraffic!!\n");
|
||||
SG_LOG(SG_ATC, SG_ALERT, "Help - can't get good runway at airport " << id << " in FGAILocalTraffic!!");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -328,7 +332,7 @@ bool FGAILocalTraffic::Init(const string& callsign, string ICAO, OperatingState
|
|||
leg = DOWNWIND;
|
||||
elevInitGood = false;
|
||||
inAir = true;
|
||||
track = rwy.hdg - (180 * patternDirection); //should tend to bring track back into the 0->360 range
|
||||
SetTrack(rwy.hdg - (180 * patternDirection));
|
||||
slope = 0.0;
|
||||
_pitch = 0.0;
|
||||
_roll = 0.0;
|
||||
|
@ -383,7 +387,7 @@ void FGAILocalTraffic::DownwindEntry() {
|
|||
leg = DOWNWIND;
|
||||
elevInitGood = false;
|
||||
inAir = true;
|
||||
track = rwy.hdg - (180 * patternDirection); //should tend to bring track back into the 0->360 range
|
||||
SetTrack(rwy.hdg - (180 * patternDirection));
|
||||
slope = 0.0;
|
||||
_pitch = 0.0;
|
||||
_roll = 0.0;
|
||||
|
@ -399,7 +403,7 @@ void FGAILocalTraffic::StraightInEntry(bool des) {
|
|||
leg = FINAL;
|
||||
elevInitGood = false;
|
||||
inAir = true;
|
||||
track = rwy.hdg;
|
||||
SetTrack(rwy.hdg);
|
||||
transmitted = true; // TODO - fix this hack.
|
||||
// TODO - set up the next 5 properly for a descent!
|
||||
slope = -5.5;
|
||||
|
@ -702,7 +706,7 @@ void FGAILocalTraffic::Update(double dt) {
|
|||
//fgSetDouble("/AI/Local1/ortho-y", (ortho.ConvertToLocal(_pos)).y());
|
||||
//fgSetDouble("/AI/Local1/elev", _pos.elev() * SG_METER_TO_FEET);
|
||||
|
||||
// And finally, call parent for transmission rendering
|
||||
// And finally, call parent.
|
||||
FGAIPlane::Update(dt);
|
||||
}
|
||||
|
||||
|
@ -800,6 +804,7 @@ void FGAILocalTraffic::FlyTrafficPattern(double dt) {
|
|||
IAS = vel + (cos((_hdg - wind_from) * DCL_DEGREES_TO_RADIANS) * wind_speed);
|
||||
if(IAS >= 70) {
|
||||
leg = CLIMBOUT;
|
||||
SetTrack(rwy.hdg); // Hands over control of turning to AIPlane
|
||||
_pitch = 10.0;
|
||||
IAS = best_rate_of_climb_speed;
|
||||
//slope = 7.0;
|
||||
|
@ -808,7 +813,6 @@ void FGAILocalTraffic::FlyTrafficPattern(double dt) {
|
|||
}
|
||||
break;
|
||||
case CLIMBOUT:
|
||||
track = rwy.hdg;
|
||||
// Turn to crosswind if above 700ft AND if other traffic allows
|
||||
// (decided in FGTower and accessed through GetCrosswindConstraint(...)).
|
||||
// According to AIM, traffic should climb to within 300ft of pattern altitude before commencing crosswind turn.
|
||||
|
@ -843,16 +847,13 @@ void FGAILocalTraffic::FlyTrafficPattern(double dt) {
|
|||
}
|
||||
break;
|
||||
case TURN1:
|
||||
track += (360.0 / turn_time) * dt * patternDirection;
|
||||
Bank(25.0 * patternDirection);
|
||||
SetTrack(rwy.hdg + (90.0 * patternDirection));
|
||||
if((track < (rwy.hdg - 89.0)) || (track > (rwy.hdg + 89.0))) {
|
||||
leg = CROSSWIND;
|
||||
}
|
||||
break;
|
||||
case CROSSWIND:
|
||||
goAround = false;
|
||||
LevelWings();
|
||||
track = rwy.hdg + (90.0 * patternDirection);
|
||||
if((_pos.elev() - rwy.threshold_pos.elev()) * SG_METER_TO_FEET > 1000) {
|
||||
slope = 0.0;
|
||||
_pitch = 0.0;
|
||||
|
@ -873,8 +874,7 @@ void FGAILocalTraffic::FlyTrafficPattern(double dt) {
|
|||
}
|
||||
break;
|
||||
case TURN2:
|
||||
track += (360.0 / turn_time) * dt * patternDirection;
|
||||
Bank(25.0 * patternDirection);
|
||||
SetTrack(rwy.hdg - (180 * patternDirection));
|
||||
// just in case we didn't make height on crosswind
|
||||
if((_pos.elev() - rwy.threshold_pos.elev()) * SG_METER_TO_FEET > 1000) {
|
||||
slope = 0.0;
|
||||
|
@ -884,12 +884,9 @@ void FGAILocalTraffic::FlyTrafficPattern(double dt) {
|
|||
if((track < (rwy.hdg - 179.0)) || (track > (rwy.hdg + 179.0))) {
|
||||
leg = DOWNWIND;
|
||||
transmitted = false;
|
||||
//roll = 0.0;
|
||||
}
|
||||
break;
|
||||
case DOWNWIND:
|
||||
LevelWings();
|
||||
track = rwy.hdg - (180 * patternDirection); //should tend to bring track back into the 0->360 range
|
||||
// just in case we didn't make height on crosswind
|
||||
if(((_pos.elev() - rwy.threshold_pos.elev()) * SG_METER_TO_FEET > 995) && ((_pos.elev() - rwy.threshold_pos.elev()) * SG_METER_TO_FEET < 1015)) {
|
||||
slope = 0.0;
|
||||
|
@ -947,14 +944,12 @@ void FGAILocalTraffic::FlyTrafficPattern(double dt) {
|
|||
}
|
||||
break;
|
||||
case TURN3:
|
||||
track += (360.0 / turn_time) * dt * patternDirection;
|
||||
Bank(25.0 * patternDirection);
|
||||
SetTrack(rwy.hdg - (90 * patternDirection));
|
||||
if(fabs(rwy.hdg - track) < 91.0) {
|
||||
leg = BASE;
|
||||
}
|
||||
break;
|
||||
case BASE:
|
||||
LevelWings();
|
||||
if(!transmitted) {
|
||||
// Base report should only be transmitted at uncontrolled airport - not towered.
|
||||
if(!_controlled) TransmitPatternPositionReport();
|
||||
|
@ -977,8 +972,6 @@ void FGAILocalTraffic::FlyTrafficPattern(double dt) {
|
|||
IAS = 70.0;
|
||||
}
|
||||
|
||||
track = rwy.hdg - (90 * patternDirection);
|
||||
|
||||
// Try and arrange to turn nicely onto final
|
||||
turn_circumference = IAS * 0.514444 * turn_time;
|
||||
//Hmmm - this is an interesting one - ground vs airspeed in relation to turn radius
|
||||
|
@ -991,8 +984,7 @@ void FGAILocalTraffic::FlyTrafficPattern(double dt) {
|
|||
}
|
||||
break;
|
||||
case TURN4:
|
||||
track += (360.0 / turn_time) * dt * patternDirection;
|
||||
Bank(25.0 * patternDirection);
|
||||
SetTrack(rwy.hdg);
|
||||
if(fabs(track - rwy.hdg) < 0.6) {
|
||||
leg = FINAL;
|
||||
vel = nominal_final_speed;
|
||||
|
@ -1062,7 +1054,7 @@ void FGAILocalTraffic::FlyTrafficPattern(double dt) {
|
|||
}
|
||||
}
|
||||
// Try and track the extended centreline
|
||||
track = rwy.hdg - (0.2 * orthopos.x());
|
||||
SetTrack(rwy.hdg - (0.2 * orthopos.x()));
|
||||
//cout << "orthopos.x() = " << orthopos.x() << " hdg = " << hdg << '\n';
|
||||
if(_pos.elev() < (rwy.threshold_pos.elev()+20.0+wheelOffset)) {
|
||||
DoGroundElev(); // Need to call it here expicitly on final since it's only called
|
||||
|
@ -1077,6 +1069,8 @@ void FGAILocalTraffic::FlyTrafficPattern(double dt) {
|
|||
_pitch = 0.0;
|
||||
leg = LANDING_ROLL;
|
||||
inAir = false;
|
||||
LevelWings();
|
||||
ClearTrack(); // Take over explicit track handling since AIPlane currently always banks when changing course
|
||||
}
|
||||
} // else need a fallback position based on arpt elev in case ground elev determination fails?
|
||||
} else {
|
||||
|
|
|
@ -44,6 +44,10 @@ FGAIPlane::FGAIPlane() {
|
|||
playing = false;
|
||||
voiceOK = false;
|
||||
vPtr = NULL;
|
||||
_tgtTrack = 0.0;
|
||||
_trackSet = false;
|
||||
_tgtRoll = 0.0;
|
||||
_rollSuspended = false;
|
||||
}
|
||||
|
||||
FGAIPlane::~FGAIPlane() {
|
||||
|
@ -113,20 +117,27 @@ void FGAIPlane::Update(double dt) {
|
|||
}
|
||||
_counter += dt;
|
||||
}
|
||||
}
|
||||
|
||||
void FGAIPlane::Bank(double angle) {
|
||||
// This *should* bank us smoothly to any angle
|
||||
if(fabs(_roll - angle) > 0.6) {
|
||||
_roll -= ((_roll - angle)/fabs(_roll - angle));
|
||||
|
||||
// Fly the plane if necessary
|
||||
if(_trackSet) {
|
||||
while((_tgtTrack - track) > 180.0) track += 360.0;
|
||||
while((track - _tgtTrack) > 180.0) track -= 360.0;
|
||||
double turn_time = 60.0;
|
||||
track += (360.0 / turn_time) * dt * (_tgtTrack > track ? 1.0 : -1.0);
|
||||
Bank(25.0 * (_tgtTrack > track ? 1.0 : -1.0));
|
||||
if(fabs(track - _tgtTrack) < 2.0) { // TODO - might need to optimise the delta there - it's on the large (safe) side atm.
|
||||
track = _tgtTrack;
|
||||
LevelWings();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Duplication of Bank(0.0) really - should I cut this?
|
||||
void FGAIPlane::LevelWings(void) {
|
||||
// bring the plane back to level smoothly (this should work to come out of either bank)
|
||||
if(fabs(_roll) > 0.6) {
|
||||
_roll -= (_roll/fabs(_roll));
|
||||
|
||||
if(!_rollSuspended) {
|
||||
if(fabs(_roll - _tgtRoll) > 0.6) {
|
||||
// This *should* bank us smoothly to any angle
|
||||
_roll -= ((_roll - _tgtRoll)/fabs(_roll - _tgtRoll));
|
||||
} else {
|
||||
_roll = _tgtRoll;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -120,9 +120,12 @@ protected:
|
|||
|
||||
// Transmit regardless of other dialog on the channel eg emergency
|
||||
void ImmediateTransmit(int callback_code = 0);
|
||||
|
||||
inline void SetTrack(double t) { _tgtTrack = t; _trackSet = true; }
|
||||
inline void ClearTrack() { _trackSet = false; }
|
||||
|
||||
void Bank(double angle);
|
||||
void LevelWings(void);
|
||||
inline void Bank(double r) { _tgtRoll = r; }
|
||||
inline void LevelWings(void) { _tgtRoll = 0.0; }
|
||||
|
||||
virtual void ProcessCallback(int code);
|
||||
|
||||
|
@ -153,6 +156,12 @@ private:
|
|||
bool playing; // Indicates a message in progress
|
||||
bool voiceOK; // Flag - true if at least one voice has loaded OK
|
||||
FGATCVoice* vPtr;
|
||||
|
||||
// Navigation
|
||||
double _tgtTrack; // Track to be following if _trackSet is true
|
||||
bool _trackSet; // Set true if tgtTrack is to be followed
|
||||
double _tgtRoll;
|
||||
bool _rollSuspended; // Set true when a derived class has suspended AIPlane's roll control
|
||||
};
|
||||
|
||||
#endif // _FG_AI_PLANE_HXX
|
||||
|
|
Loading…
Add table
Reference in a new issue