//----------------------------------------------------------------------------- // Purpose: Calculates the physics shake values //----------------------------------------------------------------------------- void CASWEnvShake::Think( void ) { int i; if ( gpGlobals->curtime > m_nextShake ) { // Higher frequency means we recalc the extents more often and perturb the display again m_nextShake = gpGlobals->curtime + (1.0f / Frequency()); // Compute random shake extents (the shake will settle down from this) for (i = 0; i < 2; i++ ) { m_maxForce[i] = random->RandomFloat( -1, 1 ); } // make the force it point mostly up m_maxForce.z = 4; VectorNormalize( m_maxForce ); m_maxForce *= m_currentAmp * 400; // amplitude is the acceleration of a 100kg object } float fraction = ( m_stopTime - gpGlobals->curtime ) / Duration(); if ( fraction < 0 ) { m_pShakeController->ClearObjects(); return; } float freq = 0; // Ramp up frequency over duration if ( fraction ) { freq = (Frequency() / fraction); } // square fraction to approach zero more quickly fraction *= fraction; // Sine wave that slowly settles to zero fraction = fraction * sin( gpGlobals->curtime * freq ); // Add to view origin for ( i = 0; i < 3; i++ ) { // store the force in the controller callback m_shakeCallback.m_force[i] = m_maxForce[i] * fraction; } // Drop amplitude a bit, less for higher frequency shakes m_currentAmp -= m_currentAmp * ( gpGlobals->frametime / (Duration() * Frequency()) ); SetNextThink( gpGlobals->curtime ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CASWEnvShake::ApplyShake( ShakeCommand_t command ) { if ( !HasSpawnFlags( SF_ASW_SHAKE_NO_VIEW ) ) { bool air = (GetSpawnFlags() & SF_ASW_SHAKE_INAIR) ? true : false; UTIL_ASW_ScreenShake( GetAbsOrigin(), Amplitude(), Frequency(), Duration(), Radius(), command, air ); } if ( GetSpawnFlags() & SF_ASW_SHAKE_ROPES ) { CRopeKeyframe::ShakeRopes( GetAbsOrigin(), Radius(), Frequency() ); } if ( GetSpawnFlags() & SF_ASW_SHAKE_PHYSICS ) { if ( !m_pShakeController ) { m_pShakeController = physenv->CreateMotionController( &m_shakeCallback ); } // do physics shake switch( command ) { case SHAKE_START: { m_stopTime = gpGlobals->curtime + Duration(); m_nextShake = 0; m_pShakeController->ClearObjects(); SetNextThink( gpGlobals->curtime ); m_currentAmp = Amplitude(); CBaseEntity *list[1024]; float radius = Radius(); // probably checked "Shake Everywhere" do a big radius if ( !radius ) { radius = MAX_COORD_INTEGER; } Vector extents = Vector(radius, radius, radius); Vector mins = GetAbsOrigin() - extents; Vector maxs = GetAbsOrigin() + extents; int count = UTIL_EntitiesInBox( list, 1024, mins, maxs, 0 ); for ( int i = 0; i < count; i++ ) { // // Only shake physics entities that players can see. This is one frame out of date // so it's possible that we could miss objects if a player changed PVS this frame. // if ( ( list[i]->GetMoveType() == MOVETYPE_VPHYSICS ) ) { IPhysicsObject *pPhys = list[i]->VPhysicsGetObject(); if ( pPhys && pPhys->IsMoveable() ) { m_pShakeController->AttachObject( pPhys, false ); pPhys->Wake(); } } } } break; case SHAKE_STOP: m_pShakeController->ClearObjects(); break; case SHAKE_AMPLITUDE: m_currentAmp = Amplitude(); case SHAKE_FREQUENCY: m_pShakeController->WakeObjects(); break; } } }