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();
		}
	}
}
Example #2
0
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();
		}
	}
}
Example #3
0
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();
	}
}
Example #4
0
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);
	}
}