Esempio n. 1
0
void CPlayerStateJump::GetDesiredVelocity( const Vec3 & move, const CPlayer &player, Vec3* pDesiredVel ) const
{
	// Generate jump velocity.
	SIMDFConstant(xmfMaxMove, 1.0f);

	simdf fGroundNormalZ = xmfMaxMove;

	hwvec3 xmMove  = HWVLoadVecUnaligned(&move);	
	if( move.len2() > 0.01f )
	{
		const Matrix34A baseMtx = Matrix34A(player.GetBaseQuat());
		Matrix34A baseMtxZ(baseMtx * Matrix33::CreateScale(Vec3(0,0,1)));
		baseMtxZ.SetTranslation(Vec3(0,0,0));

		hwmtx33 xmBaseMtxZ;
		HWMtx33LoadAligned(xmBaseMtxZ, baseMtxZ);
		hwmtx33 xmBaseMtxZOpt = HWMtx33GetOptimized(xmBaseMtxZ);

		hwvec3 xmDesiredVel = HWV3Zero();
		if (player.IsRemote())
		{
			xmDesiredVel = xmMove;
		}
		else
		{
			hwvec3 xmVelocity = HWVLoadVecUnaligned(&player.GetActorPhysics().velocity);

			SIMDFConstant(xmfZero, 0.0f);
			SIMDFConstant(xmfDiffMultiplier, 0.3f);
			SIMDFConstant(xmfMaxDiff, 0.1f);
			SIMDFConstant(xmfMinMove, 0.5f);
			SIMDFConstant(xmfOnePointFive, 1.5f);

			hwvec3 xmMoveFlat		= HWVSub(xmMove, 		HWMtx33RotateVecOpt(xmBaseMtxZOpt, xmMove));
			hwvec3 xmCurrVelFlat	= HWVSub(xmVelocity,	HWMtx33RotateVecOpt(xmBaseMtxZOpt, xmVelocity));

			simdf xmfCurrVelSizeSq	= HWV3LengthSq(xmCurrVelFlat);

			hwvec3 xmMoveFlatNormalized		= HWV3Normalize(xmMoveFlat);
			hwvec3 xmCurDirFlatTemp			= HWV3Normalize(xmCurrVelFlat);

			hwvec3 xmCurVelFlatNormalized	= HWVSelectSIMDF(xmCurDirFlatTemp, HWV3Zero(), SIMDFLessThanEqual(xmfCurrVelSizeSq, xmfZero));

			simdf fDot = HWV3Dot(xmMoveFlatNormalized, xmCurVelFlatNormalized);

			hwvec3 xmScaledMoveFlat = HWVMultiplySIMDF(xmMoveFlat, SIMDFClamp(fDot, xmfMinMove, xmfMaxMove));
			simdf fMoveMult = SIMDFMax(SIMDFMult(SIMDFAbs(fDot), xmfDiffMultiplier), xmfMaxDiff);

			hwvec3 xmReducedMove = HWVMultiplySIMDF(HWVSub(xmMoveFlat, xmCurrVelFlat), fMoveMult);

			xmDesiredVel = HWVSelectSIMDF( xmScaledMoveFlat, xmReducedMove, SIMDFLessThan( fDot, xmfZero ));

			simdf xmfDesiredVelSizeSq = HWV3LengthSq(xmDesiredVel);

			hwvec3 xmDesiredVelNorm = HWV3Normalize(xmDesiredVel);

			hwvec3 xmClampedVel = HWVMultiplySIMDF(xmDesiredVelNorm, SIMDFMax( xmfOnePointFive, SIMDFSqrt(xmfCurrVelSizeSq)));

			xmDesiredVel = HWVSelectSIMDF( xmClampedVel, xmDesiredVel, SIMDFLessThan( xmfDesiredVelSizeSq, xmfCurrVelSizeSq));
		}

		HWVSaveVecUnaligned(pDesiredVel, xmDesiredVel);
	}
}
Esempio n. 2
0
bool CPlayerStateSwim::OnPrePhysicsUpdate( CPlayer& player, const SActorFrameMovementParams& movement, float frameTime )
{
	const CPlayerStateSwim_WaterTestProxy& waterProxy = player.m_playerStateSwim_WaterTestProxy;

	CPlayerStateUtil::PhySetFly( player );

	const SPlayerStats& stats = player.m_stats;

#ifdef STATE_DEBUG
	const bool debug = (g_pGameCVars->cl_debugSwimming != 0);
#endif
	
	const Vec3 entityPos = player.GetEntity()->GetWorldPos();
	const Quat baseQuat = player.GetBaseQuat();
	const Vec3 vRight(baseQuat.GetColumn0());
	
	Vec3 velocity = player.GetActorPhysics().velocity;

	// Underwater timer, sounds update and surface wave speed.
	if (waterProxy.IsHeadUnderWater())
	{
		m_headUnderWaterTimer += frameTime;
		if (m_headUnderWaterTimer <= -0.0f && !m_onSurface )
		{
			player.PlaySound(CPlayer::ESound_DiveIn, true, "speed", velocity.len());
			m_headUnderWaterTimer = 0.0f;
		}

		player.PlaySound(CPlayer::ESound_Underwater, true);
	}
	else
	{
		m_headUnderWaterTimer -= frameTime;			
		if (m_headUnderWaterTimer >= 0.0f && (waterProxy.IsHeadComingOutOfWater() || m_onSurface))
		{
			player.PlaySound(CPlayer::ESound_DiveOut, true, "speed", velocity.len());
			m_headUnderWaterTimer = 0.0f;
		}

		player.PlaySound(CPlayer::ESound_Underwater, false);
	}
	m_headUnderWaterTimer = clamp_tpl( m_headUnderWaterTimer, -0.2f, 0.2f );

	// Apply water flow velocity to the player
	Vec3 gravity;
	pe_params_buoyancy buoyancy[s_maxWaterVolumesToConsider];
	if (int count = gEnv->pPhysicalWorld->CheckAreas(entityPos, gravity, &buoyancy[0], s_maxWaterVolumesToConsider))
	{
		for(int i = 0; i < count && i < s_maxWaterVolumesToConsider; ++i)
		{
			// 0 is water
			if( buoyancy[i].iMedium == 0 )
			{
				velocity += (buoyancy[i].waterFlow * frameTime);
			}
		}
	}

	// Calculate desired acceleration (user input)	
	Vec3 desiredWorldVelocity(ZERO);

	Vec3 acceleration(ZERO);
	{
		Vec3 desiredLocalNormalizedVelocity(ZERO);
		Vec3 desiredLocalVelocity(ZERO);

		const Quat viewQuat = player.GetViewQuat();

		const float backwardMultiplier = (float)__fsel(movement.desiredVelocity.y, 1.0f, g_pGameCVars->pl_swimBackSpeedMul);
		desiredLocalNormalizedVelocity.x = movement.desiredVelocity.x * g_pGameCVars->pl_swimSideSpeedMul;
		desiredLocalNormalizedVelocity.y = movement.desiredVelocity.y * backwardMultiplier;

		float sprintMultiplier = 1.0f;
		if ((player.IsSprinting()) && !player.IsCinematicFlagActive(SPlayerStats::eCinematicFlag_RestrictMovement))
		{
			sprintMultiplier = GetSwimParams().m_swimSprintSpeedMul;

			// Higher speed multiplier when sprinting while looking up
			const float upFraction = clamp_tpl(viewQuat.GetFwdZ(), 0.0f, 1.0f);
			sprintMultiplier *= LERP(1.0f, GetSwimParams().m_swimUpSprintSpeedMul, upFraction);
		}

		const float baseSpeed = player.GetStanceMaxSpeed(STANCE_SWIM);
		desiredLocalVelocity.x = desiredLocalNormalizedVelocity.x * sprintMultiplier * baseSpeed;
		desiredLocalVelocity.y = desiredLocalNormalizedVelocity.y * sprintMultiplier * baseSpeed;
		desiredLocalVelocity.z = desiredLocalNormalizedVelocity.z * g_pGameCVars->pl_swimVertSpeedMul * baseSpeed;

		// The desired movement is applied in view-space, not in entity-space, since entity does not necessarily pitch while swimming.
		desiredWorldVelocity += viewQuat.GetColumn0() * desiredLocalVelocity.x;
		desiredWorldVelocity += viewQuat.GetColumn1() * desiredLocalVelocity.y;

		// though, apply up/down in world space.
		desiredWorldVelocity.z += desiredLocalVelocity.z;

#ifdef STATE_DEBUG
		if (debug)
		{
			gEnv->pRenderer->DrawLabel(entityPos - vRight * 1.5f + Vec3(0,0,0.8f), 1.5f, "BaseSpeed %1.3f", baseSpeed);
			gEnv->pRenderer->DrawLabel(entityPos - vRight * 1.5f + Vec3(0,0,1.0f), 1.5f, "SprintMul %1.2f", sprintMultiplier);
			gEnv->pRenderer->DrawLabel(entityPos - vRight * 1.5f + Vec3(0,0,0.6f), 1.5f, "MoveN[%1.3f, %1.3f, %1.3f]", desiredLocalNormalizedVelocity.x, desiredLocalNormalizedVelocity.y, desiredLocalNormalizedVelocity.z);
			gEnv->pRenderer->DrawLabel(entityPos - vRight * 1.5f + Vec3(0,0,0.5f), 1.5f, "VeloL[%1.3f, %1.3f, %1.3f]", desiredLocalVelocity.x, desiredLocalVelocity.y, desiredLocalVelocity.z);
			gEnv->pRenderer->DrawLabel(entityPos - vRight * 1.5f + Vec3(0,0,0.4f), 1.5f, "VeloW[%1.3f, %1.3f, %1.3f]", desiredWorldVelocity.x, desiredWorldVelocity.y, desiredWorldVelocity.z);
		}
#endif

		//Remove a bit of control when entering the water
		const float userControlFraction = (float)__fsel(0.3f - waterProxy.GetSwimmingTimer(), 0.2f, 1.0f); 
		acceleration += desiredWorldVelocity * userControlFraction;
	}

	// Apply acceleration (frame-rate independent)
	const float accelerateDelayInv = 3.333f;
	velocity += acceleration * (frameTime * accelerateDelayInv);

#ifdef STATE_DEBUG
	if( debug )
	{
		gEnv->pRenderer->DrawLabel(entityPos - vRight * 1.5f - Vec3(0,0,0.2f), 1.5f, " Axx[%1.3f, %1.3f, %1.3f]", acceleration.x, acceleration.y, acceleration.z);
	}
#endif

	//--------------------

	const float relativeWaterLevel = waterProxy.GetRelativeWaterLevel() + 0.1f;
	const float surfaceDistanceFraction = clamp_tpl(fabsf(relativeWaterLevel), 0.0f, 1.0f);
	float surfaceProximityInfluence = 1.0f - surfaceDistanceFraction;
	const float verticalVelocityFraction = clamp_tpl((fabsf(desiredWorldVelocity.z) - 0.3f) * 2.5f, 0.0f, 1.0f);
	surfaceProximityInfluence = surfaceProximityInfluence * (1.0f - verticalVelocityFraction);

	// Apply velocity dampening (frame-rate independent)
	Vec3 damping(ZERO);

	const float zSpeedPreDamping = velocity.z;

	{
		damping.x = fabsf(velocity.x);
		damping.y = fabsf(velocity.y);

		// Vertical damping is special, to allow jumping out of water with higher speed, 
		// and also not sink too deep when falling down ito the water after jump or such.
		float zDamp = 1.0f + (6.0f * clamp_tpl((-velocity.z - 1.0f) * 0.333f, 0.0f, 1.0f));
		zDamp *= 1.0f - surfaceProximityInfluence;

		damping.z = fabsf(velocity.z) * zDamp;

		const float stopDelayInv = 3.333f;
		damping *= (frameTime * stopDelayInv);
		velocity.x = (float)__fsel((fabsf(velocity.x) - damping.x), (velocity.x - fsgnf(velocity.x) * damping.x), 0.0f);
		velocity.y = (float)__fsel((fabsf(velocity.y) - damping.y), (velocity.y - fsgnf(velocity.y) * damping.y), 0.0f);
		velocity.z = (float)__fsel((fabsf(velocity.z) - damping.z), (velocity.z - fsgnf(velocity.z) * damping.z), 0.0f);
		
		//Make sure you can not swim above the surface
		if ((relativeWaterLevel >= 0.0f) && (velocity.z > 0.0f))
		{
			velocity.z = 0.0f;
		}
	}

	// Decide if we're on the surface and therefore need to be kept there..
	if( relativeWaterLevel > -0.2f && relativeWaterLevel < 1.0f && fabs_tpl( zSpeedPreDamping ) < 0.5f )
	{
		if( !waterProxy.IsHeadUnderWater() )
		{
			m_onSurface = true;
		}
	}
	else
	{
		// we only leave the surface if the player moves, otherwise we try and keep the 
		// player on the surface, even if they currently arent
		m_onSurface = false;
	}

	// Calculate and apply surface movement to the player.
	float speedDelta = 0.0f;
	if( m_onSurface )
	{
		const float newWaterLevel = waterProxy.GetWaterLevel();
		const float waterLevelDelta = clamp_tpl(newWaterLevel - m_lastWaterLevel, -1.0f, 1.0f );
		const float newCheckedTime = waterProxy.GetWaterLevelTimeUpdated();
		const float timeDelta = newCheckedTime - m_lastWaterLevelTime;

		if( timeDelta > FLT_EPSILON )
		{
			speedDelta = waterLevelDelta/timeDelta;

			velocity.z += speedDelta;
		}

		m_lastWaterLevel = newWaterLevel;
		m_lastWaterLevelTime = newCheckedTime;
	}

	// Set request type and velocity
	player.GetMoveRequest().type = eCMT_Fly;
	player.GetMoveRequest().velocity = velocity;

#ifdef STATE_DEBUG
	// DEBUG VELOCITY
	if (debug)
	{
		gEnv->pRenderer->DrawLabel(entityPos - vRight * 1.5f - Vec3(0,0,0.0f), 1.5f, "Velo[%1.3f, %1.3f, %1.3f]", velocity.x, velocity.y, velocity.z);
		gEnv->pRenderer->DrawLabel(entityPos - vRight * 1.5f - Vec3(0,0,0.4f), 1.5f, "Damp[%1.3f, %1.3f, %1.3f]", damping.x, damping.y, damping.z);
		gEnv->pRenderer->DrawLabel(entityPos - vRight * 1.5f - Vec3(0,0,0.6f), 1.5f, "FrameTime %1.4f", frameTime);
		gEnv->pRenderer->DrawLabel(entityPos - vRight * 1.5f + Vec3(0,0,0.3f), 1.5f, "DeltaSpeed[%1.3f]", speedDelta );
		//if (bNewSwimJumping)
			//gEnv->pRenderer->DrawLabel(entityPos - vRight * 0.15f + Vec3(0,0,0.6f), 2.0f, "JUMP");
	}
#endif

	return true;
}