const Vec3 CPlayerStateJump::CalculateInAirJumpExtraVelocity( const CPlayer& player, const Vec3& desiredVelocity ) const { const SPlayerStats& stats = player.m_stats; const float speedUpFactor = 0.175f; Vec3 jumpExtraVelocity(0.0f, 0.0f, 0.0f); const SActorPhysics& actorPhysics = player.GetActorPhysics(); if (actorPhysics.velocity.z > 0.0f) { //Note: Desired velocity is flat (not 'z' component), so jumpHeight should not be altered jumpExtraVelocity = desiredVelocity * speedUpFactor; } else { //Note: this makes the jump feel less 'floaty', by accelerating the player slightly down // and compensates the extra traveled distance when going up const float g = actorPhysics.gravity.len(); if (g > 0.0f) { const float jumpHeightScale = 1.0f; const float jumpHeight = player.m_params.jumpHeight * jumpHeightScale; const float estimatedLandTime = sqrt_tpl(2.0f*jumpHeight*(1.0f/g)) * (1.0f - speedUpFactor); assert(estimatedLandTime > 0.0f); if (estimatedLandTime > 0.0f) { const float requiredGravity = (2.0f*jumpHeight)/(estimatedLandTime * estimatedLandTime); const float initialAccelerationScale = clamp_tpl((-actorPhysics.velocity.z * 0.6f), 0.0f, 1.0f); jumpExtraVelocity = (requiredGravity - g) * actorPhysics.gravity.GetNormalized() * initialAccelerationScale; } } } return jumpExtraVelocity; }
bool CAreaManager::QueryAudioAreas(Vec3 const& rPos, SAudioAreaInfo *pResults, size_t const nMaxResults, size_t& rNumResults) { rNumResults = 0; if (pResults != NULL) { // Make sure the area grid is recompiled, if needed, before accessing it UpdateDirtyAreas(); uint32 numAreas = 0; TAreaPointers const& rAreasAtPos(m_areaGrid.GetAreas(rPos)); TAreaPointers::const_iterator IterAreas(rAreasAtPos.begin()); TAreaPointers::const_iterator const IterAreasEnd(rAreasAtPos.end()); for (; IterAreas != IterAreasEnd; ++IterAreas) { CArea* const pArea = *IterAreas; #if defined(DEBUG_AREAMANAGER) if (!stl::find(m_apAreas, pArea)) { CryFatalError("<AreaManager>: area in entity-area-cache not found in overall areas list!"); } #endif // DEBUG_AREAMANAGER // check if Area is hidden IEntity const* const pAreaEntity = m_pEntitySystem->GetEntity(pArea->GetEntityID()); if (pAreaEntity && !pAreaEntity->IsHidden()) { size_t const nAttachedEntities = pArea->GetEntityAmount(); if (nAttachedEntities > 0) { for (size_t iEntity = 0; iEntity < nAttachedEntities; ++iEntity) { IEntity const* const pEntity = gEnv->pEntitySystem->GetEntity(pArea->GetEntityByIdx(iEntity)); if (pEntity != NULL) { IEntityAudioProxy const* const pAudioProxy = (IEntityAudioProxy*)pEntity->GetProxy(ENTITY_PROXY_AUDIO); if (pAudioProxy != NULL) { TAudioEnvironmentID const nEnvironmentID = pAudioProxy->GetEnvironmentID(); float const fEnvironmentFadeDistance = pAudioProxy->GetEnvironmentFadeDistance(); if (nEnvironmentID != INVALID_AUDIO_ENVIRONMENT_ID) { // This is optimized internally and might not recalculate but rather retrieve the cached data. bool const bIsPointWithin = (pArea->CalcPosType(INVALID_ENTITYID, rPos, false) == AREA_POS_TYPE_2DINSIDE_ZINSIDE); float fEnvironmentAmount = 0.0f; if (!bIsPointWithin && (fEnvironmentFadeDistance > 0.0f)) { Vec3 Closest3d(ZERO); float const fDistance = sqrt_tpl(pArea->CalcPointNearDistSq(INVALID_ENTITYID, rPos, Closest3d, false)); if (fDistance <= fEnvironmentFadeDistance) { fEnvironmentAmount = 1.0f - (fDistance/fEnvironmentFadeDistance); } } else { fEnvironmentAmount = 1.0f; } if (fEnvironmentAmount > 0.0f) { // still have room to put it in? if (rNumResults == nMaxResults) return false; // found area that should go into the results pResults[rNumResults].pArea = pArea; pResults[rNumResults].fEnvironmentAmount = fEnvironmentAmount; pResults[rNumResults].nEnvironmentID = nEnvironmentID; pResults[rNumResults].nEnvProvidingEntityID = pEntity->GetId(); ++rNumResults; } } } } } } } } return true; } return false; }
void CBoidBird::Update( float dt,SBoidContext &bc ) { if (m_physicsControlled) { UpdatePhysics(dt,bc); return; } if (m_dead) return; if (m_heading.IsZero()) m_heading = Vec3(1,0,0); m_lastThinkTime += dt; { if (bc.followPlayer && !m_spawnFromPt) { if (m_pos.GetSquaredDistance(bc.playerPos) > MAX_BIRDS_DISTANCE*MAX_BIRDS_DISTANCE) { float z = bc.MinHeight + (Boid::Frand()+1)/2.0f*(bc.MaxHeight - bc.MinHeight); m_pos = bc.playerPos + Vec3(Boid::Frand()*MAX_BIRDS_DISTANCE,Boid::Frand()*MAX_BIRDS_DISTANCE,z ); m_speed = bc.MinSpeed + ((Boid::Frand()+1)/2.0f) / (bc.MaxSpeed - bc.MinSpeed); m_heading = Vec3(Boid::Frand(),Boid::Frand(),0).GetNormalized(); } } if(m_status == Bird::TAKEOFF) { float timePassed = (gEnv->pTimer->GetFrameStartTime() - m_takeOffStartTime).GetSeconds(); if(m_playingTakeOffAnim && timePassed >= m_TakeOffAnimLength) { m_playingTakeOffAnim = false; PlayAnimationId(Bird::ANIM_FLY,true); } else if( timePassed > TAKEOFF_TIME) { SetStatus(Bird::FLYING); } } if(m_status == Bird::LANDING) { Vec3 vDist(m_landingPoint - m_pos); float dist2 = vDist.GetLengthSquared2D(); float dist = sqrt_tpl(dist2 + vDist.z*vDist.z); if(dist > 0.02f && m_pos.z > m_landingPoint.z) { //if(vDist.z < 3 && m_heading) vDist /= dist; float fInterpSpeed = 2+fabs(m_heading.Dot(vDist))*3.f; Interpolate(m_heading,vDist, fInterpSpeed, dt); m_heading.NormalizeSafe(); if(m_heading.z < vDist.z) { Interpolate(m_heading.z,vDist.z,3.0f,dt); m_heading.NormalizeSafe(); } bool wasLandDeceleratingAlready = m_landDecelerating; m_accel.zero(); m_landDecelerating = dist < bc.landDecelerationHeight; if(m_landDecelerating) { float newspeed= m_startLandSpeed* dist/3.f; if(m_speed > newspeed) m_speed = newspeed; if(m_speed < 0.2f) m_speed = 0.2f; if(!wasLandDeceleratingAlready) PlayAnimationId(Bird::ANIM_LANDING_DECELERATING, true); } else m_startLandSpeed = m_speed; } else Landed(bc); CalcMovementBird( dt,bc,true ); UpdatePitch(dt,bc); return; } if (m_status != Bird::ON_GROUND) { Think(dt,bc); // Calc movement with current velocity. CalcMovementBird( dt,bc,true ); } else { if(bc.walkSpeed > 0 && m_onGroundStatus == Bird::OGS_WALKING) ThinkWalk(dt,bc); CalcMovementBird( dt,bc,true ); } m_accel.Set(0,0,0); UpdatePitch(dt,bc); // Check if landing/on ground after think(). if ( m_status == Bird::LANDING ||(m_dying && m_status != Bird::ON_GROUND)) { float LandEpsilon = 0.5f; // Check if landed on water. if (m_pos.z-bc.waterLevel < LandEpsilon+0.1f && !m_dying) { //! From water immidiatly take off. //! Gives fishing effect. TakeOff(bc); } } m_actionTime += dt; if (m_status == Bird::ON_GROUND ) UpdateOnGroundAction(dt, bc); else { if(!bc.noLanding && m_actionTime > m_maxActionTime && !static_cast<CBirdsFlock*>(m_flock)->IsPlayerNearOrigin()) Land(); } } }
bool CDialogActorContext::DoLocalPlayerChecks(const float dt) { // don't check this every frame, but only every .2 secs m_checkPlayerTimeOut-=dt; if (m_checkPlayerTimeOut <= 0.0f) { do // a dummy loop to use break { float awareDistance; float awareDistanceSq; float awareAngle; m_pSession->GetPlayerAwarenessValues(awareDistance, awareAngle); awareDistanceSq=awareDistance*awareDistance; m_checkPlayerTimeOut = PLAYER_CHECKTIME; const float spotAngleCos = cos_tpl(DEG2RAD(awareAngle)); const CDialogSession::TActorContextMap& contextMap = m_pSession->GetAllContexts(); if (contextMap.size() == 1 && contextMap.begin()->first == m_actorID) { m_bIsAware = true; break; } // early out, when we don't have to do any checks if (awareDistance <= 0.0f && awareAngle <= 0.0f) { m_bIsAware = true; break; } IEntity* pThisEntity = m_pSession->GetActorEntity(m_actorID); if (!pThisEntity) { assert (false); m_bIsAware = true; break; } IMovementController* pMC = (m_pIActor != NULL) ? m_pIActor->GetMovementController() : NULL; if (!pMC) { assert (false); m_bIsAware = true; break; } SMovementState moveState; pMC->GetMovementState(moveState); Vec3 viewPos = moveState.eyePosition; Vec3 viewDir = moveState.eyeDirection; viewDir.z = 0.0f; viewDir.NormalizeSafe(); // check the player's position // check the player's view direction AABB groupBounds; groupBounds.Reset(); CDialogSession::TActorContextMap::const_iterator iter = contextMap.begin(); CDialogScript::SActorSet lookingAt = 0; while (iter != contextMap.end()) { if (iter->first != m_actorID) { IEntity* pActorEntity = m_pSession->GetActorEntity(iter->first); if (pActorEntity) { Vec3 vEntityPos = pActorEntity->GetWorldPos(); AABB worldBounds; pActorEntity->GetWorldBounds(worldBounds); groupBounds.Add(worldBounds); // calc if we look at it somehow Vec3 vEntityDir = vEntityPos - viewPos; vEntityDir.z = 0.0f; vEntityDir.NormalizeSafe(); if (viewDir.IsUnit() && vEntityDir.IsUnit()) { const float dot = clamp_tpl(viewDir.Dot(vEntityDir),-1.0f,+1.0f); // clamping should not be needed if (spotAngleCos <= dot) lookingAt.SetActor(iter->first); DiaLOG::Log(DiaLOG::eDebugC, "Angle to actor %d is %f deg", iter->first, RAD2DEG(acos_tpl(dot))); } } } ++iter; } const float distanceSq = pThisEntity->GetWorldPos().GetSquaredDistance(groupBounds.GetCenter()); CCamera& camera=gEnv->pSystem->GetViewCamera(); const bool bIsInAABB = camera.IsAABBVisible_F(groupBounds); const bool bIsInRange = distanceSq <= awareDistanceSq; const bool bIsLooking = contextMap.empty() || lookingAt.NumActors() > 0; m_bIsAwareLooking = awareAngle <= 0.0f || (bIsInAABB || bIsLooking); m_bIsAwareInRange = awareDistance <= 0.0f || bIsInRange; m_bIsAware = m_bIsAwareLooking && m_bIsAwareInRange; DiaLOG::Log(DiaLOG::eDebugB, "[DIALOG] LPC: %s awDist=%f awAng=%f AABBVis=%d IsLooking=%d InRange=%d [Distance=%f LookingActors=%d] Final=%saware", m_pSession->GetDebugName(), awareDistance, awareAngle, bIsInAABB, bIsLooking, bIsInRange, sqrt_tpl(distanceSq), lookingAt.NumActors(), m_bIsAware ? "" : "not "); } while (false); } if (m_bIsAware) { m_playerAwareTimeOut = m_pSession->GetPlayerAwarenessGraceTime(); } else { m_playerAwareTimeOut-= dt; if (m_playerAwareTimeOut <= 0) { return false; } } return true; }
void CPlayerStateJump::StartJump( CPlayer& player, const bool isHeavyWeapon, const float fVerticalSpeedModifier ) { const SActorPhysics& actorPhysics = player.GetActorPhysics(); const SPlayerStats& stats = *player.GetActorStats(); const float onGroundTime = 0.2f; float g = actorPhysics.gravity.len(); const float jumpHeightScale = 1.0f; const float jumpHeight = player.GetActorParams().jumpHeight * jumpHeightScale; float playerZ = player.GetEntity()->GetWorldPos().z; float expectedJumpEndHeight = playerZ + jumpHeight; pe_player_dimensions dimensions; IPhysicalEntity *pPhysics = player.GetEntity()->GetPhysics(); if (pPhysics && pPhysics->GetParams(&dimensions)) { float physicsBottom = dimensions.heightCollider - dimensions.sizeCollider.z; if (dimensions.bUseCapsule) { physicsBottom -= dimensions.sizeCollider.x; } expectedJumpEndHeight += physicsBottom; } float jumpSpeed = 0.0f; if (g > 0.0f) { jumpSpeed = sqrt_tpl(2.0f*jumpHeight*(1.0f/g)) * g; if( isHeavyWeapon ) { jumpSpeed *= g_pGameCVars->pl_movement.nonCombat_heavy_weapon_speed_scale; } } //this is used to easily find steep ground float slopeDelta = (Vec3Constants<float>::fVec3_OneZ - actorPhysics.groundNormal).len(); SetJumpState(player, JState_Jump); Vec3 jumpVec(ZERO); bool bNormalJump = true; player.PlaySound(CPlayer::ESound_Jump); OnSpecialMove(player, IPlayerEventListener::eSM_Jump); CCCPOINT_IF( player.IsClient(), PlayerMovement_LocalPlayerNormalJump); CCCPOINT_IF(!player.IsClient(), PlayerMovement_NonLocalPlayerNormalJump); { // This was causing the vertical jumping speed to be much slower. float verticalMult = max(1.0f - m_jumpLock, 0.3f); const Quat baseQuat = player.GetBaseQuat(); jumpVec += baseQuat.GetColumn2() * jumpSpeed * verticalMult; jumpVec.z += fVerticalSpeedModifier; #ifdef STATE_DEBUG if (g_pGameCVars->pl_debugInterpolation > 1) { CryWatch("Jumping: vec from player BaseQuat only = (%f, %f, %f)", jumpVec.x, jumpVec.y, jumpVec.z); } #endif if (g_pGameCVars->pl_adjustJumpAngleWithFloorNormal && actorPhysics.groundNormal.len2() > 0.0f) { float vertical = clamp_tpl((actorPhysics.groundNormal.z - 0.25f) / 0.5f, 0.0f, 1.0f); Vec3 modifiedJumpDirection = LERP(actorPhysics.groundNormal, Vec3(0,0,1), vertical); jumpVec = modifiedJumpDirection * jumpVec.len(); } #ifdef STATE_DEBUG if (g_pGameCVars->pl_debugInterpolation > 1) { CryWatch("Jumping (%f, %f, %f)", jumpVec.x, jumpVec.y, jumpVec.z); } #endif } NETINPUT_TRACE(player.GetEntityId(), jumpVec); FinalizeVelocity( player, jumpVec ); if (!player.IsRemote()) { player.HasJumped(player.GetMoveRequest().velocity); } IPhysicalEntity* pPhysEnt = player.GetEntity()->GetPhysics(); if (pPhysEnt != NULL) { SAnimatedCharacterParams params = player.m_pAnimatedCharacter->GetParams(); pe_player_dynamics pd; pd.kAirControl = player.GetAirControl()* g_pGameCVars->pl_jump_control.air_control_scale; pd.kAirResistance = player.GetAirResistance() * g_pGameCVars->pl_jump_control.air_resistance_scale; params.inertia = player.GetInertia() * g_pGameCVars->pl_jump_control.air_inertia_scale; if(player.IsRemote() && (g_pGameCVars->pl_velocityInterpAirControlScale > 0)) { pd.kAirControl = g_pGameCVars->pl_velocityInterpAirControlScale; } pPhysEnt->SetParams(&pd); // Let Animated character handle the inertia player.SetAnimatedCharacterParams(params); } #if 0 if (debugJumping) { Vec3 entityPos = m_player.GetEntity()->GetWorldPos(); gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine(entityPos, ColorB(255,255,255,255), entityPos, ColorB(255,255,0,255), 2.0f); gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine(entityPos+Vec3(0,0,2), ColorB(255,255,255,255), entityPos+Vec3(0,0,2) + desiredVel, ColorB(0,255,0,255), 2.0f); gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine(entityPos, ColorB(255,255,255,255), entityPos + jumpVec, ColorB(0,255,255,255), 2.0f); gEnv->pRenderer->DrawLabel(entityPos - entityRight * 1.0f + Vec3(0,0,3.0f), 1.5f, "Velo[%2.3f = %2.3f, %2.3f, %2.3f]", m_request.velocity.len(), m_request.velocity.x, m_request.velocity.y, m_request.velocity.z); } #endif m_expectedJumpEndHeight = expectedJumpEndHeight; m_bSprintJump = player.IsSprinting(); }
//------------------------------------------------------------------------ bool CTracer::Update(float frameTime, const Vec3 &camera, const float fovScale) { frameTime = (float)__fsel(-m_age, 0.002f, frameTime); const float tracerAge = (float)__fsel(-m_age, 0.002f, m_age+frameTime); m_age = tracerAge; if (tracerAge >= m_lifeTime) return false; Vec3 currentLimitDestination; if (gEnv->bMultiplayer) { if(m_tracerFlags & kTracerFlag_updateDestFromBullet) { IEntity* pBulletEntity = gEnv->pEntitySystem->GetEntity(m_boundToBulletId); if(pBulletEntity) { m_dest = pBulletEntity->GetPos(); } } currentLimitDestination = m_dest; } else { IEntity* pBulletEntity = gEnv->pEntitySystem->GetEntity(m_boundToBulletId); currentLimitDestination = pBulletEntity ? pBulletEntity->GetPos() : m_dest; } const Vec3 maxTravelledDistance = m_dest - m_startingPos; const float maxTravelledDistanceSqr = maxTravelledDistance.len2(); float dist = sqrt_tpl(maxTravelledDistanceSqr); if (dist <= 0.001f) return false; const Vec3 dir = maxTravelledDistance * (float)__fres(dist); Vec3 pos = m_pos; float lengthScale = 1.f; Vec3 newPos = m_pos; if (!(m_tracerFlags & kTracerFlag_dontTranslate)) { const float sqrRadius = GetGameConstCVar(g_tracers_slowDownAtCameraDistance) * GetGameConstCVar(g_tracers_slowDownAtCameraDistance); const float cameraDistance = (m_pos-camera).len2(); const float speed = m_speed * (float)__fsel(sqrRadius - cameraDistance, 0.35f + (cameraDistance/(sqrRadius*2)), 1.0f); //Slow down tracer when near the player newPos += dir * min(speed*frameTime, dist); pos = newPos; if(m_slideFrac > 0.f) { pos += (((2.f * cry_frand()) - 0.5f) * m_slideFrac * speed * frameTime * dir); } } // Now update visuals... if (IEntity *pEntity = gEnv->pEntitySystem->GetEntity(m_entityId)) { AABB tracerBbox; pEntity->GetWorldBounds(tracerBbox); float tracerHalfLength = !tracerBbox.IsEmpty() ? tracerBbox.GetRadius() : 0.0f; const Vec3 frontOfTracerPos = pos + (dir * tracerHalfLength); if((frontOfTracerPos-m_startingPos).len2() > maxTravelledDistanceSqr) { return false; } if (!(m_tracerFlags & kTracerFlag_dontTranslate) && tracerHalfLength > 0.f) { //Ensure that never goes in front of the bullet const Vec3 dirFromFrontOfTracerToDestination = currentLimitDestination - frontOfTracerPos; if (dir.dot(dirFromFrontOfTracerToDestination) < 0) { pos += dirFromFrontOfTracerToDestination; } // ... and check if back of tracer is behind starting point, so adjust length. const Vec3 backOfTracerPos = pos - (dir * tracerHalfLength); const Vec3 dirFromBackOfTracerToStart = m_startingPos - backOfTracerPos; if (dir.dot(dirFromBackOfTracerToStart) > 0) { if(dir.dot((m_startingPos - pos)) > 0) { pos = m_startingPos + (dir * cry_frand() * tracerHalfLength); } lengthScale = ((pos - m_startingPos).GetLength() / tracerHalfLength); } } m_pos = newPos; Matrix34 tm(Matrix33::CreateRotationVDir(dir)); tm.AddTranslation(pos); pEntity->SetWorldTM(tm); //Do not scale effects if((m_tracerFlags & kTracerFlag_useGeometry)) { float finalFovScale = fovScale; if((m_tracerFlags & kTracerFlag_scaleToDistance) != 0) { lengthScale = dist * 0.5f; } else { const float cameraDistanceSqr = (m_pos-camera).len2(); const float minScale = GetGameConstCVar(g_tracers_minScale); const float maxScale = GetGameConstCVar(g_tracers_maxScale); const float minDistanceRange = GetGameConstCVar(g_tracers_minScaleAtDistance) * GetGameConstCVar(g_tracers_minScaleAtDistance); const float maxDistanceRange = max(GetGameConstCVar(g_tracers_maxScaleAtDistance) * GetGameConstCVar(g_tracers_maxScaleAtDistance), minDistanceRange + 1.0f); const float currentRefDistance = clamp(cameraDistanceSqr, minDistanceRange, maxDistanceRange); const float distanceToCameraFactor = ((currentRefDistance - minDistanceRange) / (maxDistanceRange - minDistanceRange)); const float distanceToCameraScale = LERP(minScale, maxScale, distanceToCameraFactor); lengthScale = m_scale * distanceToCameraScale; finalFovScale *= distanceToCameraScale; } const float widthScale = fovScale; tm.SetIdentity(); tm.SetScale(Vec3(m_scale * finalFovScale, lengthScale, m_scale * finalFovScale)); pEntity->SetSlotLocalTM(m_geometrySlot,tm); } } return true; }
// // Extract the various modifiers out into their own function. // // Aim is to make the code easier to understand and modify, as // well as to ease the addition of new modifiers. // void CPlayerView::ViewFirstPerson(SViewParams &viewParams) { //headbob Ang3 angOffset(0,0,0); Vec3 weaponOffset(0,0,0); Ang3 weaponAngleOffset(0,0,0); // jump/land spring effect. Adjust the eye and weapon pos as required. FirstPersonJump(viewParams,weaponOffset,weaponAngleOffset); //float standSpeed(GetStanceMaxSpeed(STANCE_STAND)); Vec3 vSpeed(0,0,0); if (m_in.standSpeed>0.001f) vSpeed = (m_in.stats_velocity / m_in.standSpeed); float vSpeedLen(vSpeed.len()); if (vSpeedLen>1.5f) vSpeed = vSpeed / vSpeedLen * 1.5f; float speedMul(0); if (m_in.standSpeed>0.001f) speedMul=(m_in.stats_flatSpeed / m_in.standSpeed * 1.1f); speedMul = min(1.5f,speedMul); bool crawling(m_in.stance==STANCE_PRONE /*&& m_in.stats_flatSpeed>0.1f*/ && m_in.stats_onGround>0.1f); bool weaponZoomed = false; bool weaponZomming = false; //Not crawling while in zoom mode IActor *owner = gEnv->pGame->GetIGameFramework()->GetIActorSystem()->GetActor(m_in.entityId); if(owner && owner->IsPlayer()) { IItem *pItem = owner->GetCurrentItem(); if(pItem) { CWeapon *pWeapon = static_cast<CWeapon*>(pItem->GetIWeapon()); if(pWeapon) { weaponZoomed = pWeapon->IsZoomed(); weaponZomming = pWeapon->IsZooming(); if(weaponZoomed||weaponZomming||pWeapon->IsModifying()) crawling = false; } } } // On the ground. if (m_in.stats_inAir < 0.1f /*&& m_in.stats_inWater < 0.1f*/) { //--- Bobbing. // bobCycle is a speed varying time step running (looping) from 0 to 1 // this feeds into a sin eqn creating a double horizontal figure of 8. // ( a lissajous figure with the vertical freq twice the horz freq ). // To tweak the total speed of the curve: // To tweak the effect speed has on the curve: float kSpeedToBobFactor=1.15f;//0.9f // To tweak the width of the bob: float kBobWidth=0.1f; // To tweak the height of the bob: float kBobHeight=0.05f; // To tweak the scale of strafing lag: (may need to manually adjust the strafing angle offsets as well.) const float kStrafeHorzScale=0.05f; kBobWidth = 0.15f; kBobHeight = 0.06f; m_io.stats_bobCycle += m_in.frameTime * kSpeedToBobFactor * speedMul;// * (m_in.bSprinting?1.25f:1.0f); //if player is standing set the bob to rest. (bobCycle reaches 1.0f within 1 second) if (speedMul < 0.1f) m_io.stats_bobCycle = min(m_io.stats_bobCycle + m_in.frameTime * 1.0f,1.0f); // bobCycle loops between 0 and 1 if (m_io.stats_bobCycle>1.0f) m_io.stats_bobCycle = m_io.stats_bobCycle - 1.0f; if (crawling) kBobWidth *= 2.0f * speedMul; else if (m_in.bSprinting) kBobWidth *= 1.25f * speedMul; //set the bob offset Vec3 bobDir(cry_sinf(m_io.stats_bobCycle*gf_PI*2.0f)*kBobWidth*speedMul,0,cry_sinf(m_io.stats_bobCycle*gf_PI*4.0f)*kBobHeight*speedMul); //not the bob offset for the weapon bobDir *= 0.25f; //if player is strafing shift a bit the weapon on left/right if (speedMul > 0.01f) { // right vector dot speed vector float dot(m_io.viewQuatFinal.GetColumn0() * vSpeed); bobDir.x -= dot * kStrafeHorzScale; // the faster we move right, the more the gun lags to the left and vice versa //tweak the right strafe for weapon laser if (dot>0.0f) weaponAngleOffset.z += dot * 1.5f; // kStrafeHorzScale else weaponAngleOffset.z -= dot * 2.0f; // kStrafeHorzScale weaponAngleOffset.y += dot * 5.0f; // kStrafeHorzScale } //CryLogAlways("bobDir.z: %f", bobDir.z); if (bobDir.z < 0.0f) { bobDir.x *= 1.0f; bobDir.y *= 1.0f; bobDir.z *= 0.35f; speedMul *= 0.65f; } else bobDir.z *= 1.85f; //CryLogAlways("bobDir.z: %f after", bobDir.z); weaponOffset += m_io.viewQuatFinal * bobDir; weaponOffset -= m_io.baseQuat.GetColumn2() * 0.035f * speedMul; weaponAngleOffset.y += cry_sinf(m_io.stats_bobCycle*gf_PI*2.0f) * speedMul * -1.5f; if (crawling) weaponAngleOffset.y *= 3.0f; weaponAngleOffset.x += speedMul * 1.5f; if (crawling) weaponAngleOffset.z += cry_sinf(m_io.stats_bobCycle*gf_PI*2.0f) * speedMul * 3.0f; //FIXME: viewAngles must include all the view offsets, otherwise aiming wont be precise. angOffset.x += cry_sinf(m_io.stats_bobCycle*gf_PI*4.0f)*0.7f*speedMul; if (crawling) { angOffset.x *= 2.5f; angOffset.y += cry_sinf(m_io.stats_bobCycle*gf_PI*2.0f)*1.25f*speedMul; angOffset.z -= cry_sinf(m_io.stats_bobCycle*gf_PI*2.0f)*2.5f*speedMul; } else if (m_in.bSprinting) { angOffset.x *= 2.5f; angOffset.y += cry_sinf(m_io.stats_bobCycle*gf_PI*2.0f)*1.0f*speedMul; angOffset.z -= cry_sinf(m_io.stats_bobCycle*gf_PI*2.0f)*2.25f*speedMul; } else if(m_in.stance==STANCE_CROUCH && !weaponZoomed && !weaponZomming) { weaponOffset.z += 0.035f; weaponOffset.y -= m_io.viewQuatFinal.GetColumn1().y * 0.03f; } else if(m_in.stance==STANCE_CROUCH && weaponZomming) { weaponOffset.z -= 0.07f; weaponOffset.y += m_io.viewQuatFinal.GetColumn1().y * 0.06f; } else { //angOffset.x *= 2.25f; //angOffset.y += cry_sinf(m_io.stats_bobCycle*gf_PI*2.0f)*0.5f*speedMul; //angOffset.z -= cry_sinf(m_io.stats_bobCycle*gf_PI*2.0f)*1.125f*speedMul; } } else { m_io.stats_bobCycle = 0; //while flying offset a bit the weapon model by the player speed if (m_in.stats_velocity.len2()>0.001f) { float dotFwd(m_io.viewQuatFinal.GetColumn1() * vSpeed); float dotSide(m_io.viewQuatFinal.GetColumn0() * vSpeed); float dotUp(m_io.viewQuatFinal.GetColumn2() * vSpeed); weaponOffset += m_io.viewQuatFinal * Vec3(dotSide * -0.05f,dotFwd * -0.035f,dotUp * -0.05f); weaponAngleOffset.x += dotUp * 2.0f; weaponAngleOffset.y += dotSide * 5.0f; weaponAngleOffset.z -= dotSide * 2.0f; } } //add some inertia to weapon due view direction change. float deltaDotSide(m_io.vFPWeaponLastDirVec * m_io.viewQuatFinal.GetColumn0()); float deltaDotUp(m_io.vFPWeaponLastDirVec * m_io.viewQuatFinal.GetColumn2()); weaponOffset += m_io.viewQuatFinal * Vec3(deltaDotSide * 0.1f + m_in.stats_leanAmount * 0.05f,0,deltaDotUp * 0.1f - fabs(m_in.stats_leanAmount) * 0.05f) * m_in.params_weaponInertiaMultiplier; weaponAngleOffset.x -= deltaDotUp * 5.0f * m_in.params_weaponInertiaMultiplier; weaponAngleOffset.z += deltaDotSide * 5.0f * m_in.params_weaponInertiaMultiplier; weaponAngleOffset.y += deltaDotSide * 5.0f * m_in.params_weaponInertiaMultiplier; if(m_in.stats_leanAmount<0.0f) weaponAngleOffset.y += m_in.stats_leanAmount * 5.0f; //the weapon model tries to stay parallel to the terrain when the player is freefalling/parachuting if (m_in.stats_inWater > 0.0f) weaponOffset -= m_io.viewQuat.GetColumn2() * 0.15f; if (m_in.stats_inWater>0.1f && !m_in.stats_headUnderWater) { Ang3 offset(m_io.viewQuatFinal); offset.z = 0; if (offset.x<0.0f) offset.x = 0; weaponAngleOffset -= offset*(180.0f/gf_PI)*0.75f; } else if (m_io.stats_inFreefall) { Ang3 offset(m_io.viewQuatFinal); offset.z = 0; weaponAngleOffset -= offset*(180.0f/gf_PI)*0.5f; } //same thing with crawling else if (crawling) { //FIXME:to optimize, looks like a bit too expensive Vec3 forward(m_io.viewQuatFinal.GetColumn1()); Vec3 up(m_io.baseQuat.GetColumn2()); Vec3 right(-(up % forward)); Matrix33 mat; mat.SetFromVectors(right,up%right,up); mat.OrthonormalizeFast(); Ang3 offset(m_io.viewQuatFinal.GetInverted() * Quat(mat)); weaponAngleOffset += offset*(180.0f/gf_PI)*0.5f; float lookDown(m_io.viewQuatFinal.GetColumn1() * m_io.baseQuat.GetColumn2()); weaponOffset += m_io.baseQuat * Vec3(0,-0.5f*max(-lookDown,0.0f),-0.05f); float scale = 0.5f;; if(weaponAngleOffset.x>0.0f) { scale = min(0.5f,weaponAngleOffset.x/15.0f); weaponAngleOffset.x *= scale; } else { scale = min(0.5f,-weaponAngleOffset.x/20.0f); weaponAngleOffset *= (1.0f-scale); weaponOffset *= scale; } //if(vSpeedLen>0.1f) //weaponAngleOffset += Ang3(-8.0f,0,-12.5f); } else if (m_in.bSprinting && vSpeedLen>0.5f) { weaponAngleOffset += Ang3(-20.0f,0,10.0f); weaponOffset += m_io.viewQuatFinal * Vec3(0.0f, -.01f, .1f); } else if (m_in.bLookingAtFriendlyAI && !weaponZomming && !weaponZoomed) { weaponAngleOffset += Ang3(-15.0f,0,8.0f); weaponOffset += m_io.viewQuatFinal * Vec3(0.0f, -.01f, .05f); } //apply some multipliers weaponOffset *= m_in.params_weaponBobbingMultiplier; angOffset *= m_io.bobMul * 0.25f; if (m_io.bobMul*m_io.bobMul!=1.0f) { weaponOffset *= m_io.bobMul; weaponAngleOffset *= m_io.bobMul; } float bobSpeedMult(1.0f); if(m_in.stats_inWater>0.1) bobSpeedMult = 0.75f; // m_io.viewQuatForWeapon *= Quat::CreateRotationXYZ(Ang3(rx,ry,rz)); Interpolate(m_io.vFPWeaponOffset,weaponOffset,3.95f*bobSpeedMult,m_in.frameTime); Interpolate(m_io.vFPWeaponAngleOffset,weaponAngleOffset,10.0f*bobSpeedMult,m_in.frameTime); Interpolate(m_io.vFPWeaponLastDirVec,m_io.viewQuatFinal.GetColumn1(),5.0f*bobSpeedMult,m_in.frameTime); Interpolate(m_io.angleOffset,angOffset,10.0f,m_in.frameTime,0.002f); if(weaponZomming) { m_io.vFPWeaponLastDirVec = m_io.viewQuatFinal.GetColumn1(); m_io.vFPWeaponOffset.Set(0.0f,0.0f,0.0f); m_io.vFPWeaponAngleOffset.Set(0.0f,0.0f,0.0f); m_io.bobOffset.Set(0.0f,0.0f,0.0f); } if (m_in.bSprinting) { float headBobScale = (m_in.stats_flatSpeed / m_in.standSpeed); headBobScale = min(1.0f, headBobScale); m_io.bobOffset = m_io.vFPWeaponOffset * 2.5f * g_pGameCVars->cl_headBob * headBobScale; float bobLenSq = m_io.bobOffset.GetLengthSquared(); float bobLenLimit = g_pGameCVars->cl_headBobLimit; if (bobLenSq > bobLenLimit*bobLenLimit) { float bobLen = sqrt_tpl(bobLenSq); m_io.bobOffset *= bobLenLimit/bobLen; } viewParams.position += m_io.bobOffset; } }