void CProjectileHandler::CheckGroundCollisions(ProjectileContainer& pc) { for (size_t i=0; i<pc.size(); ++i) { CProjectile* p = pc[i]; if (!p->checkCol) continue; // NOTE: if <p> is a MissileProjectile and does not // have selfExplode set, it will never be removed (!) if (p->GetCollisionFlags() & Collision::NOGROUND) continue; // NOTE: don't add p->radius to groundHeight, or most // projectiles will collide with the ground too early const float groundHeight = CGround::GetHeightReal(p->pos.x, p->pos.z); const bool belowGround = (p->pos.y < groundHeight); const bool insideWater = (p->pos.y <= 0.0f && !belowGround); const bool ignoreWater = p->ignoreWater; if (belowGround || (insideWater && !ignoreWater)) { // if position has dropped below terrain or into water // where we cannot live, adjust it and explode us now // (if the projectile does not set deleteMe = true, it // will keep hugging the terrain) p->pos.y = groundHeight * belowGround; p->Collision(); } } }
void CProjectileHandler::CheckGroundCollisions(ProjectileContainer& pc) { for (size_t i = 0; i < pc.size(); ++i) { CProjectile* p = pc[i]; if (!p->checkCol) continue; // NOTE: // if <p> is a MissileProjectile and does not have // selfExplode set, tbis will cause it to never be // removed (!) if (p->GetCollisionFlags() & Collision::NOGROUND) continue; // don't collide with ground yet if last update scheduled a bounce if (p->weapon && static_cast<const CWeaponProjectile*>(p)->HasScheduledBounce()) continue; // NOTE: // don't add p->radius to groundHeight, or most (esp. modelled) // projectiles will collide with the ground one or more frames // too early const float groundHeight = CGround::GetHeightReal(p->pos.x, p->pos.z); const bool belowGround = (p->pos.y < groundHeight); const bool insideWater = (p->pos.y <= 0.0f && !belowGround); const bool ignoreWater = p->ignoreWater; if (belowGround || (insideWater && !ignoreWater)) { // if position has dropped below terrain or into water // where we can not live, adjust it and explode us now // (if the projectile does not set deleteMe = true, it // will keep hugging the terrain) p->SetPosition(p->pos * XZVector + UpVector * groundHeight * belowGround); p->Collision(); } } }
void CProjectileHandler::CheckUnitFeatureCollisions(ProjectileContainer& pc) { static std::vector<CUnit*> tempUnits; static std::vector<CFeature*> tempFeatures; static std::vector<CPlasmaRepulser*> tempRepulsers; for (size_t i = 0; i < pc.size(); ++i) { CProjectile* p = pc[i]; if (!p->checkCol) continue; if ( p->deleteMe) continue; const float3 ppos0 = p->pos; const float3 ppos1 = p->pos + p->speed; quadField->GetUnitsAndFeaturesColVol(p->pos, p->radius + p->speed.w, tempUnits, tempFeatures, &tempRepulsers); CheckShieldCollisions(p, tempRepulsers, ppos0, ppos1); tempRepulsers.clear(); CheckUnitCollisions(p, tempUnits, ppos0, ppos1); tempUnits.clear(); CheckFeatureCollisions(p, tempFeatures, ppos0, ppos1); tempFeatures.clear(); } }
void CProjectileHandler::UpdateProjectileContainer(ProjectileContainer& pc, bool synced) { // WARNING: // we can't use iterators here because ProjectileCreated // and ProjectileDestroyed events may add new projectiles // to the container! for (size_t i = 0; i < pc.size(); /*no-op*/) { CProjectile* p = pc[i]; assert(p != nullptr); assert(p->synced == synced); #ifdef USING_CREG assert(p->synced == !!(p->GetClass()->binder->flags & creg::CF_Synced)); #endif // creation if (p->callEvent) { if (synced || !UNSYNCED_PROJ_NOEVENT) eventHandler.ProjectileCreated(p, p->GetAllyteamID()); eventHandler.RenderProjectileCreated(p); p->callEvent = false; } // deletion (FIXME: move outside of loop) if (p->deleteMe) { pc[i] = pc.back(); pc.pop_back(); eventHandler.RenderProjectileDestroyed(p); if (synced) { eventHandler.ProjectileDestroyed(p, p->GetAllyteamID()); syncedProjectileIDs[p->id] = nullptr; freeSyncedIDs.push_back(p->id); ASSERT_SYNCED(p->pos); ASSERT_SYNCED(p->id); } else { #if !UNSYNCED_PROJ_NOEVENT eventHandler.ProjectileDestroyed(p, p->GetAllyteamID()); unsyncedProjectileIDs[p->id] = nullptr; freeUnsyncedIDs.push_back(p->id); #endif } projMemPool.free(p); continue; } // neither ++i; } SCOPED_TIMER("Sim::Projectiles::Update"); // WARNING: same as above but for p->Update() for (size_t i = 0; i < pc.size(); ++i) { CProjectile* p = pc[i]; assert(p != nullptr); MAPPOS_SANITY_CHECK(p->pos); p->Update(); quadField->MovedProjectile(p); MAPPOS_SANITY_CHECK(p->pos); } }