📄 cboid.cpp
字号:
void CBoid::SetPredatorOf (BoidTypes type_v)
{
m_my_predator = type_v;
}
// EatPrey.
// Eat a prey boid if we're close enough.
bool CBoid::EatPrey (void)
{
#ifdef BOID_DEBUG
myprintf("\nInside EatPrey\n");
#endif
// test: are we within "eating distance" of our prey?
if (m_dist_to_nearest_prey <= m_feeding_distance) {
#ifdef BOID_DEBUG
myprintf(" Boid %s is eating boid %s!\n",m_id,m_nearest_prey->GetID());
#endif
// sure are...eat'em up!
// we're not as hungry now
SetHunger(m_starting_hunger * RAND());
// kill the unfortunate boid
m_nearest_prey->SetAlive(FALSE);
// let the flock know
m_preys_flock->SetLiveCount(-1);
m_preys_flock->SetDeadCount(1);
// Ordinarily we'd probably delete the prey boid right here,
// but since we have a big external list in main.cpp (this is
// a demo, after all) we won't. With the boid removed from
// the Flock's list, he won't be updated or drawn.
// clear the prey variables
m_num_prey_seen = 0;
m_nearest_prey = NULL;
m_dist_to_nearest_prey = INFINITY;
// we're done--get outta here
return (TRUE);
}
#ifdef BOID_DEBUG
myprintf(" Boid %s wasn't close enough to eat boid %s!\n",m_id,m_nearest_prey->GetID());
#endif
// fell through..must not have been close enough to eat!
return (FALSE);
}
// KillBoid.
// Kills the boid in question if he's died of hunger.
void CBoid::KillBoid (int flockid_v)
{
//#ifdef BOID_DEBUG
myprintf("\nInside KillBoid\n");
myprintf(" Boid %s has died of hunger and is being removed from flock %d.\n",m_id,flockid_v);
//#endif
// this poor boid has died of hunger--kill him
SetAlive(FALSE);
// Ordinarily we'd probably delete the prey boid right here,
// but since we have a big external list in main.cpp (this is
// a demo, after all) we won't. With the boid removed from
// the Flock's list, he won't be updated or drawn.
}
///////////////////////
// reproduction methods
///////////////////////
// CanReproduce.
// Indicates whether or not this boid can reproduce.
int CBoid::CanReproduce (void)
{
return (m_reproduction_flag);
}
// MakeBaby.
// Makes a new boid for the flock in question,
// assuming all reproduction rules have been met.
void CBoid::MakeBaby (int flockid_v)
{
CBoid *ptr;
#ifdef REPRO_DEBUG
myprintf("\nInside MakeBaby.\n");
myprintf(" Flock %d is going to see if it can create a new boid!\n",flockid_v);
#endif
// Can we SEE enough of our buddies to reproduce?
#ifdef REPRO_DEBUG
myprintf(" checking boids we can see = %d\n",m_num_flockmates_seen);
#endif
if (m_num_flockmates_seen >= NumBoidsForBaby) {
// yep--any dead boids in this flock?
#ifdef REPRO_DEBUG
myprintf("checking dead count = %d\n",CFlock::ListOfFlocks[flockid_v]->GetDeadCount());
#endif
if ((CFlock::ListOfFlocks[flockid_v]->GetDeadCount()) > 0) {
// Yep--that means there's room for a baby. Go
// make one by "reactivating" one of the dead boids.
// search through the list of boids in this flock until we find a dead one
ptr = CFlock::ListOfFlocks[flockid_v]->GetFirstMember();
while (ptr != NULL) {
// test--is this guy dead?
#ifdef REPRO_DEBUG
myprintf(" boid %s state = %d\n",ptr->GetID(),ptr->GetState());
#endif
if (!(ptr->GetState())) {
#ifdef REPRO_DEBUG
myprintf(" making new baby--reactivating boid %s\n",ptr->GetID());
#endif
// yep, he's dead--bring him back to life
ptr->SetAlive(TRUE);
// let the flock know
CFlock::ListOfFlocks[flockid_v]->SetLiveCount(1);
CFlock::ListOfFlocks[flockid_v]->SetDeadCount(-1);
#ifdef REPRO_DEBUG
myprintf("Flock live/dead count = %d %d\n",
CFlock::ListOfFlocks[flockid_v]->GetLiveCount(),
CFlock::ListOfFlocks[flockid_v]->GetDeadCount());
#endif
// we're done--get outta here
return;
}
// get next boid
ptr = ptr->GetNext();
}
}
}
}
// SetReproduction.
// Sets the reproduction flag for this boid.
void CBoid::SetReproduction (bool flag_v)
{
m_reproduction_flag = flag_v;
}
//////////////////////
// personality methods
//////////////////////
// GetPerceptionRange.
// Returns the perception range of the boid in question.
float CBoid::GetPerceptionRange (void)
{
return (m_perception_range);
}
// SetPerceptionRange.
// Sets the perception range of the boid in question.
void CBoid::SetPerceptionRange (float range_v)
{
m_perception_range = range_v;
}
// GetKeepawayDist.
// Returns the preferred keepaway distance of the boid in question.
float CBoid::GetKeepawayDistance (void)
{
return (m_keepaway_distance);
}
// GetPreferredSep.
// Retuns the preferred separation distance of the boid in question.
float CBoid::GetPreferredSep (void)
{
return (m_preferred_separation);
}
// GetState.
// Returns the current state (alive/dead) of the boid in question.
bool CBoid::GetState (void)
{
return (m_alive);
}
////////////////////////
// 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;
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 < MaxFriendsVisible) {
// 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 < MaxFriendsVisible; 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
// not using truth, so check sighting
if (m_perception_range > dist) return (dist);
// fell through; can't see it
return (INFINITY);
}
// CanISeeObstacle.
// Determine whether a given invoking boid can see the obstacle in question.
// Returns the distance to the obstacle if it can be seen, INFINITY if not.
float CBoid::CanISeeObstacle (CObstacle *ptr)
{
float dist, radius;
vector temp1, temp2;
#ifdef VISIBILITY_DEBUG
myprintf("\n Inside CanISeeObstacle.\n");
#endif
// If we're already higher than the obstacle, don't bother--we're not
// going to run into it anyway, so no reason to worry about it.
if (!(ptr->IsHeigher(m_pos.y))) {
// Determine the distance to the obstacle in question. Since the
// obstacles are cones and have some diameter to them (unlike boids,
// which we treat as point masses), we have to find the diameter of
// the obstacle at our height and consider that as part of the sight
// determination calculations.
// what's the distance from my position to the centroid of the obstacle?
temp1 = m_pos; // position of boid
temp2 = ptr->GetPos(); // position of obstacle
// zero out Y values
temp1.y = temp2.y = 0.0f;
// compute the distance between the centroids (no altitude considered)
dist = (temp1.GetDist(temp1, temp2));
#ifdef VISIBILITY_DEBUG
myprintf(" dist between %x and %x = %f\n",this,ptr,dist);
#endif
// Okay, we've got the basic distance between our boid and the centroid
// of the obstacle. However, the obstacle has a given size at this altitude,
// so we have to determine what that is and factor that into the equation.
radius = ptr->GetRelativeRadius(m_pos.y);
#ifdef VISIBILITY_DEBUG
myprintf(" relative radius of Obstacle %x is %f\n",ptr,radius);
myprintf(" perception range = %f\n",m_perception_range);
#endif
// Okay, now we can check distance vs. our range of sight
if (m_perception_range > (dist - radius)) return (dist-radius);
}
// 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);
}
// GetID.
// Returns the ID of the boid in question.
char * CBoid::GetID (void)
{
return (m_id);
}
// 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 = %s @ %x\n", m_id,this);
myprintf(" type = %d\n",m_type);
myprintf(" prey = %d predator = %d\n",m_my_prey, m_my_predator);
myprintf(" starting hunger level = %f\n",m_starting_hunger);
myprintf(" current hunger level = %f\n",m_hunger);
if (m_nearest_prey) myprintf(" currently hunting %s\n",m_nearest_prey->GetID());
myprintf(" perception range = %f\n", m_perception_range);
myprintf(" preferred separation distance = %f\n",m_preferred_separation);
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(" personal max speed = %f\n", m_max_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_predators_seen = %d\n", m_num_predators_seen);
myprintf(" nearest_predator = %x\n", m_nearest_predator);
myprintf(" dist_to_nearest_predator = %f\n", m_dist_to_nearest_predator);
myprintf(" num_prey_seen = %d\n", m_num_prey_seen);
myprintf(" nearest_prey = %x\n", m_nearest_prey);
myprintf(" dist_to_nearest_prey = %f\n", m_dist_to_nearest_prey);
myprintf(" num_obstacles_seen = %d\n", m_num_obstacles_seen);
myprintf(" nearest_obstacle = %x\n", m_nearest_obstacle);
myprintf(" dist_to_nearest_obstacle = %f\n", m_dist_to_nearest_obstacle);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -