//------------------------------------------------------------------------------ // atReleaseInit() -- Init weapon data at release //------------------------------------------------------------------------------ void Missile::atReleaseInit() { // First the base class will setup the initial conditions BaseClass::atReleaseInit(); if (getDynamicsModel() == 0) { // set initial commands cmdPitch = (LCreal) getPitch(); cmdHeading = (LCreal) getHeading(); cmdVelocity = vpMax; if (getTargetTrack() != 0) { // Set initial range and range dot osg::Vec3 los = getTargetTrack()->getPosition(); trng = los.length(); trngT = trng; } else if (getTargetPlayer() != 0) { // Set initial range and range dot osg::Vec3 los = getTargetPosition(); trng = los.length(); trngT = trng; } else { trng = 0; } // Range dot trdot = 0; trdotT = 0; } }
// setTargetTrack() -- sets a pointer to the target track bool Missile::setTargetTrack(Track* const trk, const bool pt) { // if our track has changed, reset ground truth vals for weaponGuidance's fuzing logic if (trk!=0 && trk != getTargetTrack()) { trngT = (trk->getPosition()).length(); trdotT = 0; } return BaseClass::setTargetTrack(trk, pt); }
void PlaneState::updateState(const Basic::Component* const actor) { const Simulation::AirVehicle* airVehicle = dynamic_cast<const Simulation::AirVehicle*>(actor); setAlive(false); if (airVehicle != nullptr && airVehicle->isActive()) { setAltitude(airVehicle->getAltitude()); setAlive(airVehicle->getMode() == Simulation::Player::ACTIVE); setHeading(airVehicle->getHeading()); setPitch(airVehicle->getPitch()); setRoll(airVehicle->getRoll()); osg::Vec3d angularVels = airVehicle->getAngularVelocities(); setRollRate(angularVels.x()); setPitchRate(angularVels.y()); setYawRate(angularVels.z()); setTracking(false); setTargetTrack(MAX_TRACKS); // 0 is a valid target track, use MAX_TRACKS to // signal "no tgt track" setSpeed(airVehicle->getCalibratedAirspeed()); setNumEngines(airVehicle->getNumberOfEngines()); setIncomingMissile(false); setMissileFired(false); // determine if we have a missile to fire #if 1 const Simulation::StoresMgr* stores = airVehicle->getStoresManagement(); if (stores == nullptr || stores->getNextMissile() == nullptr) { // either we have no SMS, or we have no more missile setMissileFired(true); } else { // we have an sms, and we have a missile available // loop through player list and attempt to find out if one of our missiles is active // if there is an active missile, then for the time being, we do not have a missile to fire const Simulation::Simulation* sim = airVehicle->getSimulation(); const Basic::PairStream* players = sim->getPlayers(); bool finished = false; for (const Basic::List::Item* item = players->getFirstItem(); item != nullptr && !finished; item = item->getNext()) { // Get the pointer to the target player const Basic::Pair* pair = static_cast<const Basic::Pair*>(item->getValue()); const Simulation::Player* player = static_cast<const Simulation::Player*>(pair->object()); if (player->isMajorType(Simulation::Player::WEAPON) && (player->isActive() || player->isMode(Simulation::Player::PRE_RELEASE)) && (player->getSide() == airVehicle->getSide())) { // our side has a weapon on-the-way/in-the-air; setMissileFired(true); finished=true; } } } #else // this state class has no way to determine whether we've fired a missile other than checking to see if sms is out of missiles to fire. // which means, it will fire all its missiles at first target. const Simulation::StoresMgr* stores = airVehicle->getStoresManagement(); if (stores != 0) { const Simulation::Missile* wpn = stores->getNextMissile(); if (!wpn) setMissileFired(true); } else { // we have no SMS, we can't fire a missile; setMissileFired(true); } #endif //const Basic::String* playerName = airVehicle->getName(); // DH - DOES NOT COMPILE WITH CONST -- ???? Simulation::AirVehicle* airVehicleX = const_cast<Simulation::AirVehicle*>(airVehicle); const Basic::Pair* sensorPair = airVehicleX->getSensorByType(typeid(Simulation::Radar)); if (sensorPair != nullptr) { const Simulation::Radar* radar = static_cast<const Simulation::Radar*>(sensorPair->object()); if (radar != nullptr) { const Simulation::TrackManager* trackManager = radar->getTrackManager(); Basic::safe_ptr<Simulation::Track> trackList[50]; unsigned int nTracks = trackManager->getTrackList(trackList, 50); for (int trackIndex = nTracks -1; trackIndex >= 0; trackIndex--) { setHeadingToTracked(trackIndex, trackList[trackIndex]->getRelAzimuth()); setPitchToTracked(trackIndex, trackList[trackIndex]->getElevation()); setDistanceToTracked(trackIndex, trackList[trackIndex]->getRange()); // do we have a live "target track"? (shootlist is 1-based) if (getTargetTrack()==MAX_TRACKS && (trackList[trackIndex]->getShootListIndex() == 1) && trackList[trackIndex]->getTarget()->isActive() ) { setTargetTrack(trackIndex); } setTracking(true); setNumTracks(nTracks); // hack to implement "missile warning" if (isIncomingMissile() == false) { // is this track a weapon, and if so, is it targeting me? Simulation::Player* target = trackList[trackIndex]->getTarget(); Simulation::Weapon* weapon = dynamic_cast<Simulation::Weapon*> (target); if (weapon!=nullptr && !weapon->isDead()) { Simulation::Player* wpntgt = weapon->getTargetPlayer(); if (wpntgt == airVehicle) { setIncomingMissile(true); } } } } } } const Simulation::OnboardComputer* oc = airVehicle->getOnboardComputer(); if (oc != nullptr) { const Simulation::TrackManager* rtm = oc->getTrackManagerByType(typeid(Simulation::RwrTrkMgr)); if(rtm !=nullptr) { Basic::safe_ptr<Simulation::Track> trackList[50]; unsigned int nTracks = rtm->getTrackList(trackList, 50); int newTracks = 0; for (unsigned int trackIndex = 0; trackIndex < nTracks; trackIndex++) { Simulation::Player* target = trackList[trackIndex]->getTarget(); bool alreadyTracked = false; for (unsigned int currTracks = 0; currTracks>getNumTracks(); currTracks++) { // tracks are the same if the associated players are the same if(trackList[currTracks]->getTarget()==target) { alreadyTracked = true; break; } } if (!alreadyTracked && (getNumTracks() + newTracks) < MAX_TRACKS) { int newTrackIndex = getNumTracks() + newTracks; newTracks++; setHeadingToTracked(newTrackIndex, trackList[trackIndex]->getRelAzimuth()); setPitchToTracked(newTrackIndex, trackList[trackIndex]->getElevation()); setDistanceToTracked(newTrackIndex, trackList[trackIndex]->getRange()); setTracking(true); // update numTracks to new sum of radar + rwr tracks setNumTracks(getNumTracks()+newTracks); } // do we have a live "target track"? (shootlist is 1-based) if (getTargetTrack()==MAX_TRACKS && (trackList[trackIndex]->getShootListIndex() == 1) && trackList[trackIndex]->getTarget()->isActive() ) { setTargetTrack(trackIndex); } // hack to implement "missile warning" if (isIncomingMissile() == false) { // is this track a weapon, and if so, is it targeting me? Simulation::Weapon* weapon = dynamic_cast<Simulation::Weapon*> (target); if (weapon!=nullptr && !weapon->isDead()) { Simulation::Player* wpntgt = weapon->getTargetPlayer(); if (wpntgt == airVehicle) { setIncomingMissile(true); } } } } } } } BaseClass::updateState(actor); }
//------------------------------------------------------------------------------ // weaponGuidance() -- default guidance; using Robot Aircraft (RAC) guidance //------------------------------------------------------------------------------ void Missile::weaponGuidance(const LCreal dt) { // --- // Control velocity: During burn time, accel to max velocity, // after burn time, deaccelerate to min velocity. // --- if (isEngineBurnEnabled()) cmdVelocity = vpMax; else cmdVelocity = vpMin; // --- // If the target's already dead, // then don't go away mad, just go away. // --- const Player* tgt = getTargetPlayer(); const Track* trk = getTargetTrack(); if (trk != 0) tgt = trk->getTarget(); if (tgt != 0 && !tgt->isActive()) return; osg::Vec3 los; // Target Line of Sight osg::Vec3 vel; // Target velocity // --- // Basic guidance // --- { // --- // Get position and velocity vectors from the target/track // --- osg::Vec3 posx; calculateVectors(tgt, trk, &los, &vel, &posx); // compute range to target LCreal trng0 = trng; trng = los.length(); // compute range rate, LCreal trdot0 = trdot; if (dt > 0) trdot = (trng - trng0)/dt; else trdot = 0; // Target total velocit LCreal totalVel = vel.length(); // compute target velocity parallel to LOS, LCreal vtplos = (los * vel/trng); // --- // guidance - fly to intercept point // --- // if we have guidance ... if ( isGuidanceEnabled() && trng > 0) { // get missile velocity (must be faster than target), LCreal v = vpMax; if (v < totalVel) v = totalVel + 1; // compute target velocity normal to LOS squared, LCreal tgtVp = totalVel; LCreal vtnlos2 = tgtVp*tgtVp - vtplos*vtplos; // and compute missile velocity parallex to LOS. LCreal vmplos = lcSqrt( v*v - vtnlos2 ); // Now, use both velocities parallel to LOS to compute // closure rate. LCreal vclos = vmplos - vtplos; // Use closure rate and range to compute time to intercept. LCreal dt1 = 0; if (vclos > 0) dt1 = trng/vclos; // Use time to intercept to extrapolate target position. osg::Vec3 p1 = (los + (vel * dt1)); // Compute missile commanded heading and cmdHeading = lcAtan2(p1.y(),p1.x()); // commanded pitch. LCreal grng = lcSqrt(p1.x()*p1.x() + p1.y()*p1.y()); cmdPitch = -lcAtan2(p1.z(),grng); } } // --- // fuzing logic (let's see if we've scored a hit) // (compute range at closest point and compare to max burst radius) // (use target truth data) // --- { // --- // Get position and velocity vectors from the target (truth) // (or default to the values from above) // --- if (tgt != 0) { calculateVectors(tgt, 0, &los, &vel, 0); } // compute range to target LCreal trng0 = trngT; trngT = los.length(); // compute range rate, LCreal trdot0 = trdotT; if (dt > 0) trdotT = (trngT - trng0)/dt; else trdotT = 0; // when we've just passed the target ... if (trdotT > 0 && trdot0 < 0 && !isDummy() && getTOF() > 2.0f) { bool missed = true; // assume the worst // compute relative velocity vector. osg::Vec3 velRel = (vel - getVelocity()); // compute missile velocity squared, LCreal vm2 = velRel.length2(); if (vm2 > 0) { // relative range (dot) relative velocity LCreal rdv = los * velRel; // interpolate back to closest point LCreal ndt = -rdv/vm2; osg::Vec3 p0 = los + (velRel*ndt); // range squared at closest point LCreal r2 = p0.length2(); // compare to burst radius squared if (r2 <= (getMaxBurstRng()*getMaxBurstRng()) ) { // We've detonated missed = false; setMode(DETONATED); setDetonationResults( DETONATE_ENTITY_IMPACT ); // compute location of the detonation relative to the target osg::Vec3 p0n = -p0; if (tgt != 0) p0n = tgt->getRotMat() * p0n; setDetonationLocation(p0n); // Did we hit anyone? checkDetonationEffect(); // Log the event LCreal detRange = getDetonationRange(); if (isMessageEnabled(MSG_INFO)) { std::cout << "DETONATE_ENTITY_IMPACT rng = " << detRange << std::endl; } if (getAnyEventLogger() != 0) { TabLogger::TabLogEvent* evt = new TabLogger::LogWeaponActivity(2, getLaunchVehicle(), this, getTargetPlayer(), DETONATE_ENTITY_IMPACT, detRange); // type 2 for "detonate" getAnyEventLogger()->log(evt); evt->unref(); } } } // Did we miss the target? if (missed) { // We've detonated ... setMode(DETONATED); setDetonationResults( DETONATE_DETONATION ); // because we've just missed the target setTargetPlayer(0,false); setTargetTrack(0,false); // Log the event LCreal detRange = trngT; if (isMessageEnabled(MSG_INFO)) { std::cout << "DETONATE_OTHER rng = " << detRange << std::endl; } if (getAnyEventLogger() != 0) { TabLogger::TabLogEvent* evt = new TabLogger::LogWeaponActivity(2, getLaunchVehicle(), this, getTargetPlayer(), DETONATE_DETONATION, getDetonationRange()); // type 2 for "detonate" getAnyEventLogger()->log(evt); evt->unref(); } } } } }