void CProjectileHandler::CheckGroundCollisions(ProjectileContainer& pc) { ProjectileContainer::iterator pci; for (pci = pc.begin(); pci != pc.end(); ++pci) { CProjectile* p = *pci; 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 = ground->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 = belowGround? groundHeight: 0.0f; p->Collision(); } } }
void CGround::CheckCol(CProjectileHandler* ph) { Projectile_List::iterator psi; for (psi = ph->ps.begin(); psi != ph->ps.end(); ++psi) { CProjectile* p = *psi; if (p->checkCol) { if (GetHeight(p->pos.x, p->pos.z) > p->pos.y /* - p->radius*/) { // too many projectiles seem to hit the ground before hitting // so remove the radius till a better fix is done p->Collision(); } } } }
void CProjectileHandler::CheckGroundCollisions(ProjectileContainer& pc) { ProjectileContainer::iterator pci; for (pci = pc.begin(); pci != pc.end(); ++pci) { CProjectile* p = *pci; if (p->checkCol) { // too many projectiles seem to impact the ground before // actually hitting so don't subtract the projectile radius if (ground->GetHeight(p->pos.x, p->pos.z) > p->pos.y /* - p->radius*/) { 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::CheckUnitCol() { Projectile_List::iterator psi; static std::vector<CUnit*> tempUnits(uh->MaxUnits(), NULL); static std::vector<CFeature*> tempFeatures(uh->MaxUnits(), NULL); CollisionQuery q; for (psi = ps.begin(); psi != ps.end(); ++psi) { CProjectile* p = (*psi); if (p->checkCol && !p->deleteMe) { const float3 ppos0 = p->pos; const float3 ppos1 = p->pos + p->speed; float speedf = p->speed.Length(); CUnit** endUnit = &tempUnits[0]; CFeature** endFeature = &tempFeatures[0]; qf->GetUnitsAndFeaturesExact(p->pos, p->radius + speedf, endUnit, endFeature); for (CUnit** ui = &tempUnits[0]; ui != endUnit; ++ui) { CUnit* unit = *ui; const bool friendlyShot = (p->owner() && (unit->allyteam == p->owner()->allyteam)); const bool raytraced = (unit->collisionVolume && unit->collisionVolume->GetTestType() == COLVOL_TEST_CONT); // if this unit fired this projectile or (this unit is in the // same allyteam as the unit that shot this projectile and we // are ignoring friendly collisions) if (p->owner() == unit || !unit->collisionVolume || ((p->collisionFlags & COLLISION_NOFRIENDLY) && friendlyShot)) { continue; } if (p->collisionFlags & COLLISION_NONEUTRAL) { if (unit->IsNeutral()) { continue; } } if (CCollisionHandler::DetectHit(unit, ppos0, ppos1, &q)) { // this projectile won't reach the raytraced surface impact pos // until Update() is called (right after we return, same frame) // which is a problem when dealing with fast low-AOE projectiles // since they would do almost no damage if detonated outside the // volume, so smuggle a bit ("rolling back" its pos in Update() // and waiting for the next-frame CheckUnitCol() is problematic // for noExplode projectiles) // const float3& pimpp = (q.b0)? q.p0: q.p1; const float3 pimpp = (q.b0 && q.b1)? (q.p0 + q.p1) * 0.5f: (q.b0 )? (q.p0 + ppos1) * 0.5f: (ppos0 + q.p1) * 0.5f; p->pos = (raytraced)? pimpp: ppos0; p->Collision(unit); p->pos = (raytraced)? ppos0: p->pos; break; } } if (!(p->collisionFlags & COLLISION_NOFEATURE)) { for (CFeature** fi = &tempFeatures[0]; fi != endFeature; ++fi) { CFeature* feature = *fi; const bool raytraced = (feature->collisionVolume && feature->collisionVolume->GetTestType() == COLVOL_TEST_CONT); // geothermals do not have a collision volume, skip them if (!feature->blocking || feature->def->geoThermal || !feature->collisionVolume) { continue; } if (CCollisionHandler::DetectHit(feature, ppos0, ppos1, &q)) { const float3 pimpp = (q.b0 && q.b1)? (q.p0 + q.p1) * 0.5f: (q.b0 )? (q.p0 + ppos1) * 0.5f: (ppos0 + q.p1) * 0.5f; p->pos = (raytraced)? pimpp: ppos0; p->Collision(feature); p->pos = (raytraced)? ppos0: p->pos; break; } } } } } }