Beispiel #1
0
//-----------------------------------------------------------------------
bool CSpectacularKill::ObstacleCheck(const Vec3& vKillerPos, const Vec3& vTargetPos, const SSpectacularKillAnimation& anim) const
{
	// [*DavidR | 13/Sep/2010] ToDo: Find a way to make this asynchronously
	const float OBSTACLE_CHECK_RADIUS = 0.6f;
	const float OBSTACLE_CHECK_GROUND_OFFSET = 0.2f;

	const Vec3& vCapsuleKillerEnd = vKillerPos + anim.vKillerObstacleCheckOffset;

	primitives::capsule capsPrim;
	const Vec3& vKillerToTargetDist = vTargetPos - vCapsuleKillerEnd;
	capsPrim.axis = vKillerToTargetDist.GetNormalized();
	capsPrim.r = OBSTACLE_CHECK_RADIUS;

	// hh is actually half the total height (it's measured from the center)
	capsPrim.hh = static_cast<float>(__fsel(anim.fObstacleCheckLength, 
				(anim.fObstacleCheckLength * 0.5f) - capsPrim.r,
				(min(g_pGameCVars->g_spectacularKill.maxDistanceError, vKillerToTargetDist.GetLength()) * 0.5f) - capsPrim.r));

	capsPrim.center = vCapsuleKillerEnd + (capsPrim.axis * (capsPrim.hh + capsPrim.r));
	capsPrim.center.z += capsPrim.r + OBSTACLE_CHECK_GROUND_OFFSET;

	geom_contact* pContact = NULL;
	int collisionEntityTypes = ent_static | ent_terrain | ent_sleeping_rigid | ent_ignore_noncolliding;
	float d = gEnv->pPhysicalWorld->PrimitiveWorldIntersection(capsPrim.type, &capsPrim, Vec3Constants<float>::fVec3_Zero, collisionEntityTypes, &pContact, 0, geom_colltype0);

	bool bObstacleFound = (d != 0.0f) && pContact;

#ifndef _RELEASE
	if (bObstacleFound && (g_pGameCVars->g_spectacularKill.debug > 1))
	{
		const float fTime = 6.0f;

		// visually show why it failed
		IPersistantDebug* pPersistantDebug = BeginPersistantDebug();

		// Draw a capsule using a cylinder and two spheres
		const ColorF debugColor = Col_Coral * ColorF(1.0f, 1.0f, 1.0f, 0.6f);
		pPersistantDebug->AddCylinder(capsPrim.center, capsPrim.axis, capsPrim.r, capsPrim.hh * 2.0f, debugColor, fTime);
		pPersistantDebug->AddSphere(capsPrim.center - (capsPrim.axis * capsPrim.hh), capsPrim.r, debugColor, fTime);
		pPersistantDebug->AddSphere(capsPrim.center + (capsPrim.axis * capsPrim.hh), capsPrim.r, debugColor, fTime);

		for (int i = 0; i < (int)d; ++i)
		{
		// Draw the collision point
			geom_contact collisionData(pContact[i]);
		pPersistantDebug->AddCone(collisionData.pt, -collisionData.n, 0.1f, 0.8f, Col_Red, fTime + 2.0f);
	}
	}
#endif

	return bObstacleFound;
}
	virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
	{
#if !defined(_RELEASE)
		if (event == eFE_Activate)
		{
			if (IsPortActive(pActInfo, eIP_Draw))
			{
				IPersistantDebug* pPersistentDebug = CCryAction::GetCryAction()->GetIPersistantDebug();
				if (pPersistentDebug)
				{
					const Vec3 pos = GetPortVec3(pActInfo, eIP_Pos);
					const Vec3 dir = GetPortVec3(pActInfo, eIP_Dir);
					const float radius = GetPortFloat(pActInfo, eIP_Radius);
					const float height = GetPortFloat(pActInfo, eIP_Height);
					const float time = GetPortFloat(pActInfo, eIP_Time);
					const ColorF color = GetPortVec3(pActInfo, eIP_Color);

					pPersistentDebug->Begin("FG_Cone", false);
					pPersistentDebug->AddCone(pos, dir, radius, height, color, time);
				}
			}
		}
#endif
	}
