Beispiel #1
0
void Physics::ResolveCollision(Shape& A, Shape& B, Collision& C)
{
	//Calculate relative velocity
	Vec2 rvel = B.vel - A.vel;

	//Project relative velocity onto normal
	double nvel = rvel * C.N;

	//If nvel is positive, the objects are moving away from each other
	if (nvel > 0.0)
		return;

	//Separate the objects (displacement proportional to mass)
	double A_invmass = A.invmass;
	double B_invmass = B.invmass;
	Vec2 displacement = 0.05 * C.penetration / (A_invmass + B_invmass) * C.N;
	A.Displace(-A_invmass * displacement);
	B.Displace(B_invmass * displacement);

	//Choose the lower restitution (probably not the best idea..)
	double e = min(A.restitution, B.restitution);

	//Calculate impulse scalar
	double j = -(1 + e) * nvel / (A.invmass + B.invmass);

	//Apply impulse
	Impulse(A, -j, C.N);
	Impulse(B, j, C.N);
}
//------------------------------------------------------------------------
bool CMelee::PerformRayTest(const Vec3 &pos, const Vec3 &dir, float strength, bool remote)
{
	IEntity *pOwner = m_pWeapon->GetOwner();
	IPhysicalEntity *pIgnore = pOwner ? pOwner->GetPhysics() : 0;
	ray_hit hit;
	int n = gEnv->pPhysicalWorld->RayWorldIntersection(pos, dir.normalized() * m_pShared->meleeparams.range, ent_all | ent_water,
			rwi_stop_at_pierceable | rwi_ignore_back_faces, &hit, 1, &pIgnore, pIgnore ? 1 : 0);

	//===================OffHand melee (also in PerformCylincerTest)===================
	if(m_ignoredEntity && (n > 0))
	{
		if(IEntity *pHeldObject = gEnv->pEntitySystem->GetEntity(m_ignoredEntity))
		{
			IPhysicalEntity *pHeldObjectPhysics = pHeldObject->GetPhysics();

			if(pHeldObjectPhysics == hit.pCollider)
			{
				return false;
			}
		}
	}

	//=================================================================================

	if (n > 0)
	{
		Hit(&hit, dir, strength, remote);
		Impulse(hit.pt, dir, hit.n, hit.pCollider, hit.partid, hit.ipart, hit.surface_idx, strength);
	}

	return n > 0;
}
// Compute the second friction constraint impulse
inline const Impulse ContactSolver::computeFriction2Impulse(decimal deltaLambda,
                                                        const ContactPointSolver& contactPoint)
                                                        const {
    return Impulse(-contactPoint.frictionVector2 * deltaLambda,
                   -contactPoint.r1CrossT2 * deltaLambda,
                   contactPoint.frictionVector2 * deltaLambda,
                   contactPoint.r2CrossT2 * deltaLambda);
}
void CMelee::ApplyMeleeDamage(const Vec3& point, const Vec3& dir, const Vec3& normal, IPhysicalEntity* physicalEntity,
															EntityId entityID, int partId, int ipart, int surfaceIdx, bool remote, int iPrim)
{
	const float blend = m_slideKick ? 0.4f : SATURATE(m_pMeleeParams->meleeparams.impulse_up_percentage);
	Vec3 impulseDir = Vec3(0, 0, 1) * blend + dir * (1.0f - blend);
	impulseDir.normalize();

	int hitTypeID = Hit(point, dir, normal, physicalEntity, entityID, partId, ipart, surfaceIdx, remote);

	IActor* pActor = gEnv->bMultiplayer && entityID ? g_pGame->GetIGameFramework()->GetIActorSystem()->GetActor(entityID) : NULL;
	if(!gEnv->bMultiplayer || !pActor) //MP handles melee impulses to actors in GameRulesClientServer.cpp. See: ClApplyActorMeleeImpulse)
	{
		Impulse(point, impulseDir, normal, physicalEntity, entityID, partId, ipart, surfaceIdx, hitTypeID, iPrim);
	}
}
//------------------------------------------------------------------------
bool CMelee::PerformCylinderTest(const Vec3 &pos, const Vec3 &dir, float strength, bool remote)
{
	IEntity *pOwner = m_pWeapon->GetOwner();
	IPhysicalEntity *pIgnore = pOwner ? pOwner->GetPhysics() : 0;
	IEntity *pHeldObject = NULL;

	if(m_ignoredEntity)
	{
		pHeldObject = gEnv->pEntitySystem->GetEntity(m_ignoredEntity);
	}

	primitives::cylinder cyl;
	cyl.r = 0.25f;
	cyl.axis = dir;
	cyl.hh = m_pShared->meleeparams.range / 2.0f;
	cyl.center = pos + dir.normalized() * cyl.hh;
	float n = 0.0f;
	geom_contact *contacts;
	intersection_params params;
	WriteLockCond lockContacts;
	params.bStopAtFirstTri = false;
	params.bNoBorder = true;
	params.bNoAreaContacts = true;
	n = gEnv->pPhysicalWorld->PrimitiveWorldIntersection(primitives::cylinder::type, &cyl, Vec3(ZERO),
			ent_rigid | ent_sleeping_rigid | ent_independent | ent_static | ent_terrain | ent_water, &contacts, 0,
			geom_colltype0 | geom_colltype_foliage | geom_colltype_player, &params, 0, 0, &pIgnore, pIgnore ? 1 : 0, lockContacts);
	int ret = (int)n;
	float closestdSq = 9999.0f;
	geom_contact *closestc = 0;
	geom_contact *currentc = contacts;

	for (int i = 0; i < ret; i++)
	{
		geom_contact *contact = currentc;

		if (contact)
		{
			IPhysicalEntity *pCollider = gEnv->pPhysicalWorld->GetPhysicalEntityById(contact->iPrim[0]);

			if (pCollider)
			{
				IEntity *pEntity = gEnv->pEntitySystem->GetEntityFromPhysics(pCollider);

				if (pEntity)
				{
					if ((pEntity == pOwner) || (pHeldObject && (pEntity == pHeldObject)))
					{
						++currentc;
						continue;
					}
				}

				float distSq = (pos - currentc->pt).len2();

				if (distSq < closestdSq)
				{
					closestdSq = distSq;
					closestc = contact;
				}
			}
		}

		++currentc;
	}

	if (closestc)
	{
		IPhysicalEntity *pCollider = gEnv->pPhysicalWorld->GetPhysicalEntityById(closestc->iPrim[0]);
		Hit(closestc, dir, strength, remote);
		Impulse(closestc->pt, dir, closestc->n, pCollider, closestc->iPrim[1], 0, closestc->id[1], strength);
	}

	return closestc != 0;
}
// Compute a penetration constraint impulse
inline const Impulse ContactSolver::computePenetrationImpulse(decimal deltaLambda,
                                                          const ContactPointSolver& contactPoint)
                                                          const {
    return Impulse(-contactPoint.normal * deltaLambda, -contactPoint.r1CrossN * deltaLambda,
                   contactPoint.normal * deltaLambda, contactPoint.r2CrossN * deltaLambda);
}