/*
* Copyright (C) 1996, Christopher John Kline
* Electronic mail: ckline@acm.org
*
* This software may be freely copied, modified, and redistributed
* for academic purposes and by not-for-profit organizations, provided that
* this copyright notice is preserved on all copies, and that the source
* code is included or notice is given informing the end-user that the source
* code is publicly available under the terms described here.
*
* Persons or organizations wishing to use this code or any modified version
* of this code in a commercial and/or for-profit manner must contact the
* author via electronic mail (preferred) or other method to arrange the terms
* of usage. These terms may be as simple as giving the author visible credit
* in the final product.
*
* There is no warranty or other guarantee of fitness for this software,
* it is provided solely "as is". Bug reports or fixes may be sent
* to the author, who may or may not act on them as he desires.
*
* If you use this software the author politely requests that you inform him via
* electronic mail.
*
*/
// Boid.h
//
// INTERFACE: Class for objects that move with A-Life boid-type behavior.
//
// (c) 1996 Christopher Kline
//
// $Id: Boid.h,v 1.5 1996/07/21 17:44:45 ckline Exp ckline $
#ifndef __BOID_H
#define __BOID_H
#include
#include "NamedObject.h"
#include "Obstacle.h"
class Boid : public SimObject {
public:
enum boidTypes {
NORMAL = 0,
PREDATOR,
PREY
};
Boid(Vector bPosition, Vector bVelocity, Vector bDimensions);
// Constructor. Creates a bird of type NORMAL with the given dimensions,
// initial position, and velocity.
// bDimensions.{x,y,z} = {length, width, height}
virtual bool update(const double &elapsedSeconds);
// Updates this object based on the amount of elapsed time since the last
// update, and the previous acceleration and velocity.
double maxVelocity;
// [m/sec] Maximum magnitude of velocity. Default value is 10
double maxAcceleration;
// [m/(sec^2)] Maximum magnitude of acceleration as a fraction of
// maxVelocity. Default value is 0.5
double cruiseDistance;
// [m] Desired distance from closest neighbor when flying. Default value
// is twice the bodylength.
double roll;
// [radians] Rotation around body-local z-axis (+roll =
// counterclockwise). Default value is 0.
double pitch;
// [radians] Rotation around body-local x-axis (+pitch = nose tilting
// upward). Default value is 0.
double yaw;
// [radians] Rotation around body-local y-axis (increasing
// counterclockwise, 0 is along body-local +z). Default value is 0.
static ObstacleList obstacles;
// Linked list of obstacles that every boid will try to avoid. By default
// there are no obstacles. If you add an obstacle to this list, _all_
// boids will see it (because it's a static member).
protected:
virtual double getGravAcceleration(void) const;
// Returns the magnitude of gravitational acceleration in the (0, -1, 0)
// direction [m/(sec^2)].
virtual double accumulate(Vector &accumulator, Vector valueToAdd);
// Given an accumulator and a value to add to the accumulator, this
// method truncates the magnitude of valueToAdd so that, when added to the
// accumulator, the magnitude of the accumulator is at most 1.0. It then
// adds the truncated value to the accumulator. The value returned is the
// magnitude of the accumulator after the addition.
virtual float getProbeLength(void);
// Returns how far in front of boid to probe for obstacles. By default,
// the probe length scales linearly from 10 times bodylength to 50 times
// bodylength as the boid accelerates from 0 m/s to maxVelocity.
virtual double desiredCruisingSpeed(void);
// Returns the speed the boid would like to travel at when not under any
// other influences (i.e., obstacles, flocking desires, etc). The default
// value is 1/5 of maxVelocity.
virtual void calculateVisibilityMatrix(void);
// Each boid helps maintain a visibility matrix, which is an NxN matrix,
// where N is the current number of boids (it is dynamically expanded each
// time a new boid is created). Each cell [A,B] represents whether boid A can
// see boid B. The contents of the matrix are described further in the
// visMatrix macro in boid.c++
// The reason for this matrix is to drastically reduce the computational
// complexity of determining which boids are visible to the others.
virtual int visibleToSelf(Boid *b);
// Returns 1 if this boid can see boid b, 0 otherwise.
virtual void calculateRollPitchYaw(Vector appliedAcceleration,
Vector currentVelocity,
Vector currentPosition);
// Calculate the roll, pitch, and yaw of this boid based on its
// acceleration, velocity, and position. Though position isn't necessary
// for most approximations of attitude, it may be useful in some
// circumstances.
virtual Vector levelFlight(Vector AccelSoFar);
// Returns a vector which indicates how the boid would like to accelerate
// in order to fly level (i.e., with minimal pitch).
virtual Vector wander(void);
// Returns a vector which indicates how the boid would like to accelerate
// when not under any other influences. Related to desiredCruisingSpeed().
virtual Vector collisionAvoidance(void);
// Returns a vector which indicates how the boid would like to accelerate
// in order to avoid collisions with non-boid obstacles.
virtual Vector resolveCollision(Vector pointOnObject, Vector normalToObject);
// Called by CollisionAvoidance, this method attempts to avoid a collision
// with a specific obstacle, and returns an acceleration vector indicating
// how the boid should accelerate to achieve this end.
virtual Vector maintainingCruisingDistance(void);
// Returns a vector which indicates how the boid would like to accelerate
// in order to maintain a distance of cruiseDistance from the nearest
// visible boid.
virtual Vector velocityMatching(void);
// Returns a vector which indicates how the boid would like to accelerate
// in order to fly at approximately the same speed and direction as the
// nearby boids.
virtual Vector flockCentering(void);
// Returns a vector which indicates how the boid would like to accelerate
// in order to be near the center of the flock.
virtual Vector navigator(void);
// This method prioritizes and resolves the acceleration vectors from
// CollisionAvoidance(), FlockCentering(), MaintainingCruisingDistance(),
// VelocityMatching(), Wander(), and LevelFlight(). It returns the actual
// acceleration vector that the boid will apply to its flight in the
// current time step.
virtual int getBoidType(void) const;
// Returns the type of this boid.
double bodyLength;
// [m] Length of the boid. By default this value is equal to the z
// component of the bDimensions passed to the constructor.
double time;
// [sec] current time
int boidNumber;
// Unique integer identifying the number of this boid. The first boid
// created is given boidNumber 1, and the values increase sequentially.
char bName[50];
// Name of self. This is used by the ObjectList data structure. The
// constructor sets this equal to "boidX" where X is the boidNumber.
bool flockSelectively;
// Should this boid flock only with boids of the same boidType, or with
// all boids? The default value is FALSE, meaning that this boid will
// flock with all boids regardless of type.
// Basically, should boids of a feather stick together? :)
int boidType;
// Identifies the type of boid for selective flocking
static ObjectList boidList;
// A boid is added to this list when its constructor is called. All boids
// have access to this list, and use it to determine where all the other
// boids are.
static int **visibilityMatrix;
// See description in CalculateVisibilityMatrix() and the comments for the
// visMatrix macro for more info.
static int boidCount;
// Total number of boids that have been created so far. Note that this
// value increases monotonically, and does NOT take into account boids
// that have been deleted.
private:
Vector oldVelocity;
// [m/sec] velocity at last update.
Vector acceleration;
// [m/(sec^2)] acceleration requested at last update.
bool flightflag;
// Has the boid been updated at least once?
};
// ------------------------------------------------ inline methods ------------------------------------------------
inline double
Boid::getGravAcceleration(void) const
{
return 9.806650;
}
inline int
Boid::getBoidType(void) const
{
return boidType;
}
inline int
Boid::visibleToSelf(Boid *b)
{
// find out if the boid b is within our field of view
Vector vectorToObject = b->position - position;
// This isn't perfectly accurate, since we're not always facing in
// the direction of our velocity, but it's close enough.
return(AngleBetween(velocity, vectorToObject) <= 1.0471967); // pi/3 radians is our FOV
}
inline float
Boid::getProbeLength(void)
{
float maxScale = 5;
// When we're at maxVelocity, scalefactor = maxScale.
// When our velocity is 0, scalefactor = 1.
// Linearly scale in between.
float scaleFactor = ((maxScale-1)/maxVelocity) * Magnitude(velocity) + 1;
return 10*bodyLength*scaleFactor;
}
inline double
Boid::desiredCruisingSpeed(void) {
return 0.2*maxVelocity;
}
inline Vector
Boid::levelFlight(Vector AccelSoFar) {
// Determine the vertical acceleration.
Vector verticalAcc(0, AccelSoFar.y, 0);
// Try to negate it.
return -verticalAcc;
}
#endif /* __BOID_H */