📄 boid.java
字号:
// Boid.java
// Andrew Davison, April 2005, ad@fivedots.coe.psu.ac.th
// Sirinart Sakarin, March 2003, s4210315@calvin.coe.psu.ac.th
/* A boid is:
BG --> TG --> Shape3D
- a BranchGroup so it can be detached
- a TransformGroup for moving the boid
- a Shape3D for its shape
A boid has position and velocity.
Its default behaviours are to:
* perch occasionally
* avoid obstacles
* stay within the scene volume
* not move faster than the set maximum speed
* to apply Reynold's velocity rules for:
- cohesion
- separation
- alignment
Obstacle avoidance takes precedence over other velocity rules.
The Reynold's rules are stored in the Boid's behaviour object.
In general, rules which require an examination of flockmates
(which are dynmaically changing) are stored in the behaviour.
Rules which check static things (e.g. obstacles, scene volume)
are carried out in the boid itself.
The boid is updated by a call to animateBoid() which can be
overriden to add extra behaviours. However, the addition of extra
velocity rules should be done by overriding doVelocityRules().
A boid may be 'eaten' which causes it to be detached from the scene
and removed from its BoidsList
*/
import javax.media.j3d.*;
import javax.vecmath.*;
import java.util.*;
public class Boid extends BranchGroup
{
// the boundaries for boid movement in the scene
private final static int FLOOR_LEN = 20; // should be even
private final static Point3f MIN_PT =
new Point3f( -(float)FLOOR_LEN/2.0f, 0.05f, -(float)FLOOR_LEN/2.0f);
private final static Point3f MAX_PT =
new Point3f( (float)FLOOR_LEN/2.0f, 8.0f, (float)FLOOR_LEN/2.0f);
private final static float MAX_SPEED = 0.2f;
private static final float AVOID_WEIGHT = 0.2f; // scaling for avoidance vel.
private final static int PERCH_TIME = 5; // how long to perch
private final static int PERCH_INTERVAL = 100; // how long between perches
private static final float BOID_RADIUS = 0.3f; // larger than actual radius
// used for boid's bounding sphere
// available to subclasses
protected FlockBehavior beh;
protected ArrayList velChanges = new ArrayList();
// stores all the velocity changes generated by the
// velocity rules at each update
protected Vector3f boidPos = new Vector3f();
protected Vector3f boidVel = new Vector3f();
private TransformGroup boidTG = new TransformGroup();
private Obstacles obstacles;
private BoundingSphere bs = new BoundingSphere(); // bounding sphere for boid
private float maxSpeed;
private int perchTime = 0;
private int perchInterval = 0;
private boolean isPerching = false;
// used for repeated calculations
private Vector3f avoidOb = new Vector3f(); // for the obstacle avoidance velocity
private Transform3D t3d = new Transform3D(); // for storing boid moves
private Vector3f newVel = new Vector3f(); // for holding the new boid velocity
public Boid(Color3f boidColour, float velFactor,
Obstacles obs, FlockBehavior bh)
{
maxSpeed = MAX_SPEED*velFactor; // to vary the maxSpeed
obstacles = obs;
beh = bh;
boidTG.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
boidTG.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
addChild(boidTG);
boidPos.set( randPosn(), (float)(Math.random()*6.0), randPosn() );
boidVel.set( randVel(), randVel(), randVel());
bs.setRadius(BOID_RADIUS); // set bounding sphere's radius
moveBoid();
boidTG.addChild( new BoidShape(boidColour) ); // add boid shape to TG
} // end of Boid()
private float randPosn()
// return a float between -FLOOR_LEN/2 and FLOOR_LEN/2
{ return (float)(Math.random()*FLOOR_LEN - FLOOR_LEN/2); }
private float randVel()
// return a float between -MAX_SPEED/2 and MAX_SPEED/2
{ return (float)(Math.random()*MAX_SPEED*2 - MAX_SPEED); }
private void moveBoid()
/* Boid movement is a rotation and a translation, which use
the current boid velocity and position.
*/
{ t3d.setIdentity(); // reset t3d
t3d.rotY( Math.atan2( boidVel.x, boidVel.z) ); // rotate around y-axis
// atan2() handles 0 value input arguments
t3d.setTranslation(boidPos);
boidTG.setTransform(t3d); // move the TG
} // end of moveBoid()
// -------------------------- animateBoid ---------------------
// called by FlockBehavior and subclasses
public void animateBoid()
// top-level method for updating the boid
{
if (isPerching) {
if (perchTime > 0) {
perchTime--; // perch a while longer
return; // skip rest of boid update
}
else { // finished perching
isPerching = false;
boidPos.y = 0.1f; // give the boid a push up off the floor
perchInterval = 0;
}
}
// update the boid's vel & posn, but keep within scene bounds
boidVel.set( calcNewVel() );
boidPos.add(boidVel);
keepInBounds();
moveBoid();
} // end of animateBoid()
private Vector3f calcNewVel()
/* Apply the velocity rules, storing the new velocities
in the velChanges ArrayList. Then add the velocities
together, and limit the total speed to maxSpeed.
The velocity rules are only applied if there are no obstacles
-- obstacle avoidance has priority over the velocity rules
*/
{ velChanges.clear(); // reset ArrayList
Vector3f v = avoidObstacles(); // check for obstacle avoidance
if ((v.x == 0.0f) && (v.z == 0.0f)) // if no obstacles velocity
doVelocityRules(); // then carry out the other velocity rules
else
velChanges.add(v); // else only do obstacle avoidance
newVel.set( boidVel ); // re-initialise newVel
for(int i=0; i < velChanges.size(); i++)
newVel.add( (Vector3f)velChanges.get(i) ); // add vels to newVel
newVel.scale( limitMaxSpeed() );
return newVel;
} // end of calcNewVel()
protected void doVelocityRules()
// override this method to add new velocity rules
{
Vector3f v1 = beh.cohesion(boidPos);
Vector3f v2 = beh.separation(boidPos);
Vector3f v3 = beh.alignment(boidPos, boidVel);
velChanges.add(v1);
velChanges.add(v2);
velChanges.add(v3);
} // end of doVelocityRules()
private Vector3f avoidObstacles()
/* The boid avoids obstacles by checking it's bounding sphere
against all the obstacles. The avoidance velocity is stored in avoidOb.
We don't bother calculating a real rebound velocity, just move
away by some random amount in the x- and z- direction.
We don't handle impacts on the top of obstacles which require a change
in the y- direction.
*/
{ avoidOb.set(0,0,0); // reset
// update the BoundingSphere's position (but its radius stays the same)
bs.setCenter( new Point3d( (double)boidPos.x, (double)boidPos.y,
(double)boidPos.z) );
if ( obstacles.isOverlapping(bs)) {
avoidOb.set( -(float)Math.random()*boidPos.x, 0.0f,
-(float)Math.random()*boidPos.z);
// scale to reduce distance moved away from the obstacle
avoidOb.scale(AVOID_WEIGHT);
}
return avoidOb;
} // end of avoidObstacles()
private float limitMaxSpeed()
// scale boid speed so no faster than maxSpeed
{
float speed = boidVel.length();
if(speed > maxSpeed)
return maxSpeed/speed;
else
return 1.0f; // no scaling
} // end of limitMaxSpeed
private void keepInBounds()
/* Adjust the boid's position and velocity so it stays
within the volume of space defined by MIN_PT and MAX_PT.
Also check if perching should be started.
*/
{
// check if x part of the boid's position is within the volume
if (boidPos.x > MAX_PT.x) { // beyond max boundary
boidPos.x = MAX_PT.x; // put back at edge
boidVel.x = -Math.abs(boidVel.x); // move away from boundary
}
else if (boidPos.x < MIN_PT.x) {
boidPos.x = MIN_PT.x;
boidVel.x = Math.abs(boidVel.x);
}
// check if z part is within the volume
if (boidPos.z > MAX_PT.z) {
boidPos.z = MAX_PT.z;
boidVel.z = -Math.abs(boidVel.z);
}
else if (boidPos.z < MIN_PT.z) {
boidPos.z = MIN_PT.z;
boidVel.z = Math.abs(boidVel.z);
}
// check if y part is within the volume
if (boidPos.y > MAX_PT.y) {
boidPos.y = MAX_PT.y;
boidVel.y = -Math.abs(boidVel.y);
}
else if (boidPos.y < MIN_PT.y) {
boidPos.y = MIN_PT.y;
boidVel.y = Math.abs(boidVel.y);
}
perchInterval++;
if ((perchInterval > PERCH_INTERVAL) &&
(boidPos.y <= MIN_PT.y)) { // let the boid perch
boidPos.y = 0.0f; // set down on the floor
perchTime = PERCH_TIME; // start perching time
isPerching = true;
}
} // end of keepInBounds()
// ------------------------- other public methods -------------------
public Vector3f getBoidPos()
{ return boidPos; }
public Vector3f getBoidVel()
{ return boidVel; }
} // end of Boid class
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -