//------------------------------------------------------------------------
void CVehicleSeatActionRotateTurret::UpdatePartRotation(EVehicleTurretRotationType eType, float frameTime)
{
	CRY_ASSERT( eType < eVTRT_NumRotationTypes );

	const float threshold = 0.01f;
	if (frameTime > 0.08f) frameTime = 0.08f;

	CVehiclePartBase* pPart   = m_rotations[eType].m_pPart;
	IVehiclePart*     pParent = pPart->GetParent();
	IActor*           pActor  = m_pSeat->GetPassengerActor();

	float rot_dir      = fsgnf(m_rotations[eType].m_action);
	float max_rotation = fabsf(m_rotations[eType].m_action);
	float rot_speed    = DEG2RAD(fabsf(m_rotations[eType].m_speed)) * GetDamageSpeedMul(pPart);

	float delta = rot_dir * rot_speed  * frameTime;
	delta += m_rotations[eType].m_aimAssist;

	delta = fmod(delta, gf_PI2);
	if (delta > gf_PI)  delta -= gf_PI2;
	if (delta < -gf_PI) delta += gf_PI2;

	Limit( delta, -max_rotation, max_rotation);

	Ang3 deltaAngles(ZERO);
	if (eType == eVTRT_Pitch)
		deltaAngles.x = delta;
	else if (eType == eVTRT_Yaw)
		deltaAngles.z = delta;
	else
		CRY_ASSERT(false && "Unknown turret rotation");

	Matrix34 tm     = pPart->GetLocalBaseTM();
	Ang3     angles = Ang3::GetAnglesXYZ(tm) + deltaAngles;

	float lerp = 0.f;
	if (eType == eVTRT_Pitch)
	{
		Vec3 yAxis = m_rotations[eVTRT_Yaw].m_pPart->GetLocalBaseTM().GetColumn1();
		yAxis.z = 0.f;
		yAxis.normalize();
		lerp = 0.5f - 0.5f * yAxis.y;
		Limit(lerp, 0.0f, 1.0f);
	}

	// clamp to limits
	if (m_rotations[eType].m_minLimitF != 0.0f || m_rotations[eType].m_maxLimit != 0.0f)
	{
		// Different clamp angles facing forwards/backwards
		float minLimit = m_rotations[eType].m_minLimitF + (m_rotations[eType].m_minLimitB - m_rotations[eType].m_minLimitF) * lerp;
		float angle    = (eType == eVTRT_Pitch) ? angles.x : angles.z;
		if (angle > m_rotations[eType].m_maxLimit || angle < minLimit)
		{
			angle                             = clamp_tpl(angle, minLimit, m_rotations[eType].m_maxLimit);
			m_rotations[eType].m_currentValue = 0.f;

			if (eType == eVTRT_Pitch)
				angles.x = angle;
			else
				angles.z = angle;
		}
	}

	m_rotations[eType].m_orientation.Set(Quat::CreateRotationXYZ(angles));
	m_rotations[eType].m_orientation.Update(frameTime);

	m_rotations[eType].m_action    = 0.0f;
	m_rotations[eType].m_aimAssist = 0.0f;

	Matrix34 newTM(m_rotations[eType].m_orientation.Get().GetNormalized());
	newTM.SetTranslation(tm.GetTranslation());
	pPart->SetLocalBaseTM(newTM);

	// store world-space rotation
	const Matrix34 &worldTM = pPart->GetWorldTM();
	m_rotations[eType].m_prevWorldQuat = Quat(worldTM);
	CRY_ASSERT(m_rotations[eType].m_prevWorldQuat.IsValid());

	// now update the turret sound based on the calculated rotation speed
	UpdateRotationSound(eType, delta, frameTime);

}
//------------------------------------------------------------------------------------
// Adjust the aim dir before we pass it to the torsoAim pose modifier, this allows us
// to have the weapon deviate from the camera in certain circumstances
// Should only be called once per frame as it time-steps internal vars
//------------------------------------------------------------------------------------
void CLocalPlayerComponent::AdjustTorsoAimDir(float fFrameTime, Vec3 &aimDir)
{
	const f32 HALF_PI = gf_PI * 0.5f;
	float newElevLimit = HALF_PI;

	const f32 MIN_FLATTEN_LEVEL		= -0.3f;
	const f32 MAX_FLATTEN_LEVEL		= -0.1f;
	const f32 TARGET_FLATTEN_ELEV	= -0.2f;
	const f32 LIMIT_CHANGE_RATE		= HALF_PI;

	if (g_pGameCVars->pl_swimAlignArmsToSurface && m_rPlayer.IsSwimming() && (m_rPlayer.m_playerStateSwim_WaterTestProxy.GetRelativeWaterLevel() > MIN_FLATTEN_LEVEL))
	{
		newElevLimit = (m_rPlayer.m_playerStateSwim_WaterTestProxy.GetRelativeWaterLevel() - MIN_FLATTEN_LEVEL) / (MAX_FLATTEN_LEVEL - MIN_FLATTEN_LEVEL);
		newElevLimit = LERP(gf_PI * 0.5f, TARGET_FLATTEN_ELEV, clamp_tpl(newElevLimit, 0.0f, 1.0f));
	}

	float limitDelta = LIMIT_CHANGE_RATE * fFrameTime;
	float limitDiff	 = newElevLimit - m_stapElevLimit;
	float smoothedLimit = (float) fsel(fabs_tpl(limitDiff) - limitDelta, m_stapElevLimit + (fsgnf(limitDiff) * limitDelta), newElevLimit);
	m_stapElevLimit = smoothedLimit;

	if (smoothedLimit < HALF_PI)
	{
		//--- Need to limit, convert to yaw & elev, limit & then convert back
		float yaw, elev;
		float xy = aimDir.GetLengthSquared2D();
		if (xy > 0.001f)
		{
			yaw = atan2_tpl(aimDir.y,aimDir.x);
			elev = asin_tpl(clamp_tpl(aimDir.z, -1.f, +1.f));
		}
		else
		{
			yaw = 0.f;
			elev = (float)fsel(aimDir.z, +1.f, -1.f) * (gf_PI*0.5f);
		}

		elev = min(elev, smoothedLimit);

		float sinYaw, cosYaw;
		float sinElev, cosElev;

		sincos_tpl(yaw, &sinYaw, &cosYaw);
		sincos_tpl(elev, &sinElev, &cosElev);

		aimDir.x = cosYaw * cosElev;
		aimDir.y = sinYaw * cosElev;
		aimDir.z = sinElev;
	}
}
Ejemplo n.º 3
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;
}
Ejemplo n.º 4
0
void CNetPlayerInput::UpdateMoveRequest()
{
	CMovementRequest moveRequest;
	SMovementState moveState;
	m_pPlayer->GetMovementController()->GetMovementState(moveState);
	Quat worldRot = m_pPlayer->GetBaseQuat(); // m_pPlayer->GetEntity()->GetWorldRotation();
	Vec3 deltaMovement = worldRot.GetInverted().GetNormalized() * m_curInput.deltaMovement;
	// absolutely ensure length is correct
	deltaMovement = deltaMovement.GetNormalizedSafe(ZERO) * m_curInput.deltaMovement.GetLength();
	moveRequest.AddDeltaMovement( deltaMovement );
	if( IsDemoPlayback() )
	{
		Vec3 localVDir(m_pPlayer->GetViewQuatFinal().GetInverted() * m_curInput.lookDirection);
		Ang3 deltaAngles(asinf(localVDir.z),0,atan2_tpl(-localVDir.x,localVDir.y));
		moveRequest.AddDeltaRotation(deltaAngles*gEnv->pTimer->GetFrameTime());
	}
	
	const float fNetAimLerpFactor = g_pGameCVars->pl_netAimLerpFactor;

	//Vector slerp produces artifacts here, using a per-component lerp instead
	Vec3 vCurrentRight			= m_lookDir.cross(Vec3Constants<float>::fVec3_OneZ);
	Vec3 vCurrentProjected = -(vCurrentRight.cross(Vec3Constants<float>::fVec3_OneZ));
	vCurrentRight.Normalize();
	vCurrentProjected.Normalize();

	Vec3 vNewRight					= m_curInput.lookDirection.cross(Vec3Constants<float>::fVec3_OneZ);
	Vec3 vNewProjected			= -(vNewRight.cross(Vec3Constants<float>::fVec3_OneZ));
	vNewProjected.Normalize();

	float fRotZDirDot	= vNewProjected.dot(vCurrentRight);
	float fRotZDot		= vNewProjected.dot(vCurrentProjected);
	float fRotZ				= acos_tpl(fRotZDot);

	fRotZ = AngleWrap_PI(fRotZ);

	float fRotZFinal	= -fsgnf(fRotZDirDot) * fRotZ * fNetAimLerpFactor;

	float fCurrentAngle = acos_tpl(Vec3Constants<float>::fVec3_OneZ.dot(m_lookDir));
	float fNewAngle			= acos_tpl(Vec3Constants<float>::fVec3_OneZ.dot(m_curInput.lookDirection));

	float fRotXFinal = (fNewAngle - fCurrentAngle) * -fNetAimLerpFactor;

	//Rotate around X first, as we have already generated the right vector
	Vec3 vNewLookDir = m_lookDir.GetRotated(vCurrentRight, fRotXFinal);

	m_lookDir = vNewLookDir.GetRotated(Vec3Constants<float>::fVec3_OneZ, fRotZFinal);

	Vec3 distantTarget = moveState.eyePosition + 1000.0f * m_lookDir;
	Vec3 lookTarget = distantTarget;

	if (m_curInput.usinglookik)
		moveRequest.SetLookTarget( lookTarget );
	else
		moveRequest.ClearLookTarget();

	if (m_curInput.aiming)
		moveRequest.SetAimTarget( lookTarget );
	else
		moveRequest.ClearAimTarget();

	if (m_curInput.deltaMovement.GetLengthSquared() > sqr(0.02f)) // 0.2f is almost stopped
		moveRequest.SetBodyTarget( distantTarget );
	else
		moveRequest.ClearBodyTarget();

	moveRequest.SetAllowStrafing(m_curInput.allowStrafing);

	moveRequest.SetPseudoSpeed(CalculatePseudoSpeed());

	moveRequest.SetStance( (EStance)m_curInput.stance );

	m_pPlayer->GetMovementController()->RequestMovement(moveRequest);

	if (m_curInput.sprint)
		m_pPlayer->m_actions |= ACTION_SPRINT;
	else
		m_pPlayer->m_actions &= ~ACTION_SPRINT;

#if 0
	if (m_pPlayer->m_netSetPosition)
	{
		SPredictedCharacterStates charStates;
		charStates.states[0].position		 = m_pPlayer->GetEntity()->GetPos();
		charStates.states[0].orientation = m_pPlayer->GetEntity()->GetRotation();
		charStates.states[0].deltatime	 = 0.0f;

		charStates.states[1].position		 = m_pPlayer->m_netCurrentLocation;
		charStates.states[1].orientation = m_pPlayer->GetEntity()->GetRotation();
		charStates.states[1].deltatime	 = gEnv->pTimer->GetFrameTime();

		charStates.states[2].position		 = m_pPlayer->m_netDesiredLocation;
		charStates.states[2].orientation = m_pPlayer->GetEntity()->GetRotation();
		charStates.states[2].deltatime	 = m_pPlayer->m_netLerpTime;
		charStates.nStates = 3;

		moveRequest.SetPrediction(charStates);
	}
#endif //0

#if !defined(_RELEASE)
	// debug..
	if (g_pGameCVars->g_debugNetPlayerInput & 2)
	{
		IPersistantDebug * pPD = gEnv->pGame->GetIGameFramework()->GetIPersistantDebug();
		pPD->Begin( string("update_player_input_") + m_pPlayer->GetEntity()->GetName(), true );
		Vec3 wp = m_pPlayer->GetEntity()->GetWorldPos();
		wp.z += 2.0f;
		pPD->AddSphere( moveRequest.GetLookTarget(), 0.5f, ColorF(1,0,1,0.3f), 1.0f );
		//		pPD->AddSphere( moveRequest.GetMoveTarget(), 0.5f, ColorF(1,1,0,0.3f), 1.0f );
		pPD->AddDirection( m_pPlayer->GetEntity()->GetWorldPos() + Vec3(0,0,2), 1, m_curInput.deltaMovement, ColorF(1,0,0,0.3f), 1.0f );
	}
#endif

	//m_curInput.deltaMovement.zero();
}