boidsflyer.cpp
来自「3D的Boids效果演示源程序」· C++ 代码 · 共 1,091 行 · 第 1/3 页
CPP
1,091 行
{
return;
}
D3DVALUE tempX, tempY, tempZ;
bool newVelocity = false;
D3DVALUE distance;
D3DVALUE shortestDistance = win -> getFlockFormingDistance( );
D3DVALUE hHeadingTo, vHeadingTo;
D3DVALUE newSpeed, newHHeading, newVHeading;
// Find out the number of Boids present by calling the parent window.
int &numFlyers = win -> getNumObjects( );
// Get a reference to the window's vector of boids.
vector< BoidsFlyer * > &objects = win -> getFlyersRef( );
// Iterate through all the boids ignoring the current one.
for ( int index = 0; index < numFlyers; index++ )
{
// Skip the current boid.
if ( objects[ index ] != this )
{
// Shift the other boid so that the current boid is on the origin.
// This prevents the screen wrap around interfering.
tempX = objects[ index ] -> x - x;
tempY = objects[ index ] -> y - y;
tempZ = objects[ index ] -> z - z;
wrapAround( &tempX, &tempY, &tempZ );
// Do a distance check on the boids.
distance = sqrt( pow( tempX, 2 ) + pow( tempY, 2 )
+ pow( tempZ, 2 ) );
if ( distance <= win -> getFlockFormingDistance( ) )
{
// Check if the boid is in the angle of vision.
// Find the headings to the other boid.
// First find the vertical heading.
if ( distance < 0.5 ) // Prevent division by zero.
{
distance = D3DVALUE( 0.5 );
}
vHeadingTo = asin( tempY / distance ) * 180.0 / PI;
// Then find the horizontal heading.
// Prevent division by zero.
if ( ( tempZ > -0.5 ) && ( tempZ < 0.5 ) )
{
tempZ = D3DVALUE( 0.5 );
}
hHeadingTo = atan( tempX / tempZ ) * 180.0 / PI;
// Correct the headings if z is less than zero.
if ( ( tempX > 0.0 ) && ( tempZ < 0.0 ) )
{
hHeadingTo += 180.0;
}
if ( ( tempX < 0.0 ) && ( tempZ < 0.0 ) )
{
hHeadingTo -= 180.0;
}
// Normalize the headings, so that -
// - they can be properly compared.
hHeadingTo -= hHeading;
vHeadingTo -= vHeading;
maintainHeadings( &hHeadingTo, &vHeadingTo );
if ( ( hHeadingTo <= win -> getAngleOfVision( ) )
&& ( hHeadingTo >= -( win -> getAngleOfVision( ) ) )
&& ( vHeadingTo <= win -> getAngleOfVision( ) )
&& ( vHeadingTo >= -( win -> getAngleOfVision( ) ) ) )
{
if ( distance < shortestDistance )
{
// Restore the headings so that -
// - they can be used properly.
hHeadingTo += hHeading;
vHeadingTo += vHeading;
maintainHeadings( &hHeadingTo, &vHeadingTo );
// Set the new required velocity.
newVelocity = true;
shortestDistance = distance;
newHHeading = hHeadingTo;
newVHeading = vHeadingTo;
newSpeed = objects[ index ] ->
speed + CATCH_UP_INCREASE;
// Limit the speed.
if ( newSpeed > win -> getMaximumSpeed( ) )
{
newSpeed = win -> getMaximumSpeed( );
}
}
}
}
}
}
if ( newVelocity )
{
setReqVelocity( newSpeed, newHHeading, newVHeading );
}
}
// Function to enable a boid to match it's flockmates velocites.
void BoidsFlyer::velocityMatching( )
{
BoidsWin *win = static_cast< BoidsWin * >( window );
// Only perform velocity matching if the flag is set.
if ( win -> getVelocityMatchingActive( ) == false )
{
return;
}
D3DVALUE tempX, tempY, tempZ;
bool newVelocity = false;
D3DVALUE distance;
D3DVALUE hHeadingOf, vHeadingOf;
D3DVALUE totalSpeed = 0, totalHHeading = 0, totalVHeading = 0;
int flockmates = 0;
D3DVALUE newSpeed, newHHeading, newVHeading;
// Find out the number of Boids present by calling the parent window.
int &numFlyers = win -> getNumObjects( );
// Get a reference to the window's vector of boids.
vector< BoidsFlyer * > &objects = win -> getFlyersRef( );
// Iterate through all the boids ignoring the current one.
for ( int index = 0; index < numFlyers; index++ )
{
// Skip the current boid.
if ( objects[ index ] != this )
{
// Shift the other boid so that the current boid is on the origin.
// This prevents the screen wrap around from interfering.
tempX = objects[ index ] -> x - x;
tempY = objects[ index ] -> y - y;
tempZ = objects[ index ] -> z - z;
wrapAround( &tempX, &tempY, &tempZ );
// Do a distance check on the boids.
distance = sqrt( pow( tempX, 2 ) +
pow( tempY, 2 ) + pow( tempZ, 2 ) );
// If the distance is in the flocking radius.
if ( distance <= win -> getFlockingRadius( ) )
{
// Check that the headings are similar.
// Get the headings of the other boid.
hHeadingOf = objects[ index ] -> hHeading;
vHeadingOf = objects[ index ] -> vHeading;
// Normalise the headings, so that -
// - they can be properly compared.
hHeadingOf -= hHeading;
vHeadingOf -= vHeading;
maintainHeadings( &hHeadingOf, &vHeadingOf );
if ( ( hHeadingOf <= +( win ->
getRangeOfFlockHeadings( ) ) )
&& ( hHeadingOf >= -( win ->
getRangeOfFlockHeadings( ) ) )
&& ( vHeadingOf <= +( win ->
getRangeOfFlockHeadings( ) ) )
&& ( vHeadingOf >= -( win ->
getRangeOfFlockHeadings( ) ) ) )
{
// Restore the headings so that they can be used properly.
hHeadingOf += hHeading;
vHeadingOf += vHeading;
maintainHeadings( &hHeadingOf, &vHeadingOf );
// Take the boids velocity into account ( in the flock ).
// Add the components to the totals -
// - to find an average later on.
totalSpeed += objects[ index ] -> speed;
totalHHeading += hHeadingOf;
totalVHeading += vHeadingOf;
flockmates++;
newVelocity = true;
}
}
}
}
if ( newVelocity )
{
newSpeed = totalSpeed / flockmates;
newHHeading = totalHHeading / flockmates;
newVHeading = totalVHeading / flockmates;
setReqVelocity( newSpeed, newHHeading, newVHeading );
}
}
// Function to detect and prevent any boid collisions.
void BoidsFlyer::collisionAvoidance( )
{
BoidsWin *win = static_cast< BoidsWin * >( window );
// Only perform collision avoidance if the flag is set.
if ( win -> getCollisionAvoidanceActive( ) == false )
{
return;
}
D3DVALUE tempX, tempY, tempZ;
bool newVelocity = false;
D3DVALUE distance;
D3DVALUE shortestDistance = win -> getCollisionDistance( );
D3DVALUE hHeadingTo, vHeadingTo;
D3DVALUE newSpeed, newHHeading, newVHeading;
// Find out the number of Boids present by calling the parent window.
int &numFlyers = win -> getNumObjects( );
// Get a reference to the window's vector of boids.
vector< BoidsFlyer * > &objects = win -> getFlyersRef( );
// Iterate through all the boids ignoring the current one.
for ( int index = 0; index < numFlyers; index++ )
{
// Skip the current boid.
if ( objects[ index ] != this )
{
// Shift the other boid so that the current boid is on the origin.
// This prevents the screen wrap around interfering.
tempX = objects[ index ] -> x - x;
tempY = objects[ index ] -> y - y;
tempZ = objects[ index ] -> z - z;
wrapAround( &tempX, &tempY, &tempZ );
// Do a distance check on the boids.
distance = sqrt( pow( tempX, 2 ) +
pow( tempY, 2 ) + pow( tempZ, 2 ) );
if ( distance <= win -> getCollisionDistance( ) )
{
// Find the headings to the other boid.
// First find the vertical heading.
if ( distance < 0.5 ) // Prevent division by zero.
{
distance = D3DVALUE( 0.5 );
}
vHeadingTo = asin( tempY / distance ) * 180.0 / PI;
// Then find the horizontal heading.
// Prevent division by zero.
if ( ( tempZ > -0.5 ) && ( tempZ < 0.5 ) )
{
tempZ = D3DVALUE( 0.5 );
}
hHeadingTo = atan( tempX / tempZ ) * 180.0 / PI;
// Correct the headings if z is less than zero.
if ( ( tempX > 0.0 ) && ( tempZ < 0.0 ) )
{
hHeadingTo += 180.0;
}
if ( ( tempX < 0.0 ) && ( tempZ < 0.0 ) )
{
hHeadingTo -= 180.0;
}
if ( distance < shortestDistance )
{
newVelocity = true;
shortestDistance = distance;
// Set the new headings.
// Normalise the headings, so that -
// - they can be properly calculated.
hHeadingTo -= hHeading;
vHeadingTo -= vHeading;
maintainHeadings( &hHeadingTo, &vHeadingTo );
if ( hHeadingTo >= 0.0 ) // Turn left.
{
newHHeading = hHeading + ( hHeadingTo - 90 )
* ( distance / win -> getCollisionDistance( ) );
}
if ( hHeadingTo < 0.0 ) // Turn right.
{
newHHeading = hHeading + ( hHeadingTo + 90 )
* ( distance / win -> getCollisionDistance( ) );
}
if ( vHeadingTo >= 0.0 ) // Turn down.
{
newVHeading = vHeading + ( vHeadingTo - 90 )
* ( distance / win -> getCollisionDistance( ) );
}
if ( vHeadingTo < 0.0 ) // Turn up.
{
newVHeading = vHeading + ( vHeadingTo + 90 )
* ( distance / win -> getCollisionDistance( ) );
}
// Set the new speed.
newSpeed = objects[ index ] -> speed - (
SLOW_DOWN_DECREASE * ( distance / win ->
getCollisionDistance( ) ) );
// Limit the speed.
if ( newSpeed < win -> getMinimumSpeed( ) )
{
newSpeed = win -> getMinimumSpeed( );
}
}
}
}
}
if ( newVelocity )
{
setReqVelocity( newSpeed, newHHeading, newVHeading );
}
}
// Calculate a position relative to a boid & the -
// - scene, given the distance and direction.
D3DVECTOR BoidsFlyer::calculateOffset( D3DVALUE distance,
D3DVALUE hAngle, D3DVALUE vAngle )
{
D3DVECTOR position;
// 1. Find the Y component of the points position.
position.y = distance * D3DVALUE( sin( vAngle / 180.0 * PI ) );
position.y += y; // Make relative to the boid's position.
// 2. Find the horizontal distance to points position
// ( intermediate calculation ).
D3DVALUE horizontalDistance = distance * D3DVALUE(
cos( vAngle / 180.0 * PI ) );
// 3. Find the X component of the points position.
position.x = horizontalDistance * D3DVALUE(
sin( hAngle / 180.0 * PI ) );
position.x += x; // Make relative to the boid's position.
// 4. Find the Z component of the points position.
position.z = horizontalDistance * D3DVALUE(
cos( hAngle / 180.0 * PI ) );
position.z += z; // Make relative to the boid's position.
// 5. Perform a wrap around on the position to ensure it is within range.
wrapAround( &position.x, &position.y, &position.z );
return position;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?