void CVehicleMovementAmphibiousT<Wheeled>::UpdateRunSound(const float deltaTime) { Wheeled::UpdateRunSound(deltaTime); if (Wheeled::m_pVehicle->IsProbablyDistant()) return; SetSoundParam(eSID_Run, "swim", this->m_statusDyn.submergedFraction); if (this->Boosting()) SetSoundParam(eSID_Boost, "swim", this->m_statusDyn.submergedFraction); }
//------------------------------------------------------------------------ void CVehicleMovementHelicopter::Update(const float deltaTime) { FUNCTION_PROFILER( GetISystem(), PROFILE_GAME ); CVehicleMovementBase::Update(deltaTime); UpdateDamages(deltaTime); UpdateEngine(deltaTime); { CryAutoCriticalSection lk(m_lock); m_netActionSync.Read(this); if (gEnv->bServer) { m_sendTimer -= deltaTime; if (m_sendTimer<=0.f) { m_netActionSync.Write(this); CHANGED_NETWORK_STATE(m_pVehicle, m_updateAspects); m_sendTimer = m_sendTime; } } } SetSoundParam(eSID_Run, "rpm_scale", m_rpmScale); // update animation if(m_isEngineGoingOff) { if(m_enginePower > 0.0f) { UpdateEngine(deltaTime); } else { m_enginePower = 0.0f; } } SetAnimationSpeed(eVMA_Engine, (m_enginePower / m_enginePowerMax)); }
//------------------------------------------------------------------------ void CVehicleMovementVTOL::Update(const float deltaTime) { FUNCTION_PROFILER( GetISystem(), PROFILE_GAME ); CVehicleMovementHelicopter::Update(deltaTime); CryAutoCriticalSection lk(m_lock); if (m_pWingsAnimation) { m_pWingsAnimation->SetTime(m_wingsAnimTime); } IActorSystem* pActorSystem = g_pGame->GetIGameFramework()->GetIActorSystem(); assert(pActorSystem); IActor* pActor = pActorSystem->GetActor(m_actorId); if (pActor && pActor->IsClient()) { float turbulence = m_turbulence; if (m_pAltitudeLimitVar) { float altitudeLimit = m_pAltitudeLimitVar->GetFVal(); float currentHeight = m_pEntity->GetWorldPos().z; if (!iszero(altitudeLimit)) { float altitudeLowerOffset; if (m_pAltitudeLimitLowerOffsetVar) { float r = 1.0f - min(1.0f, max(0.0f, m_pAltitudeLimitLowerOffsetVar->GetFVal())); altitudeLowerOffset = r * altitudeLimit; if (currentHeight >= altitudeLowerOffset) { if (currentHeight > altitudeLowerOffset) { float zone = altitudeLimit - altitudeLowerOffset; turbulence += (currentHeight - altitudeLowerOffset) / (zone); } } } } } if (turbulence > 0.0f) { static_cast<CActor*>(pActor)->CameraShake(0.50f * turbulence, 0.0f, 0.05f, 0.04f, Vec3(0.0f, 0.0f, 0.0f), 10, "VTOL_Update_Turbulence"); } float enginePowerRatio = m_enginePower / m_enginePowerMax; if (enginePowerRatio > 0.0f) { float rpmScaleDesired = 0.2f; rpmScaleDesired += abs(m_forwardAction) * 0.8f; rpmScaleDesired += abs(m_strafeAction) * 0.4f; rpmScaleDesired += abs(m_turnAction) * 0.25f; rpmScaleDesired = min(1.0f, rpmScaleDesired); Interpolate(m_rpmScale, rpmScaleDesired, 1.0f, deltaTime); } float turnParamGoal = min(1.0f, abs(m_turnAction)) * 0.6f; turnParamGoal *= (min(1.0f, max(0.0f, m_speedRatio)) + 1.0f) * 0.50f; turnParamGoal += turnParamGoal * m_boost * 0.25f; Interpolate(m_soundParamTurn, turnParamGoal, 0.5f, deltaTime); SetSoundParam(eSID_Run, "turn", m_soundParamTurn); float damage = GetSoundDamage(); if (damage > 0.1f) { //if (ISound* pSound = GetOrPlaySound(eSID_Damage, 5.f, m_enginePos)) //SetSoundParam(pSound, "damage", damage); } } }
//------------------------------------------------------------------------ void CVehicleMovementStdBoat::UpdateSurfaceEffects(const float deltaTime) { FUNCTION_PROFILER( GetISystem(), PROFILE_GAME ); if (0 == g_pGameCVars->v_pa_surface) { ResetParticles(); return; } IEntity* pEntity = m_pVehicle->GetEntity(); const Matrix34& worldTM = pEntity->GetWorldTM(); float distSq = worldTM.GetTranslation().GetSquaredDistance(gEnv->pRenderer->GetCamera().GetPosition()); if (distSq > sqr(300.f) || (distSq > sqr(50.f) && !m_pVehicle->GetGameObject()->IsProbablyVisible())) return; Matrix34 worldTMInv = worldTM.GetInverted(); const SVehicleStatus& status = m_pVehicle->GetStatus(); float velDot = status.vel * worldTM.GetColumn1(); float powerNorm = min(abs(m_movementAction.power), 1.f); SEnvironmentParticles* envParams = m_pPaParams->GetEnvironmentParticles(); SEnvParticleStatus::TEnvEmitters::iterator end = m_paStats.envStats.emitters.end(); for (SEnvParticleStatus::TEnvEmitters::iterator emitterIt = m_paStats.envStats.emitters.begin(); emitterIt!=end; ++emitterIt) { if (emitterIt->layer < 0) { assert(0); continue; } const SEnvironmentLayer& layer = envParams->GetLayer(emitterIt->layer); SEntitySlotInfo info; info.pParticleEmitter = 0; pEntity->GetSlotInfo(emitterIt->slot, info); float countScale = 1.f; float sizeScale = 1.f; float speedScale = 1.f; float speed = 0.f; // check if helper position is beneath water level Vec3 emitterWorldPos = worldTM * emitterIt->quatT.t; float waterLevel = gEnv->p3DEngine->GetWaterLevel(&emitterWorldPos); int matId = 0; if (emitterWorldPos.z <= waterLevel+0.1f && m_physStatus[k_mainThread].submergedFraction<0.999f) { matId = gEnv->pPhysicalWorld->GetWaterMat(); speed = status.speed; bool spray = !strcmp(layer.GetName(), "spray"); if (spray) { // slip based speed -= abs(velDot); } GetParticleScale(layer, speed, powerNorm, countScale, sizeScale, speedScale); } else { countScale = 0.f; } if (matId && matId != emitterIt->matId) { // change effect IParticleEffect* pEff = 0; const char* effect = GetEffectByIndex( matId, layer.GetName() ); if (effect && (pEff = gEnv->pParticleManager->FindEffect(effect))) { #if ENABLE_VEHICLE_DEBUG if (DebugParticles()) CryLog("%s changes water sfx to %s (slot %i)", pEntity->GetName(), effect, emitterIt->slot); #endif if (info.pParticleEmitter) { info.pParticleEmitter->Activate(false); pEntity->FreeSlot(emitterIt->slot); } emitterIt->slot = pEntity->LoadParticleEmitter(emitterIt->slot, pEff); if (emitterIt->slot != -1) pEntity->SetSlotLocalTM(emitterIt->slot, Matrix34(emitterIt->quatT)); info.pParticleEmitter = 0; pEntity->GetSlotInfo(emitterIt->slot, info); } else countScale = 0.f; } if (matId) emitterIt->matId = matId; if (info.pParticleEmitter) { SpawnParams sp; sp.fSizeScale = sizeScale; sp.fCountScale = countScale; sp.fSpeedScale = speedScale; info.pParticleEmitter->SetSpawnParams(sp); if (layer.alignToWater && countScale > 0.f) { Vec3 worldPos(emitterWorldPos.x, emitterWorldPos.y, waterLevel+0.05f); Matrix34 localTM(emitterIt->quatT); localTM.SetTranslation(worldTMInv * worldPos); pEntity->SetSlotLocalTM(emitterIt->slot, localTM); } } #if ENABLE_VEHICLE_DEBUG if (DebugParticles() && m_pVehicle->IsPlayerDriving()) { float color[] = {1,1,1,1}; ColorB red(255,0,0,255); IRenderAuxGeom* pAuxGeom = gEnv->pRenderer->GetIRenderAuxGeom(); const char* effect = info.pParticleEmitter ? info.pParticleEmitter->GetName() : ""; const Matrix34& slotTM = m_pEntity->GetSlotWorldTM(emitterIt->slot); Vec3 ppos = slotTM.GetTranslation(); pAuxGeom->DrawSphere(ppos, 0.2f, red); pAuxGeom->DrawCone(ppos, slotTM.GetColumn1(), 0.1f, 0.5f, red); gEnv->pRenderer->Draw2dLabel(50.f, (float)(400+10*emitterIt->slot), 1.2f, color, false, "<%s> water fx: slot %i [%s], speed %.1f, sizeScale %.2f, countScale %.2f (pos %.0f,%0.f,%0.f)", pEntity->GetName(), emitterIt->slot, effect, speed, sizeScale, countScale, ppos.x, ppos.y, ppos.z); } #endif } // generate water splashes Vec3 wakePos; if(m_pSplashPos) { wakePos = m_pSplashPos->GetWorldSpaceTranslation(); } else { wakePos = worldTM.GetTranslation(); } float wakeWaterLevel = gEnv->p3DEngine->GetWaterLevel(&wakePos); const Vec3& localW = m_localSpeed; if (localW.x >= 0.f) m_diving = false; if (!m_diving && localW.x < -0.03f && status.speed > 10.f && wakePos.z < m_lastWakePos.z && wakeWaterLevel+0.1f >= wakePos.z) { float speedRatio = min(1.f, status.speed/(m_maxSpeed*m_factorMaxSpeed)); m_diving = true; if (m_pWaveEffect) { if (IParticleEmitter* pEmitter = pEntity->GetParticleEmitter(m_wakeSlot)) { pEmitter->Activate(false); pEntity->FreeSlot(m_wakeSlot); m_wakeSlot = -1; } SpawnParams spawnParams; spawnParams.fSizeScale = spawnParams.fCountScale = 0.5f + 0.25f*speedRatio; spawnParams.fSizeScale += 0.4f*m_waveRandomMult; spawnParams.fCountScale += cry_random(0.0f, 0.4f); m_wakeSlot = pEntity->LoadParticleEmitter(m_wakeSlot, m_pWaveEffect, &spawnParams); } // handle splash sound ExecuteTrigger(eSID_Splash); SetSoundParam(eSID_Splash, "intensity", 0.2f*speedRatio + 0.5f*m_waveRandomMult); if (m_rpmPitchDir == 0) { m_rpmPitchDir = -1; m_waveSoundPitch = 0.f; m_waveSoundAmount = 0.02f + m_waveRandomMult*0.08f; } } if (m_wakeSlot != -1) { // update emitter local pos to short above waterlevel Matrix34 tm; if(m_pSplashPos) m_pSplashPos->GetVehicleTM(tm); else tm.SetIdentity(); Vec3 pos = tm.GetTranslation(); pos.z = worldTMInv.TransformPoint(Vec3(wakePos.x,wakePos.y,wakeWaterLevel)).z + 0.2f; tm.SetTranslation(pos); pEntity->SetSlotLocalTM(m_wakeSlot, tm); #if ENABLE_VEHICLE_DEBUG if (IsProfilingMovement()) { Vec3 wPos = worldTM * tm.GetTranslation(); ColorB col(128, 128, 0, 200); gEnv->pRenderer->GetIRenderAuxGeom()->DrawSphere(wPos, 0.4f, col); gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine(wPos, col, wPos+Vec3(0,0,1.5f), col); } #endif } m_lastWakePos = wakePos; }
//------------------------------------------------------------------------ void CVehicleMovementStdBoat::Update(const float deltaTime) { CVehicleMovementBase::Update(deltaTime); SetAnimationSpeed(eVMA_Engine, abs(m_rpmScaleSgn)); if (m_inWater) { SetSoundParam(eSID_Run, "slip", 0.2f*abs(m_localSpeed.x)); } #if ENABLE_VEHICLE_DEBUG if (IsProfilingMovement() && g_pGameCVars->v_profileMovement != 2) { IEntity* pEntity = m_pVehicle->GetEntity(); const Matrix34& wTM = pEntity->GetWorldTM(); Matrix34 wTMInv = wTM.GetInvertedFast(); const SVehiclePhysicsStatus* physStatus = &m_physStatus[k_mainThread]; Vec3 localW = physStatus->q * physStatus->w; float speed = physStatus->v.len2() > 0.001f ? physStatus->v.len() : 0.f; float speedRatio = min(1.f, speed/(m_maxSpeed*m_factorMaxSpeed)); float absPedal = abs(m_movementAction.power); float absSteer = abs(m_movementAction.rotateYaw); static const float fSubmergedMin = 0.01f; static const float fWaterLevelMaxDiff = 0.15f; // max allowed height difference between propeller center and water level Vec3 worldPropPos = wTM * m_pushOffset; float waterLevelWorld = gEnv->p3DEngine->GetWaterLevel( &worldPropPos ); float fWaterLevelDiff = worldPropPos.z - waterLevelWorld; // wave stuff float waveFreq = 1.f; waveFreq += 3.f*speedRatio; float kx = m_waveIdleStrength.x*(m_waveRandomMult+0.3f) * (1.f-speedRatio + m_waveSpeedMult*speedRatio); float ky = m_waveIdleStrength.y * (1.f - 0.5f*absPedal - 0.5f*absSteer); Vec3 waveLoc = m_massOffset; waveLoc.y += speedRatio*min(0.f, m_pushOffset.y-m_massOffset.y); waveLoc = wTM * waveLoc; IRenderer* pRenderer = gEnv->pRenderer; static float color[4] = {1,1,1,1}; float colorRed[4] = {1,0,0,1}; float colorGreen[4] = {0,1,0,1}; float y=50.f, step1=15.f, step2=20.f, size1=1.3f, size2=1.5f; pRenderer->Draw2dLabel(5.0f, y, size2, color, false, "Boat movement"); pRenderer->Draw2dLabel(5.0f, y+=step2, size1, color, false, "Speed: %.1f (%.1f km/h)", speed, speed*3.6f); pRenderer->Draw2dLabel(5.0f, y+=step1, size1, color, false, "LocalW.z norm: %.2f", abs(localW.z)/m_turnRateMax); if (m_velLift > 0.f) { pRenderer->Draw2dLabel(5.0f, y+=step2, size1, m_lifted ? colorGreen : color, false, m_lifted ? "Lifted" : "not lifted"); //pRenderer->Draw2dLabel(5.0f, y+=step2, size1, color, false, "Impulse lift: %.0f", liftImp.impulse.len()); } pRenderer->Draw2dLabel(5.0f, y+=step1, size1, physStatus->submergedFraction > fSubmergedMin ? color : colorRed, false, "Submerged: %.2f", physStatus->submergedFraction); pRenderer->Draw2dLabel(5.0f, y+=step1, size1, fWaterLevelDiff < fWaterLevelMaxDiff ? color : colorRed, false, "WaterLevel: %.2f (max: %.2f)", fWaterLevelDiff, fWaterLevelMaxDiff); pRenderer->Draw2dLabel(5.0f, y+=step2, size2, color, false, "Driver input"); pRenderer->Draw2dLabel(5.0f, y+=step2, size1, color, false, "power: %.2f", m_movementAction.power); pRenderer->Draw2dLabel(5.0f, y+=step1, size1, color, false, "steer: %.2f", m_movementAction.rotateYaw); pRenderer->Draw2dLabel(5.0f, y+=step2, size2, color, false, "Propelling"); //pRenderer->Draw2dLabel(5.0f, y+=step2, size1, color, false, "turnAccel (norm/real): %.2f / %.2f", turnAccelNorm, turnAccel); //pRenderer->Draw2dLabel(5.0f, y+=step1, size1, color, false, "Impulse acc: %.0f", linearImp.impulse.len()); //pRenderer->Draw2dLabel(5.0f, y+=step1, size1, color, false, "Impulse steer/damp: %.0f", angularImp.angImpulse.len()); //pRenderer->Draw2dLabel(5.0f, y+=step1, size1, color, false, "Impulse corner: %.0f", dampImp.impulse.len()); pRenderer->Draw2dLabel(5.0f, y+=step2, size2, color, false, "Waves"); pRenderer->Draw2dLabel(5.0f, y+=step2, size1, color, false, "timer: %.1f", m_waveTimer); pRenderer->Draw2dLabel(5.0f, y+=step1, size1, color, false, "frequency: %.2f", waveFreq); pRenderer->Draw2dLabel(5.0f, y+=step1, size1, color, false, "random: %.2f", m_waveRandomMult); pRenderer->Draw2dLabel(5.0f, y+=step1, size1, color, false, "kX: %.2f", kx); pRenderer->Draw2dLabel(5.0f, y+=step1, size1, color, false, "kY: %.2f", ky); if (Boosting()) pRenderer->Draw2dLabel(5.0f, y+=step1, size1, color, false, "Boost: %.2f", m_boostCounter); IRenderAuxGeom* pGeom = pRenderer->GetIRenderAuxGeom(); ColorB colorB(0,255,0,255); pRenderer->DrawLabel(worldPropPos, 1.3f, "WL: %.2f", waterLevelWorld); pGeom->DrawSphere(worldPropPos, 0.15f, colorB); pGeom->DrawSphere(waveLoc, 0.25f, colorB); pGeom->DrawLine(waveLoc, colorB, waveLoc+Vec3(0,0,2), colorB); // impulses //DrawImpulse(linearImp, Vec3(0,0,1), 3.f/deltaTime, ColorB(255,0,0,255)); //DrawImpulse(angularImp, Vec3(0,0,1), 2.f/deltaTime, ColorB(128,0,0,255)); //DrawImpulse(liftImp, Vec3(0,0,6), 2.f/deltaTime, ColorB(0,0,255,255)); } #endif }
//------------------------------------------------------------------------ void CVehicleMovementStdBoat::UpdateRunSound(const float deltaTime) { Vec3 localAccel(ZERO); m_measureSpeedTimer+=deltaTime; if(m_measureSpeedTimer > 0.25f) { Vec3 accel = (m_statusDyn.v - m_lastMeasuredVel) * (1.f/m_measureSpeedTimer); Matrix33 worldTM(!m_statusPos.q); localAccel = worldTM * accel; m_lastMeasuredVel = m_statusDyn.v; m_measureSpeedTimer = 0.f; } if(m_pVehicle->IsProbablyDistant()) return; float soundSpeedRatio = ms_engineSoundIdleRatio + (1.f-ms_engineSoundIdleRatio) * m_speedRatio; SetSoundParam(eSID_Run, "speed", soundSpeedRatio); SetSoundParam(eSID_Ambience, "speed", soundSpeedRatio); //SetSoundParam(eSID_Run, "boost", Boosting() ? 1.f : 0.f); float acceleration = min(1.f, abs(localAccel.y) / m_accel*max(1.f, m_accelCoeff)); if(acceleration > 0.5f) { if(ISound *pSound = GetOrPlaySound(eSID_Acceleration, 2.f)) SetSoundParam(pSound, "acceleration", acceleration); } float damage = GetSoundDamage(); if(damage > 0.1f) { if(ISound *pSound = GetOrPlaySound(eSID_Damage, 5.f, m_enginePos)) SetSoundParam(pSound, "damage", damage); } // rpm dropdown for waves if(m_rpmPitchDir != 0) { float speed = (m_rpmPitchDir > 0) ? 0.1f : -0.8f; // quick down, slow up m_waveSoundPitch += deltaTime * speed; if(m_waveSoundPitch < -m_waveSoundAmount) // dropdown amount { m_waveSoundPitch = -m_waveSoundAmount; m_rpmPitchDir = 1; } else if(m_waveSoundPitch > 0.f) { m_waveSoundPitch = 0.f; m_rpmPitchDir = 0; } } if(m_rpmPitchSpeed>0.f) { const float maxPedal = (!m_inWater) ? 1.f : Boosting() ? 0.8f : 0.7f; // pitch rpm with pedal float pedal = GetEnginePedal(); pedal = sgnnz(pedal)*max(ms_engineSoundIdleRatio, min(maxPedal, abs(pedal))); // clamp "pedal" to [0.2..0.7] range float delta = pedal - m_rpmScaleSgn; m_rpmScaleSgn = max(-1.f, min(1.f, m_rpmScaleSgn + sgn(delta)*min(abs(delta), m_rpmPitchSpeed*deltaTime))); // skip transition around 0 when on pedal (sounds more realistic) if(abs(GetEnginePedal()) > 0.001f && abs(delta) > 0.001f && sgn(m_rpmScaleSgn) != sgn(delta) && abs(m_rpmScaleSgn) <= 0.3f) m_rpmScaleSgn = sgn(delta)*0.3f; // for normal driving, rpm is clamped at max defined by sound dept m_rpmScale = abs(m_rpmScaleSgn); m_rpmScale = min(1.f, max(ms_engineSoundIdleRatio, m_rpmScale + m_waveSoundPitch)); SetSoundParam(eSID_Run, "rpm_scale", m_rpmScale); SetSoundParam(eSID_Ambience, "rpm_scale", m_rpmScale); } }