//----------------------------------------------------------------------------- // File: Flock.cpp // // Desc: // // Copyright (c) 1995-2001 Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- #include #include #include "DXUtil.h" #include "boids.h" #include "music.h" const float g_fInfluenceRadius = 10.0f; // outside of this range forces are considered to be 0 const float CollisionFraction = 0.8f; const float InvCollisionFraction = 1.0f/(1.0f-CollisionFraction); const float g_fNormalSpeed = 0.1f; const float AngleTweak = 0.02f; const float g_fPitchToSpeedRatio = 0.002f; // More arbitray constants that look cool const float fSeparationScale = 0.05f; const float fAlignmentScale = 0.1f; const float fCohesionScale = 1.0f; const float fMigratoryScale = 0.4f; const float fObstacleScale = 1.0f; //----------------------------------------------------------------------------- // Effects //----------------------------------------------------------------------------- extern BoidMusic g_Music; extern BOOL g_bSeparation; extern BOOL g_bAlignment; extern BOOL g_bCohesion; extern BOOL g_bMigratory; extern BOOL g_bObstacle; //----------------------------------------------------------------------------- // Name: // Desc: //----------------------------------------------------------------------------- VOID CFlock::Update( FLOAT fElapsedTime ) { DWORD i, j; static DWORD lastobj = 0xffffffff; // First, update the dist array 0.0..1.0 with 0.0 being furthest away for( i=0; i 0.0f ) continue; FLOAT fDist = D3DXVec3Length( &vDiff ) - fObRadius; if( fDist < g_fInfluenceRadius ) { if( ( lastobj != j ) && ( fDist < 5.0f ) ) { lastobj = j; g_Music.Transition(); } vDiff /= fDist; // normalize fDist -= fObRadius; if( fDist < 0.01f ) fDist = 0.01f; m_Boids[i].vObstacleForce += vDiff; } } // Find cohesion force if( m_Boids[i].dwNumNeighbors ) { m_Boids[i].vCohesionForce /= (FLOAT)m_Boids[i].dwNumNeighbors; // Find average location of neighbors D3DXVECTOR3 vDiff = m_Boids[i].vCohesionForce - m_Boids[i].vPos; // Find delta to center of flock FLOAT fMag = D3DXVec3Length( &vDiff ); if( fMag > 0.0f) m_Boids[i].vCohesionForce = vDiff/fMag; // normalized else m_Boids[i].vCohesionForce = D3DXVECTOR3( 0.0f, 0.0f, 0.0f ); } // Find the alignment force if( m_Boids[i].dwNumNeighbors != 0 ) { m_Boids[i].vAlignmentForce /= (FLOAT)m_Boids[i].dwNumNeighbors; FLOAT fMag = D3DXVec3Length( &m_Boids[i].vAlignmentForce ); if( fMag > 0.0f ) { m_Boids[i].vAlignmentForce /= fMag; // normalize D3DXVECTOR3 vDiff = m_Boids[i].vAlignmentForce - m_Boids[i].vDir; m_Boids[i].vAlignmentForce = vDiff / fMag; } } // Finally, the migratory force m_Boids[i].vMigratoryForce = m_vGoal - m_Boids[i].vPos; D3DXVec3Normalize( &m_Boids[i].vMigratoryForce, &m_Boids[i].vMigratoryForce ); } // Update the boids for( i=0; i 1.0f ) vForce /= mag; // first deal with pitch changes if( vForce.y > 0.01f ) { // we're too low m_Boids[i].pitch += AngleTweak; if (m_Boids[i].pitch > 0.8f) m_Boids[i].pitch = 0.8f; } else if( vForce.y < -0.01f ) { // we're too high m_Boids[i].pitch -= AngleTweak; if (m_Boids[i].pitch < -0.8f) m_Boids[i].pitch = -0.8f; } else { // add damping m_Boids[i].pitch *= 0.98f; } // speed up or slow down depending on angle of attack m_Boids[i].speed -= m_Boids[i].pitch * g_fPitchToSpeedRatio; // damp back to normal m_Boids[i].speed = (m_Boids[i].speed-g_fNormalSpeed)*0.99f + g_fNormalSpeed; // limit speed changes to +- 50% from normal if( m_Boids[i].speed < g_fNormalSpeed/2 ) m_Boids[i].speed = g_fNormalSpeed/2; if( m_Boids[i].speed > g_fNormalSpeed*5 ) m_Boids[i].speed = g_fNormalSpeed*5; // now figure out yaw changes D3DXVECTOR3 vOffset = vForce; vOffset.y = 0.0f; D3DXVECTOR3 vDelta = m_Boids[i].vDir; if( D3DXVec3Length( &vOffset ) > 0.0f ) D3DXVec3Normalize( &vOffset, &vOffset ); float dot = D3DXVec3Dot( &vOffset, &vDelta ); // speed up slightly if not turning much if (dot > 0.7f) { dot -= 0.7f; m_Boids[i].speed += dot * 0.005f; } D3DXVec3Cross( &vOffset, &vOffset, &vDelta ); // D3DXVec3Cross( &vOffset, &vDelta, &vOffset ); dot = (1.0f-dot)/2.0f * 0.07f; if( vOffset.y > 0.05f ) { m_Boids[i].dyaw = (m_Boids[i].dyaw*19.0f + dot) * 0.05f; } else if( vOffset.y < -0.05f ) { m_Boids[i].dyaw = (m_Boids[i].dyaw*19.0f - dot) * 0.05f; } else { m_Boids[i].dyaw *= 0.98f; // damp it } m_Boids[i].yaw += m_Boids[i].dyaw; m_Boids[i].roll = -m_Boids[i].dyaw * 20.0f; // Take new info and create a new world matrix // First translate into place, then set orientation, then scale (if needed) D3DXMATRIX matTrans, matRotateX, matRotateY, matRotateZ, matTemp1, matTemp2; D3DXMatrixTranslation( &matTrans, m_Boids[i].vPos.x, m_Boids[i].vPos.y, m_Boids[i].vPos.z ); D3DXMatrixRotationX( &matRotateX, -m_Boids[i].pitch ); D3DXMatrixRotationY( &matRotateY, -m_Boids[i].yaw ); D3DXMatrixRotationZ( &matRotateZ, -m_Boids[i].roll ); D3DXMatrixMultiply( &matTemp1, &matRotateX, &matRotateY ); D3DXMatrixMultiply( &matTemp2, &matRotateZ, &matTemp1 ); D3DXMatrixMultiply( &m_Boids[i].matWorld, &matTemp2, &matTrans ); // Now extract the boid's direction out of the matrix m_Boids[i].vDir.x = m_Boids[i].matWorld._31; m_Boids[i].vDir.y = m_Boids[i].matWorld._32; m_Boids[i].vDir.z = m_Boids[i].matWorld._33; // And update the boid's location m_Boids[i].vPos += m_Boids[i].vDir * m_Boids[i].speed * 100 * fElapsedTime; } }