⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 boid.java

📁 一个模拟鸟群飞行的3D程序
💻 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 + -