/* * Copyright (c) 2009 Anthony Steed and Manuel Fradinho Oliveira * All rights reserved. * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the * following conditions are met: * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other * materials provided with the distribution. * 3. All advertising materials mentioning features or use of * this software must display the following acknowledgement: * This product includes software from the book "Networked * Graphics" written by Anthony Steed and Manuel Fradinho * Oliveira published by Morgan Kaufmann * 4. Neither the name of the University nor of the Department * may be used to endorse or promote products derived from * this software without specific prior written permission. * 5. Neither the name of Cyntelix may be used to enforese or * promote products derived from this software without prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION). HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Contact Info: Anthony Steed * a.steed@cs.ucl.ac.uk * * Manuel Fradinho Oliveira * mfradinho@cyntelix.com * */ import javax.media.j3d.*; import javax.vecmath.*; import java.util.*; class FlockBehaviour extends Behavior { static float INERTIA_FACTOR; static float PULL_FACTOR; static float PROXIMITY_DISTANCE; static float PROXIMITY_FACTOR; static float MAX_VELOCITY; Flock _localFlock; Vector _remoteFlocks; Vector _totalFlock; Network _network; long _t0; WakeupOnElapsedFrames criteria; Vector3f center, inertia, localCenter, pull, diff, auxVel; Transform3D trans; public FlockBehaviour() { INERTIA_FACTOR = 0.1f; PULL_FACTOR = 1.0f;//0.1f;//3.0f; PROXIMITY_DISTANCE = 6.0f;//6.0f;//3.0f; PROXIMITY_FACTOR = 5.0f; MAX_VELOCITY = 5.0f; _localFlock = null; _remoteFlocks = new Vector(); center = new Vector3f(); inertia = new Vector3f(); trans = new Transform3D(); pull = new Vector3f(); diff = new Vector3f(); auxVel = new Vector3f(); localCenter = new Vector3f(); _totalFlock = new Vector(); } public void addFlock(Flock flock) { _remoteFlocks.add(flock); extractBoids(flock); } public void setNetwork(Network network) { _network = network; } public void initialize() { setSchedulingBounds(new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0)); criteria = new WakeupOnElapsedFrames(0); _t0 = System.currentTimeMillis(); wakeupOn(criteria); } public void setLocalFlock(Flock flock) { _localFlock = flock; extractBoids(flock); } private void extractBoids(Flock flock) { Object o; Enumeration e; e = flock.getBoids(); while (e.hasMoreElements()) { o = e.nextElement(); if (o instanceof Boid) { _totalFlock.addElement(o); } } } private void updateBoids(float time) { Boid thisBoid; Boid otherBoid; int proximate; float averageTotalFlockSize = 1/(float)_totalFlock.size(); float tempPullScale = time*PULL_FACTOR; center.set(0,0,0); inertia.set(0,0,0); Enumeration flockIterator; for ( flockIterator = _totalFlock.elements(); flockIterator.hasMoreElements();){ thisBoid = (Boid)flockIterator.nextElement(); center.add(thisBoid._position); inertia.add(thisBoid._velocity); } center.scale(averageTotalFlockSize); inertia.scale(averageTotalFlockSize); inertia.scale(INERTIA_FACTOR*time); for (Enumeration localIterator = _localFlock.getBoids(); localIterator.hasMoreElements();){ thisBoid = (Boid)localIterator.nextElement(); pull.set(center); pull.sub(thisBoid._position); pull.scale(tempPullScale); thisBoid._velocity.add(pull); thisBoid._velocity.add(inertia); proximate = 0; localCenter.set(0,0,0); for (flockIterator = _totalFlock.elements(); flockIterator.hasMoreElements();) { otherBoid = (Boid)flockIterator.nextElement(); if (!otherBoid.equals(thisBoid)) { diff.set(thisBoid._position); diff.sub(otherBoid._position); if (diff.length() < PROXIMITY_DISTANCE) { proximate++; localCenter.add(diff); } } } if (proximate != 0) { localCenter.scale(PROXIMITY_FACTOR*time); thisBoid._velocity.add(localCenter); } // Max velocity float velocity = thisBoid._velocity.length(); if (velocity > MAX_VELOCITY) thisBoid._velocity.scale(MAX_VELOCITY/velocity); // Calculate new position auxVel.set(thisBoid._velocity); auxVel.scale(time); thisBoid._position.add(auxVel); // World limits thisBoid.worldConstraints(); } if (_network !=null) _network.send(_localFlock.getBoids()); } private void drawBoids() { Boid thisBoid; for (Enumeration flock = _totalFlock.elements(); flock.hasMoreElements();){ thisBoid = (Boid)flock.nextElement(); trans.setIdentity(); trans.rotY(Math.atan2(-thisBoid._velocity.x, -thisBoid._velocity.z)); trans.setTranslation(thisBoid._position); thisBoid.setTransform(trans); } } public void processStimulus(Enumeration en) { if (_totalFlock == null) { _t0 = System.currentTimeMillis(); } else { long t; t = System.currentTimeMillis(); updateBoids((t-_t0)/ 1000.0f); drawBoids(); _t0 = t; } wakeupOn(new WakeupOnElapsedFrames(0)); } }