Beispiel #3
0
	bool operator() (const SSpectacularKillAnimation& killAnim) const
	{
		const SSpectacularKillCVars& skCVars = g_pGameCVars->g_spectacularKill;
		const CActor* pOwner = m_spectacularKill.m_pOwner;

		// 0. the anim shouldn't be redundant
		if (((gEnv->pTimer->GetFrameStartTime().GetSeconds() - s_lastKillInfo.timeStamp) <= skCVars.minTimeBetweenSameKills) &&
			(killAnim.killerAnimation.compare(s_lastKillInfo.killerAnim)))
		{
			SK_DEBUG_LOG("GetValidAnim - %s is not valid: This animation was last played %.1f ago, a minimum time of %.1f is required", 
				killAnim.killerAnimation.c_str(), (gEnv->pTimer->GetFrameStartTime().GetSeconds() - s_lastKillInfo.timeStamp), skCVars.minTimeBetweenSameKills);

			return true;
		}


		// 1. the killer needs to be within a certain distance from the target
		IEntity* pTargetEntity = m_pTarget->GetEntity();
		IEntity* pKillerEntity = pOwner->GetEntity();

		const QuatT& killerTransform = pOwner->GetAnimatedCharacter()->GetAnimLocation();
		const QuatT& targetTransform = m_pTarget->GetAnimatedCharacter()->GetAnimLocation();
		const Vec3& vKillerPos = killerTransform.t;
		const Vec3& vTargetPos = targetTransform.t;

		Vec2 vKillerToTarget = Vec2(vTargetPos) - Vec2(vKillerPos);
		float distance = vKillerToTarget.GetLength();

		const float optimalDistance = killAnim.optimalDist;
		if ((optimalDistance > 0.0f) && (fabs_tpl(distance - optimalDistance) > skCVars.maxDistanceError))
		{
#ifndef _RELEASE
			if (g_pGameCVars->g_spectacularKill.debug > 1)
			{
				// visually shows why it failed
				IPersistantDebug* pPersistantDebug = m_spectacularKill.BeginPersistantDebug();
				const float fConeHeight = killAnim.optimalDist + skCVars.maxDistanceError;
				pPersistantDebug->AddPlanarDisc(vTargetPos, killAnim.optimalDist - skCVars.maxDistanceError, killAnim.optimalDist + skCVars.maxDistanceError, Col_Coral, 6.0f);
				pPersistantDebug->AddLine(vKillerPos, vKillerPos + Vec3(0.f, 0.f, 5.0f), Col_Red, 6.f);
			}

			SK_DEBUG_LOG("GetValidAnim - %s is not valid: Distance between actors should be %.2f, is %.2f (max error is %f)", 
				killAnim.killerAnimation.c_str(), optimalDistance, distance, skCVars.maxDistanceError);
#endif

			return true;
		}


		// 2. The killer needs to be facing the target within cosLookToConeHalfAngleRadians angle
		Vec2 vKillerDir(killerTransform.GetColumn1()); // In decoupled catchup mode we need the animated character's orientation
		vKillerDir.Normalize();
		if (vKillerToTarget.GetNormalizedSafe().Dot(vKillerDir) <= skCVars.minKillerToTargetDotProduct)
		{
			SK_DEBUG_LOG("GetValidAnim - %s is not valid: Killer is not looking within %.2f degrees towards the target", 
				killAnim.killerAnimation.c_str(), RAD2DEG(acos_tpl(skCVars.minKillerToTargetDotProduct) * 2.0f));

			return true;
		}


		// 3. If specified, the killer needs to be within a certain angle range from a given reference orientation from the target
		// e.g. Specifying referenceAngle 180 means using the back of the target as the center of the angle range 
		// (imagine it as a cone) where the killer has to be for the kill to be valid
		if (killAnim.targetToKillerAngle >= 0.f)
		{
			const float referenceAngle = killAnim.targetToKillerAngle;

			// Find the reference vector which will be the center of the allowed angle range
			Vec2 vTargetDir(targetTransform.GetColumn1());
			vTargetDir.Normalize();

			// 2D rotation
			Vec2 vReferenceDir((vTargetDir.x * cosf(referenceAngle)) - (vTargetDir.y * sinf(referenceAngle)), 
				(vTargetDir.y * cosf(referenceAngle)) + (vTargetDir.x * sinf(referenceAngle)));

			if (vKillerToTarget.GetNormalizedSafe().Dot(-vReferenceDir) <= killAnim.targetToKillerMinDot)
			{
#ifndef _RELEASE
				if (g_pGameCVars->g_spectacularKill.debug > 1)
				{
					// visually shows why it failed
					IPersistantDebug* pPersistantDebug = m_spectacularKill.BeginPersistantDebug();
					const float fConeHeight = killAnim.optimalDist + skCVars.maxDistanceError;
					pPersistantDebug->AddCone(vTargetPos + (vReferenceDir * fConeHeight), -vReferenceDir, killAnim.targetToKillerMinDot * fConeHeight * 2.0f, fConeHeight, Col_Coral, 6.f);
					pPersistantDebug->AddLine(vKillerPos, vKillerPos + Vec3(0.f, 0.f, 5.0f), Col_Red, 6.f);
				}

				float targetToKillerDot = vTargetDir.GetNormalizedSafe().Dot(-vKillerToTarget);
				SK_DEBUG_LOG("GetValidAnim - %s is not valid: Killer is not within a %.2f degrees cone centered on the target's %.2f degrees. Killer is at %.2f angles respect the target", 
					killAnim.killerAnimation.c_str(), RAD2DEG(acos_tpl(killAnim.targetToKillerMinDot) * 2.0f), RAD2DEG(killAnim.targetToKillerAngle), RAD2DEG(acos_tpl(targetToKillerDot)));
#endif

				return true;
			}
		}

		SK_DEBUG_LOG("GetValidAnim - %s is valid", killAnim.killerAnimation.c_str());
		return false;
	}