//------------------------------------------------------------------------------ // burstFrame() -- generate a small burst of bullets (usually every 1/10 seconds) //------------------------------------------------------------------------------ void Gun::burstFrame() { // Compute the number of rounds this burst int ibullets = static_cast<int>(rcount + 0.5f); // Do we have any bullets to fire ... if (ibullets > 0){ // Decrease the number of rounds remaining if ( !isUnlimited() ) { if (ibullets > rounds) { ibullets = rounds; rcount = LCreal(ibullets); } rounds -= ibullets; } // Update the rounds fired count rcount -= ibullets; // Log this event Player* ownship = static_cast<Player*>( findContainerByType(typeid(Player)) ); if (ownship != 0) { BEGIN_RECORD_DATA_SAMPLE( getSimulation()->getDataRecorder(), REID_GUN_FIRED ) SAMPLE_1_OBJECT( ownship ) SAMPLE_1_VALUE( rcount ) END_RECORD_DATA_SAMPLE() } // TabLogger is deprecated if (ownship != nullptr && getAnyEventLogger() != nullptr) { TabLogger::TabLogEvent* evt = new TabLogger::LogGunActivity(1, ownship, ibullets); // type 1 == gun fired getAnyEventLogger()->log(evt); evt->unref(); } // When we have a bullet model ... we're going to create a bullet (weapon) // player to flyout the rounds. Bullet* wpn = getBulletType(); Simulation* sim = static_cast<Simulation*>( findContainerByType(typeid(Simulation)) ); if (wpn != nullptr && ownship != nullptr && sim != nullptr) { // Compute the bullet burst's initial position and velocity osg::Vec3 ipos = computeInitBulletPosition(); osg::Vec3 ivel = computeInitBulletVelocity(); // Get the bullet player being used to fly-out the bullets Bullet* flyout = static_cast<Bullet*>( wpn->getFlyoutWeapon() ); if (flyout == nullptr) { // If we don't have the flyout bullet (i.e., weapon and player) ... create it wpn->setLaunchVehicle(ownship); flyout = static_cast<Bullet*>( wpn->release() ); } // The flyout bullet (player) will handle this burst of bullets. if (flyout != nullptr) { flyout->burstOfBullets(&ipos, &ivel, ibullets, getRoundsPerMinute(), sim->getNewWeaponEventID() ); } // Cleanup if (flyout != nullptr) { flyout->unref(); flyout = nullptr; } } } else rcount = 0;
//------------------------------------------------------------------------------ // 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(); } } } } }