📄 cboid.cpp
字号:
// test: if this is OUR flock, skip it
if (i == flock_id) continue;
#ifdef VISIBILITY_DEBUG
myprintf(" Testing to see if %x can see anybody in flock %d\n",this,i);
#endif
// not our flock, so check it out
enemy = CFlock::ListOfFlocks[i]->GetFirstMember();
while (enemy != NULL) {
#ifdef VISIBILITY_DEBUG
myprintf(" looking at %x\n",enemy);
#endif
// if this enemy is visible...
if ((dist = CanISee(enemy)) != INFINITY) {
// I can see it..increment counter
m_num_enemies_seen++;
// Test: Closest enemy?
if (dist < m_dist_to_nearest_enemy) {
// yes...save it off
m_dist_to_nearest_enemy = dist;
m_nearest_enemy = enemy;
}
}
// get next enemy in flock
enemy = enemy->GetNext();
}
}
#ifdef VISIBILITY_DEBUG
myprintf("\n");
myprintf(" total enemies seen = %d\n",m_num_enemies_seen);
myprintf(" nearest enemy is %x at %f\n",m_nearest_enemy,m_dist_to_nearest_enemy);
#endif
return (m_num_enemies_seen);
}
// SeeFriends.
// Determines which flockmates a given flock boid can see.
int CBoid::SeeFriends (CBoid *first_boid)
{
float dist;
CBoid *flockmate = first_boid;
#ifdef BOID_DEBUG
myprintf("\nInside SeeFriends\n");
#endif
#ifdef VISIBILITY_DEBUG
myprintf(" Building visibilty list for %x...\n",this);
#endif
// clear the existing visibility list of any holdover from last round
ClearVisibleList();
// now figure out who we can see
while (flockmate != NULL) {
// Test: Within sight of this boid?
#ifdef VISIBILITY_DEBUG
myprintf(" looking at %x\n",flockmate);
#endif
if ((dist = CanISee(flockmate)) != INFINITY) {
// add it to the list
AddToVisibleList(flockmate);
// Test: If this guy is closer than the current
// closest, make him the current closest
if (dist < m_dist_to_nearest_flockmate) {
m_dist_to_nearest_flockmate = dist;
m_nearest_flockmate = flockmate;
}
}
// next flockmate
flockmate = flockmate->GetNext();
}
#ifdef VISIBILITY_DEBUG
myprintf("\n");
myprintf(" total flockmates seen = %d\n",m_num_flockmates_seen);
myprintf(" nearest flockmate is %x at %f\n",
m_nearest_flockmate, m_dist_to_nearest_flockmate);
#endif
return (m_num_flockmates_seen);
}
// SteerToCenter.
// Generates a vector to guide a flock boid towards
// the "center of mass" of the flockmates he can see.
vector CBoid::SteerToCenter (void)
{
vector center, change;
#ifdef BOID_DEBUG
myprintf("\nInside SteerToCenter\n");
#endif
// walk down the visibility list and sum up their position vectors
for (int i = 0; i < m_num_flockmates_seen; i++) {
if (VisibleFriendsList[i] != NULL) center += VisibleFriendsList[i]->m_pos;
}
#ifdef BOID_DEBUG
myprintf(" perceived center before averaging = %f %f %f\n",center.x, center.y, center.z);
myprintf(" num_flockmates_seen = %d\n",m_num_flockmates_seen);
#endif
// average the positions to get the perceived center of the flock
center /= m_num_flockmates_seen;
#ifdef BOID_DEBUG
myprintf(" perceived center after averaging = %f %f %f\n",center.x, center.y, center.z);
#endif
// now that we have the perceived center, computer a vector towards it
change = center - m_pos;
// Scale the change vector so we don't turn on a dime..
change.SetMagnitudeOfVector (MinUrgency);
#ifdef BOID_DEBUG
myprintf(" final change vector from SteerToCenter = %f %f %f\n",
change.x, change.y, change.z);
#endif
// return change vector
return (change);
}
// WorldBound.
// Implements a world boundary so that flocks don't fly
// infinitely far away from the camera, instead remaining
// in a nice viewable area. It does this by wrapping flock
// boids around to the other side of the world, so (for example)
// they move out the right and return on the left.
// Returns: nothing.
void CBoid::WorldBound (void)
{
float maxX = CBox::WorldPtr->GetBoxWidth()/2;
float maxY = CBox::WorldPtr->GetBoxHeight()/2;
float maxZ = CBox::WorldPtr->GetBoxLength()/2;
float minX = -maxX;
float minY = -maxY;
float minZ = -maxZ;
#ifdef BOID_DEBUG
myprintf("\nInside Worldbound\n");
#endif
// test position of flock boid and
// 'warp' if they've strayed out of bounds
if (m_pos.x > maxX) {
m_pos.x = minX;
} else if (m_pos.x < minX) {
m_pos.x = maxX;
} else if (m_pos.y > maxY) {
m_pos.y = minY;
} else if (m_pos.y < minY) {
m_pos.y = maxY;
} else if (m_pos.z > maxZ) {
m_pos.z = minZ;
} else if (m_pos.z < minZ) {
m_pos.z = maxZ;
}
}
////////////////////////
// miscellaneous methods
////////////////////////
// AccumulateChanges.
// Adds vector values in changes into the accumumlator vector.
// Returns: magnitude of accumulator vector after adding changes.
float CBoid::AccumulateChanges (vector &accumulator, vector changes)
{
#ifdef BOID_DEBUG
myprintf("\nInside AccumulateChanges\n");
#endif
// apply the change
accumulator += changes;
//accumulator.x += changes.x;
//accumulator.y += changes.y;
//accumulator.z += changes.z;
return (accumulator.length());
}
// AddToVisibleList.
// Adds a boid to the list of visible boids.
// This visibility list is regenerated for each boid each update cycle,
// and acts much like a push-down queue; the latest boid added to the
// list becomes the first one when the list is sequentially accessed.
// Mostly I did this for speed reasons, as this allows for fast inserts
// (and we don't delete from this list, we just rebuild it each update cycle).
void CBoid::AddToVisibleList (CBoid *ptr)
{
// test: do we see enough buddies already?
if (m_num_flockmates_seen < Max_Friends_Visible) {
// nope--we can add to this one to the list
VisibleFriendsList[m_num_flockmates_seen] = ptr;
// increment counter
m_num_flockmates_seen++;
}
#ifdef VISIBILITY_DEBUG
int i;
myprintf("visibility list for %x after adding %x:\n",this,ptr);
for (i = 0; i < m_num_flockmates_seen; i++) {
if (VisibleFriendsList[i] != NULL) {
myprintf("VFL = %x\n",VisibleFriendsList[i]);
} else {
break;
}
}
#endif
}
// ClearVisibleList.
// Clears the visibility list.
void CBoid::ClearVisibleList (void)
{
// walk down the list and clear each visible entry
for (int i = 0; i < Max_Friends_Visible; i++) {
VisibleFriendsList[i] = NULL;
}
// clear other visibility info
m_num_flockmates_seen = 0;
m_nearest_flockmate = NULL;
m_dist_to_nearest_flockmate = INFINITY;
}
// Determine whether a given invoking boid can see the boid in question.
// Returns the distance to the boid.
float CBoid::CanISee (CBoid *ptr)
{
#ifdef VISIBILITY_DEBUG
myprintf("\n Inside CanISee.\n");
#endif
// Test: if we're looking at ourselves, never mind
if (this == ptr) return (INFINITY);
// figure out distance
float dist = (m_pos.GetDist(m_pos, ptr->m_pos));
#ifdef VISIBILITY_DEBUG
myprintf(" dist between %x and %x = %f\n",this,ptr,dist);
#endif
// if we're using truth data, don't bother to check sighting
if (UseTruth) return (dist);
// not using truth, so check sighting
if (m_perception_range > dist) return (dist);
// fell through; can't see it
return (INFINITY);
}
// ComputeRPY.
// Computes the roll/pitch/yaw of the flock boid based on its
// latest velocity vector changes. Roll/pitch/yaw are stored in
// the "ang" data boid as follows:
// pitch is about the x axis
// yaw is about the y axis
// roll is about the z axis
//
// All calculations assume a right-handed coordinate system:
// +x = through the left side of the object
// +y = up
// +z = through the nose of the model
//
// All angles are computed in radians.
//
// NOTE: This algorithm was generously provided by Christopher Kline, who originally
// developed it for *his* flocking applications. Thanks Christopher!
void CBoid::ComputeRPY (void)
{
float roll, pitch, yaw;
// Determine the direction of the lateral acceleration.
vector lateralDir = (m_vel % (m_vel - m_oldvel)) % m_vel;
lateralDir.GetDirection();
// Set the lateral acceleration's magnitude. The magnitude is the vector
// projection of the appliedAcceleration vector onto the direction of the
// lateral acceleration).
float lateralMag = (m_vel - m_oldvel) * lateralDir;
// compute roll
if (lateralMag == 0) {
roll = 0.0f;
} else {
roll = (float) -atan2(GRAVITY, lateralMag) + HALF_PI;
}
// compute pitch
pitch = (float) -atan(m_vel.y / sqrt((m_vel.z*m_vel.z) + (m_vel.x*m_vel.x)));
// compute yaw
yaw = (float) atan2(m_vel.x, m_vel.z);
// store them
m_ang.x = pitch;
m_ang.y = yaw;
m_ang.z = roll;
#ifdef BOID_DEBUG
myprintf(" roll = %f pitch = %f yaw = %f\n",roll, pitch, yaw);
#endif
}
// SetNext.
// Set the "next" pointer of an individual boid.
void CBoid::SetNext (CBoid *ptr)
{
m_next = ptr;
}
// GetNext.
// Returns the "next" pointer of the invoking boid.
CBoid * CBoid::GetNext()
{
return (m_next);
}
// SetPrev.
// Set the "prev" pointer of an individual boid.
void CBoid::SetPrev (CBoid *ptr)
{
m_prev = ptr;
}
// GetOrient.
// Returns the orientation of the boid in question.
vector * CBoid::GetOrient (void)
{
return (&m_ang);
}
// GetPos.
// Returns the position of the boid in question.
vector * CBoid::GetPos (void)
{
return (&m_pos);
}
// LinkOut.
// Removes a boid from a list.
void CBoid::LinkOut ()
{
// test location of boid
if ((m_next == NULL) && (m_prev == NULL)) {
SetNext(NULL);
SetPrev(NULL);
} else if (m_next == NULL) {
m_prev->SetNext(NULL);
} else if (m_prev == NULL) {
m_next->SetPrev(NULL);
} else {
m_prev->SetNext(m_next);
m_next->SetPrev(m_prev);
}
}
// PrintData
// Dumps all data describing a given boid.
void CBoid::PrintData (void)
{
myprintf("===================\n");
myprintf("Data for boid = %d @ %x\n", m_id,this);
myprintf(" perception_range = %f\n", m_perception_range);
myprintf(" pos x, y, z = %f %f %f\n", m_pos.x, m_pos.y, m_pos.z);
myprintf(" vel x, y, z = %f %f %f\n", m_vel.x, m_vel.y, m_vel.z);
myprintf(" roll, pitch, yaw = %f %f %f\n", m_ang.z, m_ang.x, m_ang.y);
myprintf(" speed = %f\n", m_speed);
myprintf(" num_flockmates_seen = %d\n", m_num_flockmates_seen);
myprintf(" nearest_flockmate = %x\n", m_nearest_flockmate);
myprintf(" dist_to_nearest_flockmate = %f\n", m_dist_to_nearest_flockmate);
myprintf(" num_enemies_seen = %d\n", m_num_enemies_seen);
myprintf(" nearest_enemy = %x\n", m_nearest_enemy);
myprintf(" dist_to_nearest_enemy = %f\n", m_dist_to_nearest_enemy);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -