Skip to content

Instantly share code, notes, and snippets.

@foldi
Last active Sep 27, 2016
Embed
What would you like to do?
FloraJS | Sheep vs. Wolves

IMPORTANT: If the simulation above does not render correctly, click 'open in a new window'.

FloraJS | Sheep vs. Wolves

This simulation uses a custom Animal class that carries a custom sensor. One group, the Sheep, carries a Wolf sensor that triggers a COWARD behavior. The other group, the Wolves, carries a Sheep sensor that triggers an AGGRESSIVE behavior.

The result... the wolves chase the sheep. To make things fair, the sheep have a 'wrapWorldEdges' property set to true. When they cross the world boundary, they cross to the other side. Wolves however bounce off the world boundary.

Play with the various properties to affect the simulation.

Why use custom classes for this?

Flora's sensors are hardcoded for heat, cold, lights, oxygen and food. So reacting to specific agents requires a custom Sensor class.

Also, Agents only flock with other Agents. So to make distinct flocking groups, we need a custom Animal class that extends Agent and allows us to flock according to a 'name' property.

Why is Animal an extension of Burner.Item and not of Flora.Agent or Flora.Sensor?

I want Burner to contain a root item to make it easy to decouple it from Flora and use with custom classes or a completely different framework. Flora.Mover extends Burner.Item... Flora.Agent extends Flora.Mover.

Run the example here to see Burner rendering an object outside Flora. https://github.com/foldi/Burner/tree/master/public

The example is obviously very simple. But you could build your own custom classes and create simulations beyond the scope of what Flora provides. You could also borrow code from Flora classes as a head start.

var Utils = Flora.Utils,
Mover = Flora.Mover;
function Animal(opt_options) {
var options = opt_options || {};
options.name = options.name || 'Animal';
Mover.call(this, options);
}
Utils.extend(Animal, Mover);
Animal.prototype.init = function(opt_options) {
var options = opt_options || {};
Animal._superClass.prototype.init.call(this, options);
this.followMouse = !!options.followMouse;
this.maxSteeringForce = typeof options.maxSteeringForce === 'undefined' ? 10 : options.maxSteeringForce;
this.seekTarget = options.seekTarget || null;
this.flocking = !!options.flocking;
this.desiredSeparation = typeof options.desiredSeparation === 'undefined' ? this.width * 2 : options.desiredSeparation;
this.separateStrength = typeof options.separateStrength === 'undefined' ? 0.3 : options.separateStrength;
this.alignStrength = typeof options.alignStrength === 'undefined' ? 0.2 : options.alignStrength;
this.cohesionStrength = typeof options.cohesionStrength === 'undefined' ? 0.1 : options.cohesionStrength;
this.flowField = options.flowField || null;
this.sensors = options.sensors || [];
this.color = options.color || [197, 177, 115];
this.borderWidth = options.borderWidth || 0;
this.borderStyle = options.borderStyle || 'none';
this.borderColor = options.borderColor || 'transparent';
this.borderRadius = options.borderRadius || this.sensors.length ? 100 : 0;
//
this.separateSumForceVector = new Burner.Vector(); // used in Agent.separate()
this.alignSumForceVector = new Burner.Vector(); // used in Agent.align()
this.cohesionSumForceVector = new Burner.Vector(); // used in Agent.cohesion()
this.followTargetVector = new Burner.Vector(); // used in Agent.applyForces()
this.followDesiredVelocity = new Burner.Vector(); // used in Agent.follow()
//
Burner.System.updateCache(this);
};
Animal.prototype.applyForces = function() {
var i, max, sensorActivated, sensor, r, theta, x, y;
if (this.sensors.length > 0) { // Sensors
for (i = 0, max = this.sensors.length; i < max; i += 1) {
sensor = this.sensors[i];
r = sensor.offsetDistance; // use angle to calculate x, y
theta = Utils.degreesToRadians(this.angle + sensor.offsetAngle);
x = r * Math.cos(theta);
y = r * Math.sin(theta);
sensor.location.x = this.location.x;
sensor.location.y = this.location.y;
sensor.location.add(new Burner.Vector(x, y)); // position the sensor
if (i) {
sensor.borderStyle = 'none';
}
if (sensor.activated) {
this.applyForce(sensor.getActivationForce(this));
sensorActivated = true;
}
}
}
if (this.seekTarget) { // seek target
this.applyForce(this._seek(this.seekTarget));
}
if (this.flocking) {
this.flock(Burner.System.getAllItemsByName(this.name));
}
return this.acceleration;
};
/**
* Bundles flocking behaviors (separate, align, cohesion) into one call.
*
* @returns {Object} This object's acceleration vector.
*/
Animal.prototype.flock = function(elements) {
this.applyForce(this.separate(elements).mult(this.separateStrength));
this.applyForce(this.align(elements).mult(this.alignStrength));
this.applyForce(this.cohesion(elements).mult(this.cohesionStrength));
return this.acceleration;
};
/**
* Loops through a passed elements array and calculates a force to apply
* to avoid all elements.
*
* @param {array} elements An array of Flora elements.
* @returns {Object} A force to apply.
*/
Animal.prototype.separate = function(elements) {
var i, max, element, diff, d,
sum, count = 0, steer;
this.separateSumForceVector.x = 0;
this.separateSumForceVector.y = 0;
sum = this.separateSumForceVector;
for (i = 0, max = elements.length; i < max; i += 1) {
element = elements[i];
if (this.className === element.className && this.id !== element.id) {
d = this.location.distance(element.location);
if ((d > 0) && (d < this.desiredSeparation)) {
diff = Burner.Vector.VectorSub(this.location, element.location);
diff.normalize();
diff.div(d);
sum.add(diff);
count += 1;
}
}
}
if (count > 0) {
sum.div(count);
sum.normalize();
sum.mult(this.maxSpeed);
sum.sub(this.velocity);
sum.limit(this.maxSteeringForce);
return sum;
}
return new Burner.Vector();
};
/**
* Loops through a passed elements array and calculates a force to apply
* to align with all elements.
*
* @param {array} elements An array of Flora elements.
* @returns {Object} A force to apply.
*/
Animal.prototype.align = function(elements) {
var i, max, element, d,
neighbordist = this.width * 2,
sum, count = 0, steer;
this.alignSumForceVector.x = 0;
this.alignSumForceVector.y = 0;
sum = this.alignSumForceVector;
for (i = 0, max = elements.length; i < max; i += 1) {
element = elements[i];
d = this.location.distance(element.location);
if ((d > 0) && (d < neighbordist)) {
if (this.className === element.className && this.id !== element.id) {
sum.add(element.velocity);
count += 1;
}
}
}
if (count > 0) {
sum.div(count);
sum.normalize();
sum.mult(this.maxSpeed);
sum.sub(this.velocity);
sum.limit(this.maxSteeringForce);
return sum;
}
return new Burner.Vector();
};
/**
* Loops through a passed elements array and calculates a force to apply
* to stay close to all elements.
*
* @param {array} elements An array of Flora elements.
* @returns {Object} A force to apply.
*/
Animal.prototype.cohesion = function(elements) {
var i, max, element, d,
neighbordist = 10,
sum, count = 0, desiredVelocity, steer;
this.cohesionSumForceVector.x = 0;
this.cohesionSumForceVector.y = 0;
sum = this.cohesionSumForceVector;
for (i = 0, max = elements.length; i < max; i += 1) {
element = elements[i];
d = this.location.distance(element.location);
if ((d > 0) && (d < neighbordist)) {
if (this.className === element.className && this.id !== element.id) {
sum.add(element.location);
count += 1;
}
}
}
if (count > 0) {
sum.div(count);
sum.sub(this.location);
sum.normalize();
sum.mult(this.maxSpeed);
sum.sub(this.velocity);
sum.limit(this.maxSteeringForce);
return sum;
}
return new Burner.Vector();
};
/*
Burner
Copyright (c) 2013 Vince Allen | vince@vinceallen.com | http://www.vinceallen.com | florajs.com/license
*/
/* Version: 2.0.4 */
/* Build time: August 24, 2013 12:38:14 */body {background-color: transparent;}
.world {position: absolute;top: 0;left: 0;margin: 0;padding: 0;}
.item {position: absolute;top: 0; left: 0;-webkit-box-sizing: border-box;-moz-box-sizing: border-box;-o-box-sizing: border-box;-ms-box-sizing: border-box;box-sizing: border-box;}
/*
Burner
Copyright (c) 2013 Vince Allen | vince@vinceallen.com | http://www.vinceallen.com | florajs.com/license
*/
/* Version: 2.0.4 */
/* Build time: August 24, 2013 12:38:14 */var Burner={},exports=Burner;
(function(e){function h(a,b){this.x=a||0;this.y=b||0}function l(){var a,b;this.name="StatsDisplay";this._active=!0;this._fps=0;this._timeLastSecond=this._timeLastFrame=this._time=Date.now?Date.now():0;this._frameCount=0;this.el=document.createElement("div");this.el.id="statsDisplay";this.el.className="statsDisplay";this.el.style.backgroundColor="black";this.el.style.color="white";this.el.style.fontFamily="Helvetica";this.el.style.padding="0.5em";this.el.style.opacity="0.5";this._fpsValue=this._totalElementsValue=
null;a=document.createElement("span");a.className="statsDisplayLabel";a.style.marginLeft="0.5em";b=document.createTextNode("total elements: ");a.appendChild(b);this.el.appendChild(a);this._totalElementsValue=document.createTextNode("0");this.el.appendChild(this._totalElementsValue);a=document.createElement("span");a.className="statsDisplayLabel";a.style.marginLeft="0.5em";b=document.createTextNode("fps: ");a.appendChild(b);this.el.appendChild(a);this._fpsValue=document.createTextNode("0");this.el.appendChild(this._fpsValue);
document.body.appendChild(this.el);this._update(this)}function j(){}function i(a){if(!a||!a.world||"object"!==typeof a.world)throw Error('Item: A valid DOM object is required for the new Item "world" property.');this.world=a.world;this.name=a.name||"Item";this.id=this.name+e.System.getNewId();this._force=new e.Vector;this._camera=new e.Vector;this.el=document.createElement("div");this.el.id=this.id;this.el.className="item "+this.name.toLowerCase();this.el.style.visibility="hidden";this.world.el.appendChild(this.el)}
function m(a,b){if(!a||"object"!==typeof a)throw Error('World: A valid DOM object is required for the new World "el" property.');var d=b||{};this.el=a;this.name="World";this.el.className=this.name.toLowerCase();this.id=this.name+e.System.getNewId();this.width=d.width||0;this.height=d.height||0;this.angle=0;this.color=d.color||"transparent";this.colorMode=d.colorMode||"rgb";this.visibility=d.visibility||"visible";this.opacity=d.opacity||1;this.borderWidth=d.borderWidth||0;this.borderStyle=d.borderStyle||
"none";this.borderColor=d.borderColor||"transparent";this.boxShadowOffset=d.boxShadowOffset||new e.Vector;this.boxShadowBlur=d.boxShadowBlur||0;this.boxShadowSpread=d.boxShadowSpread||0;this.boxShadowColor=d.boxShadowColor||"transparent";this.gravity=d.gravity||new e.Vector(0,1);this.c=d.c||0.1;this.boundToWindow=!1===d.boundToWindow?!1:!0;this.location=d.location;this.pauseDraw=this.pauseStep=!1;this._setBounds();this._pool=[];this.world={};this.draw()}function n(a){a=a||{};a.name="Box";e.Item.call(this,
a)}function o(a){a=a||{};a.name="Ball";e.Item.call(this,a)}window.requestAnimFrame=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(a){window.setTimeout(a,1E3/60)};h.VectorSub=function(a,b){return new h(a.x-b.x,a.y-b.y)};h.VectorAdd=function(a,b){return new h(a.x+b.x,a.y+b.y)};h.VectorMult=function(a,b){return new h(a.x*b,a.y*b)};h.VectorDiv=function(a,b){return new h(a.x/b,a.y/
b)};h.VectorDistance=function(a,b){return Math.sqrt(Math.pow(b.x-a.x,2)+Math.pow(b.y-a.y,2))};h.VectorMidPoint=function(a,b){return h.VectorAdd(a,b).div(2)};h.VectorAngleBetween=function(a,b){var d=a.dot(b);return Math.acos(d/(a.mag()*b.mag()))};h.prototype.name="Vector";h.prototype.clone=function(){function a(){}a.prototype=this;return new a};h.prototype.add=function(a){this.x+=a.x;this.y+=a.y;return this};h.prototype.sub=function(a){this.x-=a.x;this.y-=a.y;return this};h.prototype.mult=function(a){this.x*=
a;this.y*=a;return this};h.prototype.div=function(a){this.x/=a;this.y/=a;return this};h.prototype.mag=function(){return Math.sqrt(this.x*this.x+this.y*this.y)};h.prototype.limit=function(a,b){var d=a||null,c=b||null;d&&this.mag()>d&&(this.normalize(),this.mult(d));c&&this.mag()<c&&(this.normalize(),this.mult(c));return this};h.prototype.normalize=function(){var a=this.mag();if(0!==a)return this.div(a)};h.prototype.distance=function(a){return Math.sqrt(Math.pow(a.x-this.x,2)+Math.pow(a.y-this.y,2))};
h.prototype.rotate=function(a){var b=Math.cos(a),a=Math.sin(a),d=this.x,c=this.y;this.x=d*b-c*a;this.y=d*a+c*b;return this};h.prototype.midpoint=function(a){return h.VectorAdd(this,a).div(2)};h.prototype.dot=function(a){return this.z&&a.z?this.x*a.x+this.y*a.y+this.z*a.z:this.x*a.x+this.y*a.y};e.Vector=h;l.prototype.getFPS=function(){return this._fps};l.prototype._update=function(a){var b=e.System.count();a._time=Date.now?Date.now():0;a._frameCount++;a._time>a._timeLastSecond+1E3&&(a._fps=a._frameCount,
a._timeLastSecond=a._time,a._frameCount=0,a._fpsValue.nodeValue=a._fps,a._totalElementsValue.nodeValue=b);var d=this;this._active&&window.requestAnimFrame(function(){d._update(d)})};l.prototype.destroy=function(){this._active=!1;document.getElementById(this.el.id)&&document.body.removeChild(this.el)};e.StatsDisplay=l;j.detect=function(a){return!this[a]?!1:this[a].call(this)};j.csstransforms=function(){var a=document.createDocumentFragment(),b=document.createElement("div");a.appendChild(b);b.style.cssText=
"-webkit-transform: translateX(1px) translateY(1px);-moz-transform: translateX(1px) translateY(1px);-o-transform: translateX(1px) translateY(1px);-ms-transform: translateX(1px) translateY(1px)";for(var a=[b.style.transform,b.style.webkitTransform,b.style.MozTransform,b.style.OTransform,b.style.msTransform],b=!1,d=0;d<a.length;d+=1)if(a[d]){b=!0;break}return b};j.csstransforms3d=function(){var a=document.createDocumentFragment(),b=document.createElement("div");a.appendChild(b);b.style.cssText="-webkit-transform: translate3d(1px, 1px, 0);-moz-transform: translate3d(1px, 1px, 0);-o-transform: translate3d(1px, 1px, 0);-ms-transform: translate3d(1px, 1px, 0)";
for(var a=[b.style.transform,b.style.webkitTransform,b.style.MozTransform,b.style.OTransform,b.style.msTransform],b=!1,d=0;d<a.length;d+=1)if(a[d]){b=!0;break}return b};j.touch=function(){var a=document.createElement("div");a.setAttribute("ongesturestart","return;");return"function"===typeof a.ongesturestart?!0:!1};e.FeatureDetector=j;i.prototype.reset=function(a){var b,a=a||{};for(b in a)a.hasOwnProperty(b)&&(this[b]=a[b]);this.width=void 0===a.width?10:a.width;this.height=void 0===a.height?10:a.height;
this.color=a.color||[0,0,0];this.colorMode=a.colorMode||"rgb";this.visibility=a.visibility||"visible";this.opacity=void 0===a.opacity?1:a.opacity;this.zIndex=void 0===a.zIndex?1:a.zIndex;this.borderWidth=a.borderWidth||0;this.borderStyle=a.borderStyle||"none";this.borderColor=a.borderColor||"transparent";this.borderRadius=a.borderRadius||0;this.boxShadowOffset=void 0===a.boxShadowOffset?new e.Vector:a.boxShadowOffset;this.boxShadowBlur=a.boxShadowBlur||0;this.boxShadowSpread=a.boxShadowSpread||0;
this.boxShadowColor=void 0===a.boxShadowColor?"transparent":a.boxShadowColor;this.bounciness=void 0===a.bounciness?0.8:a.bounciness;this.mass=void 0===a.mass?10:a.mass;this.acceleration="function"===typeof a.acceleration?a.acceleration.call(this):a.acceleration||new e.Vector;this.velocity="function"===typeof a.velocity?a.velocity.call(this):a.velocity||new e.Vector;this.location="function"===typeof a.location?a.location.call(this):a.location||new e.Vector(this.world.width/2,this.world.height/2);this.maxSpeed=
void 0===a.maxSpeed?10:a.maxSpeed;this.minSpeed=a.minSpeed||0;this.angle=a.angle||0;this.lifespan=void 0===a.lifespan?-1:a.lifespan;this.life=a.life||0;this.isStatic=!!a.isStatic;this.controlCamera=!!a.controlCamera;this.worldBounds=a.worldBounds||[!0,!0,!0,!0];this.checkWorldEdges=void 0===a.checkWorldEdges?!0:a.checkWorldEdges;this.wrapWorldEdges=!!a.wrapWorldEdges;this.avoidWorldEdges=!!a.avoidWorldEdges;this.avoidWorldEdgesStrength=void 0===a.avoidWorldEdgesStrength?50:a.avoidWorldEdgesStrength};
i.prototype.step=function(){this.isStatic||(this.applyForce(this.world.gravity),this.velocity.add(this.acceleration),this.velocity.limit(this.maxSpeed,this.minSpeed),this.location.add(this.velocity),this.controlCamera&&this._checkCameraEdges(),this.checkWorldEdges&&this._checkWorldEdges(),this.acceleration.mult(0),this.life<this.lifespan?this.life++:-1!==this.lifespan&&e.System.destroyItem(this))};i.prototype.applyForce=function(a){if(a)return this._force.x=a.x,this._force.y=a.y,this._force.div(this.mass),
this.acceleration.add(this._force),this.acceleration};i.prototype._checkWorldEdges=function(){var a=this.world.bounds[1],b=this.world.bounds[2],d=this.worldBounds,c=this.location,f=this.velocity,e=this.width,k=this.height,h=this.bounciness;this.wrapWorldEdges?(d=c.x,f=c.y,c.x>a?(c.x=0,this.controlCamera&&(this.world.location.x=this.world.location.x+d-c.x)):0>c.x&&(c.x=a,this.controlCamera&&(this.world.location.x=this.world.location.x+d-c.x)),c.y>b)?(c.y=0,this.controlCamera&&(this.world.location.y=
this.world.location.y+f-c.y)):c.y<-k/2&&(c.y=b,this.controlCamera&&(this.world.location.y=this.world.location.y+f-c.y)):(c.x+e/2>a&&d[1]?(c.x=a-e/2,f.x*=-1*h):c.x<e/2&&d[3]&&(c.x=e/2,f.x*=-1*h),c.y+k/2>b&&d[2])?(c.y=b-k/2,f.y*=-1*h):c.y<k/2&&d[0]&&(c.y=k/2,f.y*=-1*h)};i.prototype._checkCameraEdges=function(){this._camera.x=this.velocity.x;this._camera.y=this.velocity.y;this.world.location.add(this._camera.mult(-1))};i.prototype.draw=function(){e.System._draw(this)};e.Item=i;var c={name:"System",_stylePosition:"",
clock:0,supportedFeatures:{csstransforms:!0,csstransforms3d:!0},_records:{lookup:{},list:[]},_worlds:{lookup:{},list:[]},_caches:{},_idCount:0};c.mouse={location:new e.Vector,lastLocation:new e.Vector,velocity:new e.Vector};c._resizeTime=0;c.init=function(a,b,d,g){a=a||function(){};b=b||new e.World(document.body);d=d||null;g=!g?!1:!0;if(d)if("object"===typeof d&&"undefined"!==typeof d.csstransforms&&"undefined"!==typeof d.csstransforms3d)this.supportedFeatures=d;else throw Error("System: supportedFeatures should be passed as an object.");
else this.supportedFeatures=c._getSupportedFeatures();this._stylePosition=c.supportedFeatures.csstransforms3d?"transform: translate3d(<x>px, <y>px, 0) rotate(<angle>deg) scale(<scale>, <scale>); -webkit-transform: translate3d(<x>px, <y>px, 0) rotate(<angle>deg) scale(<scale>, <scale>); -moz-transform: translate3d(<x>px, <y>px, 0) rotate(<angle>deg) scale(<scale>, <scale>); -o-transform: translate3d(<x>px, <y>px, 0) rotate(<angle>deg) scale(<scale>, <scale>); -ms-transform: translate3d(<x>px, <y>px, 0) rotate(<angle>deg) scale(<scale>, <scale>);":
c.supportedFeatures.csstransforms?"transform: translate(<x>px, <y>px) rotate(<angle>deg) scale(<scale>, <scale>); -webkit-transform: translate(<x>px, <y>px) rotate(<angle>deg) scale(<scale>, <scale>); -moz-transform: translate(<x>px, <y>px) rotate(<angle>deg) scale(<scale>, <scale>); -o-transform: translate(<x>px, <y>px) rotate(<angle>deg) scale(<scale>, <scale>); -ms-transform: translate(<x>px, <y>px) rotate(<angle>deg) scale(<scale>, <scale>);":"position: absolute; left: <x>px; top: <y>px;";if("[object Array]"===
Object.prototype.toString.call(b))for(var f=0,h=b.length;f<h;f++)c._addWorld(b[f]);else c._addWorld(b);document.body.onorientationchange=c.updateOrientation;this._addEvent(window,"resize",function(a){c._resize.call(c,a)});this._addEvent(document,"mousemove",function(a){c._recordMouseLoc.call(c,a)});this._addEvent(window,"touchstart",function(a){c._recordMouseLoc.call(c,a)});this._addEvent(window,"touchmove",function(a){c._recordMouseLoc.call(c,a)});this._addEvent(window,"touchend",function(a){c._recordMouseLoc.call(c,
a)});this._addEvent(window,"devicemotion",function(a){var b=c._caches.World.list,d=a.accelerationIncludingGravity.x,g=a.accelerationIncludingGravity.y;f=0;for(h=b.length;f<h;f++)a=b[f],0===window.orientation?(a.gravity.x=d,a.gravity.y=-1*g):-90===window.orientation?(a.gravity.x=g,a.gravity.y=d):(a.gravity.x=-1*g,a.gravity.y=-1*d)});this._addEvent(window,"keyup",function(a){c._keyup.call(c,a)});this._setup=a;this._setup.call(this);g||this._update()};c._addWorld=function(a){c._records.list.push(a);
c._worlds.list.push(c._records.list[c._records.list.length-1]);c._worlds.lookup[a.el.id]=c._records.list[c._records.list.length-1]};c.add=function(a,b,d){var g,f=this._records.list,e=this._records.lookup,b=b||{};b.world=d||f[0];if(this.getAllItemsByName(a,b.world._pool).length){d=0;for(g=b.world._pool.length;d<g;d++)if(b.world._pool[d].name===a){f[f.length]=b.world._pool.splice(d,1)[0];f[f.length-1].options=b;c._updateCacheLookup(f[f.length-1],!0);break}}else f[f.length]=Burner[a]?new Burner[a](b):
new Burner.Classes[a](b);a=f.length-1;e[f[a].id]=f[a].el.parentNode;f[a].reset(b);f[a].init(b);return f[a]};c.start=function(){this._update()};c.updateCache=function(a){var b=c._caches[a.name]||(c._caches[a.name]={lookup:{},list:[]});b.list[b.list.length]=a;b.lookup[a.id]=!0;return b};c._updateCacheLookup=function(a,b){var d=c._caches[a.name];d&&(d.lookup[a.id]=b)};c.count=function(){return this._records.list.length};c.firstWorld=function(){return this._worlds.list.length?this._worlds.list[0]:null};
c.lastWorld=function(){return this._worlds.list.length?this._worlds.list[this._worlds.list.length-1]:null};c.firstItem=function(){return this._records.list[0]};c.lastItem=function(){return this._records.list[this._records.list.length-1]};c.getAllWorlds=function(){return c._worlds.list};c._update=function(){var a,b,d=c._records.list,g,f=c.firstWorld();if(c._resizeTime&&100<(new Date).getTime()-c._resizeTime){c._resizeTime=0;g=c.getAllWorlds();a=0;for(b=g.length;a<b;a++)g[a].pauseStep=!1;f.afterResize&&
f.afterResize.call(this)}for(a=d.length-1;0<=a;a-=1)b=d[a],b.step&&!b.world.pauseStep&&b.step();for(a=d.length-1;0<=a;a-=1)b=d[a],b.draw&&!b.world.drawStep&&b.draw();c.clock++;window.requestAnimFrame(c._update)};c._stepForward=function(){var a,b,d,g=c._records.list,f=c.getAllWorlds();a=0;for(d=f.length;a<d;a++){b=f[a];b.pauseStep=!0;for(b=g.length-1;0<=b;b-=1)g[b].step&&g[b].step();for(b=g.length-1;0<=b;b-=1)g[b].draw&&g[b].draw()}c.clock++};c._resetSystem=function(a){var b,d,g,f=c.getAllWorlds();
b=0;for(d=f.length;b<d;b++){g=f[b];g.pauseStep=!1;for(g.pauseDraw=!1;g.el.firstChild;)g.el.removeChild(g.el.firstChild)}c._caches={};c._destroyAllItems();c._idCount=0;c.mouse={location:new e.Vector,lastLocation:new e.Vector,velocity:new e.Vector};c._resizeTime=0;a||c._setup.call(c)};c._destroySystem=function(){this._resetSystem(!0);this._destroyAllWorlds();this._idCount=this.clock=0};c._destroyAllItems=function(){var a,b=this._records.list;for(a=b.length-1;0<=a;a--)"World"!==b[a].name&&b.splice(a,
1)};c._destroyAllWorlds=function(){var a,b,d=this._records.list;for(a=d.length-1;0<=a;a--)b=d[a],"World"===b.name&&(b.el.parentNode.removeChild(b.el),d.splice(a,1));this._worlds={lookup:{},list:[]}};c.destroyItem=function(a){var b,d,g=this._records.list;b=0;for(d=g.length;b<d;b++)if(g[b].id===a.id){g[b].el.style.visibility="hidden";g[b].el.style.top="-5000px";g[b].el.style.left="-5000px";g[b].world._pool[g[b].world._pool.length]=g.splice(b,1)[0];c._updateCacheLookup(a,!1);break}};c.getAllItemsByName=
function(a,b){var d,c,f=[],e=b||this._records.list;d=0;for(c=e.length;d<c;d++)e[d].name===a&&(f[f.length]=e[d]);return f};c.getAllItemsByAttribute=function(a,b){var d,c,f=[],e=this._records.list,h=void 0!==b?b:null;d=0;for(c=e.length;d<c;d++)void 0!==e[d][a]&&!(null!==h&&e[d][a]!==h)&&(f[f.length]=e[d]);return f};c.updateItemPropsByName=function(a,b){var c,e,f,h=this.getAllItemsByName(a);c=0;for(e=h.length;c<e;c++)for(f in b)b.hasOwnProperty(f)&&(h[c][f]=b[f]);return h};c.getItem=function(a){var b,
c,e=this._records.list;b=0;for(c=e.length;b<c;b+=1)if(e[b].id===a)return e[b];return null};c.updateItem=function(a,b){for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c]);return a};c._resize=function(){var a,b,d=this._records.list,g,f=this.getWindowSize(),h=c.getAllWorlds();a=0;for(b=d.length;a<b;a++)g=d[a],"World"!==g.name&&(g.world.boundToWindow&&g.location)&&(g.location.x=f.width*(g.location.x/g.world.width),g.location.y=f.height*(g.location.y/g.world.height));a=0;for(b=h.length;a<b;a++)d=h[a],d.boundToWindow&&
(d.bounds=[0,f.width,f.height,0],d.width=f.width,d.height=f.height,d.location=new e.Vector(f.width/2,f.height/2))};c._keyup=function(a){var b,d,e=this.getAllWorlds();switch(a.keyCode){case 39:c._stepForward();break;case 80:a=0;for(b=e.length;a<b;a++)d=e[a],d.pauseStep=!d.pauseStep;break;case 82:c._resetSystem();break;case 83:c._toggleStats()}};c.getNewId=function(){this._idCount++;return this._idCount};c._addEvent=function(a,b,c){a.addEventListener?a.addEventListener(b,c,!1):a.attachEvent&&a.attachEvent("on"+
b,c)};c._recordMouseLoc=function(a){var b,c=this.firstWorld();this.mouse.lastLocation.x=this.mouse.location.x;this.mouse.lastLocation.y=this.mouse.location.y;a.changedTouches&&(b=a.changedTouches[0]);a.pageX&&a.pageY?(this.mouse.location.x=this.map(a.pageX,0,window.innerWidth,0,c.width),this.mouse.location.y=this.map(a.pageY,0,window.innerHeight,0,c.height)):a.clientX&&a.clientY?(this.mouse.location.x=this.map(a.clientX,0,window.innerWidth,0,c.width),this.mouse.location.y=this.map(a.clientY,0,window.innerHeight,
0,c.height)):b&&(this.mouse.location.x=b.pageX,this.mouse.location.y=b.pageY);this.mouse.velocity.x=this.mouse.lastLocation.x-this.mouse.location.x;this.mouse.velocity.y=this.mouse.lastLocation.y-this.mouse.location.y};c.extend=function(a,b){function c(){}c.prototype=b.prototype;a.prototype=new c;a.prototype.constructor=a};c.getWindowSize=function(){var a={width:!1,height:!1};"undefined"!==typeof window.innerWidth?(a.width=window.innerWidth,a.height=window.innerHeight):"undefined"!==typeof document.documentElement&&
"undefined"!==typeof document.documentElement.clientWidth?(a.width=document.documentElement.clientWidth,a.height=document.documentElement.clientHeight):"undefined"!==typeof document.body&&(a.width=document.body.clientWidth,a.height=document.body.clientHeight);return a};c.updateOrientation=function(){setTimeout(function(){c._records.list[0]._setBounds()},500)};c.getRandomNumber=function(a,b,c){return c?Math.random()*(b-(a-1))+a:Math.floor(Math.random()*(b-(a-1)))+a};c._toggleStats=function(){c._statsDisplay?
c._statsDisplay&&c._statsDisplay._active?c._statsDisplay.destroy():c._statsDisplay&&!c._statsDisplay._active&&(c._statsDisplay=new e.StatsDisplay):c._statsDisplay=new e.StatsDisplay};c._getSupportedFeatures=function(){return window.Modernizr?{csstransforms3d:Modernizr.csstransforms3d,csstransforms:Modernizr.csstransforms,touch:Modernizr.touch}:{csstransforms3d:e.FeatureDetector.detect("csstransforms3d"),csstransforms:e.FeatureDetector.detect("csstransforms"),touch:e.FeatureDetector.detect("touch")}};
c.map=function(a,b,c,e,f){return(a-b)/(c-b)*(f-e)+e};c._draw=function(a){var b=e.System.getCSSText({x:a.location.x-a.width/2,y:a.location.y-a.height/2,angle:a.angle,scale:a.scale||1,width:a.width,height:a.height,color0:a.color[0],color1:a.color[1],color2:a.color[2],colorMode:a.colorMode,visibility:a.visibility,opacity:a.opacity,zIndex:a.zIndex,borderWidth:a.borderWidth,borderStyle:a.borderStyle,borderColor0:a.borderColor[0],borderColor1:a.borderColor[1],borderColor2:a.borderColor[2],borderRadius:a.borderRadius,
boxShadowOffsetX:a.boxShadowOffset.x,boxShadowOffsetY:a.boxShadowOffset.y,boxShadowBlur:a.boxShadowBlur,boxShadowSpread:a.boxShadowSpread,boxShadowColor0:a.boxShadowColor[0],boxShadowColor1:a.boxShadowColor[1],boxShadowColor2:a.boxShadowColor[2]});a.el.style.cssText=b};c.getCSSText=function(a){return this._stylePosition.replace(/<x>/g,a.x).replace(/<y>/g,a.y).replace(/<angle>/g,a.angle).replace(/<scale>/g,a.scale)+"width: "+a.width+"px; height: "+a.height+"px; background-color: "+a.colorMode+"("+
a.color0+", "+a.color1+("hsl"===a.colorMode?"%":"")+", "+a.color2+("hsl"===a.colorMode?"%":"")+"); border: "+a.borderWidth+"px "+a.borderStyle+" "+a.colorMode+"("+a.borderColor0+", "+a.borderColor1+("hsl"===a.colorMode?"%":"")+", "+a.borderColor2+("hsl"===a.colorMode?"%":"")+"); border-radius: "+a.borderRadius+"%; box-shadow: "+a.boxShadowOffsetX+"px "+a.boxShadowOffsetY+"px "+a.boxShadowBlur+"px "+a.boxShadowSpread+"px "+a.colorMode+"("+a.boxShadowColor0+", "+a.boxShadowColor1+("hsl"===a.colorMode?
"%":"")+", "+a.boxShadowColor2+("hsl"===a.colorMode?"%":"")+"); visibility: "+a.visibility+"; opacity: "+a.opacity+"; z-index: "+a.zIndex+";"};e.System=c;m.prototype.step=function(){};m.prototype.draw=function(){e.System._draw(this)};m.prototype._setBounds=function(){var a=e.System.getWindowSize();this.boundToWindow?(this.bounds=[0,a.width,a.height,0],this.width=a.width,this.height=a.height):this.bounds=[0,this.width,this.height,0];this.location||(this.location=new e.Vector(a.width/2,a.height/2))};
e.World=m;e.System.extend(n,e.Item);n.prototype.init=function(a){this.width=a.width||20;this.height=a.height||20;this.color=a.color||[100,100,100];this.borderRadius=a.borderRadius||0};e.Box=n;e.System.extend(o,e.Item);o.prototype.init=function(a){this.width=a.width||20;this.height=a.height||20;this.color=a.color||[0,0,0];this.colorMode=a.colorMode||"rgb";this.borderRadius=a.borderRadius||100;this.opacity=a.opacity||1;this.boxShadowOffset=a.boxShadowOffset||new e.Vector;this.boxShadowBlur=a.boxShadowBlur||
0;this.boxShadowSpread=a.boxShadowSpread||0;this.boxShadowColor=a.boxShadowColor||[0,0,0]};e.Ball=o})(exports);
/*
FloraJS
Copyright (c) 2013 Vince Allen | vince@vinceallen.com | http://www.vinceallen.com | florajs.com/license
*/
/* Version: 2.0.8 */
/* Build time: June 16, 2013 07:51:47 */body {margin: 0;padding: 0;overflow: hidden;width: 100%; height: 100%;background-color: rgb(0, 0, 0);}
.hasSensor {border-radius: 100%;}
.nose {position: absolute;left: 80%;top: 40%;width: 20%; height: 20%;background: rgb(255, 255, 255);}
.caption, .inputMenu {width: auto;position: absolute;font-family: "Franklin Gothic Medium", "Franklin Gothic", "ITC Franklin Gothic", Arial, sans-serif;color: rgb(0, 0, 0);text-align: center;cursor: default;-webkit-user-select: none;-moz-user-select: none;-o-user-select: none;-ms-user-select: none;user-select: none;}
.captionTop, .inputMenuTop {bottom: 90%;}
.captionBottom, .inputMenuBottom {top: 90%;}
.captionLeft, .inputMenuLeft {left: 0;}
.captionRight, .inputMenuRight {right: 0;}
.captionCenter, .inputMenuCenter {width: 100%;text-align: center;margin: 0 auto;}
/*
FloraJS
Copyright (c) 2013 Vince Allen | vince@vinceallen.com | http://www.vinceallen.com | florajs.com/license
*/
/* Version: 2.0.8 */
/* Build time: June 16, 2013 07:51:47 */var Flora={},exports=Flora;
(function(c){function t(a){this._borders=[];this.id=a||t._idCount;t._idCount++}function l(a){this._gradients=[];this._colors=[];this.id=a||l._idCount;l._idCount++}function E(){}function A(a){var a=a||{},b,d;this.world=a.world||Burner.System.firstWorld();this.position=a.position||"top left";this.text=a.text||"";this.opacity=void 0===a.opacity?0.75:a.opacity;this.color=a.color||[255,255,255];this.borderWidth=a.borderWidth||0;this.borderStyle=a.borderStyle||"none";this.borderColor=a.borderColor||[204,
204,204];this.colorMode="rgb";this.el=document.createElement("div");this.el.id="caption";this.el.className="caption ";d=this.position.split(" ");a=0;for(b=d.length;a<b;a++)this.el.className=this.el.className+"caption"+c.Utils.capitalizeFirstLetter(d[a])+" ";this.el.style.opacity=this.opacity;this.el.style.color=this.colorMode+"("+this.color[0]+", "+this.color[1]+", "+this.color[2]+")";this.el.style.borderWidth=this.borderWidth+"px";this.el.style.borderStyle=this.borderStyle;this.el.style.borderColor=
"string"===typeof this.borderColor?this.borderColor:this.colorMode+"("+this.borderColor[0]+", "+this.borderColor[1]+", "+this.borderColor[2]+")";this.el.appendChild(document.createTextNode(this.text));document.getElementById("caption")&&document.getElementById("caption").parentNode.removeChild(document.getElementById("caption"));this.world.el.appendChild(this.el)}function B(a){var b=this,a=a||{},d,e;this.world=a.world||c.universe.first();this.position=a.position||"top left";this.opacity=void 0===
a.opacity?0.75:a.opacity;this.color=a.color||[255,255,255];this.borderWidth=a.borderWidth||0;this.borderStyle=a.borderStyle||"none";this.borderColor=a.borderColor||[204,204,204];this.colorMode="rgb";this.text=Burner.System.supportedFeatures.touch?c.config.touchMap.stats+"-finger tap = stats | "+c.config.touchMap.pause+"-finger tap = pause | "+c.config.touchMap.reset+"-finger tap = reset":"'"+String.fromCharCode(c.config.keyMap.pause).toLowerCase()+"' = pause | '"+String.fromCharCode(c.config.keyMap.resetSystem).toLowerCase()+
"' = reset | '"+String.fromCharCode(c.config.keyMap.stats).toLowerCase()+"' = stats";this.el=document.createElement("div");this.el.id="inputMenu";this.el.className="inputMenu ";e=this.position.split(" ");a=0;for(d=e.length;a<d;a++)this.el.className=this.el.className+"inputMenu"+c.Utils.capitalizeFirstLetter(e[a])+" ";this.el.style.opacity=this.opacity;this.el.style.color=this.colorMode+"("+this.color[0]+", "+this.color[1]+", "+this.color[2]+")";this.el.style.borderWidth=this.borderWidth+"px";this.el.style.borderStyle=
this.borderStyle;this.el.style.borderColor="string"===typeof this.borderColor?this.borderColor:this.colorMode+"("+this.borderColor[0]+", "+this.borderColor[1]+", "+this.borderColor[2]+")";this.el.appendChild(document.createTextNode(this.text));document.getElementById("inputMenu")&&document.getElementById("inputMenu").parentNode.removeChild(document.getElementById("inputMenu"));Burner.System.supportedFeatures.touch?c.Utils.addEvent(this.el,"touchstart",function(){b.destroy()}):c.Utils.addEvent(this.el,
"mouseup",function(){b.destroy()});this.world.el.appendChild(this.el)}function m(a){a=a||{};a.name=a.name||"Mover";Burner.Item.call(this,a)}function n(a){a=a||{};a.name=a.name||"Agent";c.Mover.call(this,a)}function F(a){a=a||{};a.name=a.name||"Walker";c.Mover.call(this,a)}function u(a){a=a||{};a.name=a.name||"Sensor";c.Mover.call(this,a)}function G(a){a=a||{};a.name=a.name||"Connector";Burner.Item.call(this,a)}function N(a){a=a||{};a.name=a.name||"Point";c.Mover.call(this,a)}function C(a){a=a||{};
a.name=a.name||"Particle";c.Agent.call(this,a)}function v(a){a=a||{};a.name=a.name||"ParticleSystem";c.Agent.call(this,a)}function H(a){a=a||{};a.name=a.name||"Oscillator";Burner.Item.call(this,a)}function I(a){a=a||{};a.name=a.name||"Liquid";c.Agent.call(this,a)}function J(a){a=a||{};a.name=a.name||"Attractor";c.Agent.call(this,a)}function K(a){a=a||{};a.name=a.name||"Repeller";c.Agent.call(this,a)}function L(a){if(!a||!a.type)throw Error("Stimulus: options.type is required.");a.name=a.type.substr(0,
1).toUpperCase()+a.type.toLowerCase().substr(1,a.type.length);c.Agent.call(this,a)}function M(a){a=a||{};a.name=a.name||"FlowField";Burner.Item.call(this,a)}function Q(a){var b,d;if(c.Interface.checkRequiredParams(a,{location:"object",scale:"number",angle:"number",opacity:"number",width:"number",height:"number",colorMode:"string",color:"array"}))return b=document.createElement("div"),d=document.createElement("div"),b.className="flowFieldMarker item",d.className="nose",b.appendChild(d),b.style.cssText=
Burner.System.getCSSText({x:a.location.x-a.width/2,y:a.location.y-a.height/2,width:a.width,height:a.height,opacity:a.opacity,angle:a.angle,scale:1,colorMode:a.colorMode,color0:a.color[0],color1:a.color[1],color2:a.color[2],zIndex:a.zIndex,borderRadius:a.borderRadius}),b}Burner.Classes=Flora;c.config={borderStyles:"none solid dotted dashed double inset outset groove ridge".split(" "),defaultColorList:[{name:"cold",startColor:[88,129,135],endColor:[171,244,255],boxShadowColor:[132,192,201]},{name:"food",
startColor:[186,255,130],endColor:[84,187,0],boxShadowColor:[57,128,0]},{name:"heat",startColor:[255,132,86],endColor:[175,47,0],boxShadowColor:[255,69,0]},{name:"light",startColor:[255,255,255],endColor:[189,148,0],boxShadowColor:[255,200,0]},{name:"oxygen",startColor:[130,136,255],endColor:[49,56,205],boxShadowColor:[60,64,140]}],keyMap:{pause:80,resetSystem:82,stats:83},touchMap:{stats:2,pause:3,reset:4}};c.Interface={checkRequiredParams:function(a,b,d){var e,c,h=!0;for(e in b)if(b.hasOwnProperty(e))try{if("undefined"===
typeof a)throw Error("checkRequiredOptions: No options were passed.");if(!this.checkDataType(this.getDataType(a[e]),b[e].split("|"))||""===a[e])throw h=!1,c=""===a[e]?'checkRequiredOptions: required option "'+e+'" is empty.':"undefined"===typeof a[e]?'checkRequiredOptions: required option "'+e+'" is missing from passed options.':'checkRequiredOptions: passed option "'+e+'" must be type '+b[e]+". Passed as "+this.getDataType(a[e])+".",Error(c);}catch(g){"undefined"!==typeof console&&console.log("ERROR: "+
g.message+(d?" from: "+d:""))}return h},checkDataType:function(a,b){var d,e;d=0;for(e=b.length;d<e;d++)if(a===b[d])return!0;return!1},getDataType:function(a){return"[object Array]"===Object.prototype.toString.call(a)?"array":"[object NodeList]"===Object.prototype.toString.call(a)?"nodeList":typeof a}};c.Utils={extend:function(a,b){function d(){}d.prototype=b.prototype;a.prototype=new d;a.prototype.constructor=a;a._superClass=b},map:function(a,b,d,e,c){return(a-b)/(d-b)*(c-e)+e},getRandomNumber:function(a,
b,d){return d?Math.random()*(b-(a-1))+a:Math.floor(Math.random()*(b-(a-1)))+a},degreesToRadians:function(a){if("undefined"!==typeof a)return 2*Math.PI*(a/360);"undefined"!==typeof console&&console.log("Error: Utils.degreesToRadians is missing degrees param.");return!1},radiansToDegrees:function(a){if("undefined"!==typeof a)return a*(180/Math.PI);"undefined"!==typeof console&&console.log("Error: Utils.radiansToDegrees is missing radians param.");return!1},constrain:function(a,b,d){return a>d?d:a<b?
b:a},clone:function(a){function b(){}b.prototype=a;return new b},addEvent:function(a,b,d){a.addEventListener?this.addEventHandler=function(a,b,d){a.addEventListener(b,d,!1)}:a.attachEvent&&(this.addEventHandler=function(a,b,d){a.attachEvent("on"+b,d)});this.addEventHandler(a,b,d)},log:function(a){"undefined"!==typeof console&&"undefined"!==typeof console.log?(this.log=function(a){console.log(a)},this.log.call(this,a)):this.log=function(){}},getWindowSize:function(){var a={width:!1,height:!1};"undefined"!==
typeof window.innerWidth?a.width=window.innerWidth:"undefined"!==typeof document.documentElement&&"undefined"!==typeof document.documentElement.clientWidth?a.width=document.documentElement.clientWidth:"undefined"!==typeof document.body&&(a.width=document.body.clientWidth);"undefined"!==typeof window.innerHeight?a.height=window.innerHeight:"undefined"!==typeof document.documentElement&&"undefined"!==typeof document.documentElement.clientHeight?a.height=document.documentElement.clientHeight:"undefined"!==
typeof document.body&&(a.height=document.body.clientHeight);return a},getDataType:function(a){return"[object Array]"===Object.prototype.toString.call(a)?"array":"[object NodeList]"===Object.prototype.toString.call(a)?"nodeList":typeof a},capitalizeFirstLetter:function(a){return a.charAt(0).toUpperCase()+a.slice(1)},isInside:function(a,b){return b&&a.location.x+a.width/2>b.location.x-b.width/2&&a.location.x-a.width/2<b.location.x+b.width/2&&a.location.y+a.height/2>b.location.y-b.height/2&&a.location.y-
a.height/2<b.location.y+b.height/2?!0:!1},mouseIsInsideWorld:function(a){var b=Burner.System.mouse,d=b.location.x,b=b.location.y,e=a.el.offsetLeft,c=a.el.offsetTop;return a&&d>e&&d<e+a.bounds[1]&&b>c&&b<c+a.bounds[2]?!0:!1}};var r={random:function(){return 0.1}};void 0===r&&(r=Math);var j,s=[];for(j=0;256>j;j+=1)s[j]=Math.floor(256*r.random());r=[];for(j=0;512>j;j+=1)r[j]=s[j&255];c.SimplexNoise={grad3:[[1,1,0],[-1,1,0],[1,-1,0],[-1,-1,0],[1,0,1],[-1,0,1],[1,0,-1],[-1,0,-1],[0,1,1],[0,-1,1],[0,1,
-1],[0,-1,-1]],p:s,perm:r,simplex:[[0,1,2,3],[0,1,3,2],[0,0,0,0],[0,2,3,1],[0,0,0,0],[0,0,0,0],[0,0,0,0],[1,2,3,0],[0,2,1,3],[0,0,0,0],[0,3,1,2],[0,3,2,1],[0,0,0,0],[0,0,0,0],[0,0,0,0],[1,3,2,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[1,2,0,3],[0,0,0,0],[1,3,0,2],[0,0,0,0],[0,0,0,0],[0,0,0,0],[2,3,0,1],[2,3,1,0],[1,0,2,3],[1,0,3,2],[0,0,0,0],[0,0,0,0],[0,0,0,0],[2,0,3,1],[0,0,0,0],[2,1,3,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,
0],[0,0,0,0],[2,0,1,3],[0,0,0,0],[0,0,0,0],[0,0,0,0],[3,0,1,2],[3,0,2,1],[0,0,0,0],[3,1,2,0],[2,1,0,3],[0,0,0,0],[0,0,0,0],[0,0,0,0],[3,1,0,2],[0,0,0,0],[3,2,0,1],[3,2,1,0]],dot:function(a,b,d){return a[0]*b+a[1]*d},noise:function(a,b){var d,c,f;f=0.5*(Math.sqrt(3)-1);f*=a+b;var h=Math.floor(a+f),g=Math.floor(b+f),i=(3-Math.sqrt(3))/6;f=(h+g)*i;d=a-(h-f);var k=b-(g-f),y,p;d>k?(y=1,p=0):(y=0,p=1);c=d-y+i;var o=k-p+i;f=d-1+2*i;var i=k-1+2*i,j=h&255,g=g&255,h=this.perm[j+this.perm[g]]%12;y=this.perm[j+
y+this.perm[g+p]]%12;p=this.perm[j+1+this.perm[g+1]]%12;g=0.5-d*d-k*k;0>g?d=0:(g*=g,d=g*g*this.dot(this.grad3[h],d,k));k=0.5-c*c-o*o;0>k?c=0:(k*=k,c=k*k*this.dot(this.grad3[y],c,o));o=0.5-f*f-i*i;0>o?f=0:(o*=o,f=o*o*this.dot(this.grad3[p],f,i));return 70*(d+c+f)},noise3d:function(a,b,d){var c,f,h,g=(a+b+d)*(1/3),i=Math.floor(a+g),k=Math.floor(b+g),j=Math.floor(d+g),g=1/6;h=(i+k+j)*g;c=a-(i-h);f=b-(k-h);var p=d-(j-h),o,m,x,l,q,n;c>=f?f>=p?(o=1,x=m=0,q=l=1,n=0):(c>=p?(o=1,x=m=0):(m=o=0,x=1),l=1,q=0,
n=1):f<p?(m=o=0,x=1,l=0,n=q=1):c<p?(o=0,m=1,l=x=0,n=q=1):(o=0,m=1,x=0,q=l=1,n=0);var w=c-o+g,r=f-m+g,t=p-x+g;h=c-l+2*g;var a=f-q+2*g,u=p-n+2*g,d=c-1+3*g,b=f-1+3*g,g=p-1+3*g,i=i&255,s=k&255,v=j&255,k=this.perm[i+this.perm[s+this.perm[v]]]%12,j=this.perm[i+o+this.perm[s+m+this.perm[v+x]]]%12;l=this.perm[i+l+this.perm[s+q+this.perm[v+n]]]%12;i=this.perm[i+1+this.perm[s+1+this.perm[v+1]]]%12;q=0.6-c*c-f*f-p*p;0>q?c=0:(q*=q,c=q*q*this.dot(this.grad3[k],c,f,p));f=0.6-w*w-r*r-t*t;0>f?f=0:(f*=f,f=f*f*this.dot(this.grad3[j],
w,r,t));w=0.6-h*h-a*a-u*u;0>w?h=0:(w*=w,h=w*w*this.dot(this.grad3[l],h,a,u));a=0.6-d*d-b*b-g*g;0>a?d=0:(a*=a,d=a*a*this.dot(this.grad3[i],d,b,g));return 32*(c+f+h+d)}};t._idCount=0;t.prototype.name="BorderPalette";t.prototype.addBorder=function(a){var b,d;if(c.Interface.checkRequiredParams(a,{min:"number",max:"number",style:"string"})){d=c.Utils.getRandomNumber(a.min,a.max);for(b=0;b<d;b++)this._borders.push(a.style)}return this};t.prototype.getBorder=function(){if(0<this._borders.length)return this._borders[c.Utils.getRandomNumber(0,
this._borders.length-1)];throw Error("BorderPalette.getBorder: You must add borders via addBorder() before using getBorder().");};c.BorderPalette=t;l._idCount=0;l.prototype.name="ColorPalette";l.prototype.addColor=function(a){var b,d;if(c.Interface.checkRequiredParams(a,{min:"number",max:"number",startColor:"array",endColor:"array"})){b=c.Utils.getRandomNumber(a.min,a.max);d=l._createColorRange(a.startColor,a.endColor,255);for(a=0;a<b;a++)this._colors.push(d[c.Utils.getRandomNumber(0,d.length-1)])}return this};
l.prototype.createGradient=function(a){if(c.Interface.checkRequiredParams(a,{startColor:"array",endColor:"array"}))if(this.startColor=a.startColor,this.endColor=a.endColor,this.totalColors=a.totalColors||255,0<this.totalColors)this._gradients.push(l._createColorRange(this.startColor,this.endColor,this.totalColors));else throw Error("ColorPalette: total colors must be greater than zero.");};l.prototype.getColor=function(){if(0<this._colors.length)return this._colors[c.Utils.getRandomNumber(0,this._colors.length-
1)];throw Error("ColorPalette.getColor: You must add colors via addColor() before using getColor().");};l.prototype.createSampleStrip=function(a){var b,d,c;b=0;for(d=this._colors.length;b<d;b++)c=document.createElement("div"),c.className="color-sample-strip",c.style.background="rgb("+this._colors[b].toString()+")",a.appendChild(c)};l._createColorRange=function(a,b,d){var c,f=[],h=a[0],g=a[1],a=a[2],i=b[1];c=b[2];var k,j,p,o,b=b[0]-h,i=i-g;k=c-a;for(c=0;c<d;c++)j=parseInt(b*c/d,10)+h,p=parseInt(i*
c/d,10)+g,o=parseInt(k*c/d,10)+a,f.push([j,p,o]);return f};c.ColorPalette=l;E.prototype.addColor=function(a){c.Interface.checkRequiredParams(a,{name:"string",startColor:"array",endColor:"array"})&&(this[a.name]={startColor:a.startColor,endColor:a.endColor});return this};E.prototype.name="ColorTable";E.prototype.getColor=function(a,b,d){var e,f;if("string"===c.Interface.getDataType(a))if(this[a]){a=this[a];b&&(e=a.startColor);d&&(f=a.endColor);if(e&&f||!e&&!f)return{startColor:a.startColor,endColor:a.endColor};
if(e)return e;if(f)return f}else throw Error("ColorTable: "+a+" does not exist. Add colors to the ColorTable via addColor().");else throw Error("ColorTable: You must pass a name (string) for the color entry in the table.");};c.ColorTable=E;A.prototype.name="Caption";A.prototype.reset=function(){};A.prototype.init=function(){};A.prototype.destroy=function(){var a=this.el.id;this.el.parentNode.removeChild(this.el);if(!document.getElementById(a))return!0};c.Caption=A;B.prototype.name="InputMenu";B.prototype.reset=
function(){};B.prototype.init=function(){};B.prototype.destroy=function(){var a=this.el.id;this.el.parentNode.removeChild(this.el);if(!document.getElementById(a))return!0};c.InputMenu=B;c.Utils.extend(m,Burner.Item);m.prototype.init=function(a){this.width=void 0===a.width?20:a.width;this.height=void 0===a.height?20:a.height;this.color=a.color||[255,255,255];this.motorSpeed=a.motorSpeed||0;this.angle=a.angle||0;this.pointToDirection=void 0===a.pointToDirection?!0:a.pointToDirection;this.draggable=
!!a.draggable;this.parent=a.parent||null;this.pointToParentDirection=!!a.pointToParentDirection;this.offsetDistance=void 0===a.offsetDistance?30:a.offsetDistance;this.offsetAngle=a.offsetAngle||0;this.beforeStep=a.beforeStep||null;this.afterStep=a.afterStep||null;this.isPressed=this.isMouseOut=!1;var b=this,a=function(a){b.mouseover(a,b)},d,e=this;d=function(a){e.mousedown(a,e)};var f,h=this;f=function(a){h.mousemove(a,h)};var g,i=this;g=function(a){i.mouseup(a,i)};var k,j=this;k=function(a){j.mouseout(a,
j)};this.draggable&&(c.Utils.addEvent(this.el,"mouseover",a),c.Utils.addEvent(this.el,"mousedown",d),c.Utils.addEvent(this.el,"mousemove",f),c.Utils.addEvent(this.el,"mouseup",g),c.Utils.addEvent(this.el,"mouseout",k))};m.prototype.mouseover=function(){this.isMouseOut=!1;clearInterval(this.mouseOutInterval)};m.prototype.mousedown=function(a){var b,d=a.target||a.srcElement;a.changedTouches&&(b=a.changedTouches[0]);a.pageX&&a.pageY?(this.offsetX=a.pageX-d.offsetLeft,this.offsetY=a.pageY-d.offsetTop):
a.clientX&&a.clientY?(this.offsetX=a.clientX-d.offsetLeft,this.offsetY=a.clientY-d.offsetTop):b&&(this.offsetX=b.pageX-d.offsetLeft,this.offsetY=b.pageY-d.offsetTop);this.isPressed=!0;this.isMouseOut=!1};m.prototype.mousemove=function(a){var b,d,e;this.isPressed&&(this.isMouseOut=!1,a.changedTouches&&(e=a.changedTouches[0]),a.pageX&&a.pageY?(b=a.pageX-this.world.el.offsetLeft,d=a.pageY-this.world.el.offsetTop):a.clientX&&a.clientY?(b=a.clientX-this.world.el.offsetLeft,d=a.clientY-this.world.el.offsetTop):
e&&(b=e.pageX-this.world.el.offsetLeft,d=e.pageY-this.world.el.offsetTop),c.Utils.mouseIsInsideWorld(this.world)?this.location=new Burner.Vector(b,d):this.isPressed=!1)};m.prototype.mouseup=function(){this.isPressed=!1};m.prototype.mouseout=function(a,b){var d=Burner.System.mouse,c,f;b.isPressed&&(b.isMouseOut=!0,b.mouseOutInterval=setInterval(function(){b.isPressed&&b.isMouseOut&&(c=d.location.x-b.world.el.offsetLeft,f=d.location.y-b.world.el.offsetTop,b.location=new Burner.Vector(c,f))},16))};m.prototype.step=
function(){var a,b,d;this.beforeStep&&this.beforeStep.apply(this);if(!this.isStatic&&!this.isPressed&&(this.world.c&&(a=c.Utils.clone(this.velocity),a.mult(-1),a.normalize(),a.mult(this.world.c),this.applyForce(a)),this.applyForce(this.world.gravity),this.applyForces&&this.applyForces(),this.velocity.add(this.acceleration),this.velocity.limit(this.maxSpeed,this.minSpeed),this.location.add(this.velocity),this.pointToDirection&&0.1<this.velocity.mag()))this.angle=c.Utils.radiansToDegrees(Math.atan2(this.velocity.y,
this.velocity.x));this.controlCamera&&this._checkCameraEdges();this.checkWorldEdges&&this._checkWorldEdges();this.parent&&(this.offsetDistance?(b=this.offsetDistance,d=c.Utils.degreesToRadians(this.parent.angle+this.offsetAngle),a=b*Math.cos(d),b*=Math.sin(d),this.location.x=this.parent.location.x,this.location.y=this.parent.location.y,this.location.add(new Burner.Vector(a,b)),this.pointToParentDirection&&(this.angle=c.Utils.radiansToDegrees(Math.atan2(this.parent.velocity.y,this.parent.velocity.x)))):
this.location=this.parent.location);this.acceleration.mult(0);this.life<this.lifespan?this.life+=1:-1!==this.lifespan&&Burner.System.destroyItem(this);this.afterStep&&this.afterStep.apply(this)};m.prototype._seek=function(a){var b=this.world,a=Burner.Vector.VectorSub(a.location,this.location),d=a.mag();a.normalize();d<b.bounds[1]/2?(b=c.Utils.map(d,0,b.bounds[1]/2,0,this.maxSpeed),a.mult(b)):a.mult(this.maxSpeed);a.sub(this.velocity);a.limit(this.maxSteeringForce);return a};m.prototype._checkAvoidEdges=
function(){var a,b;this.location.x<this.avoidWorldEdgesStrength?a=this.maxSpeed:this.location.x>this.world.bounds[1]-this.avoidWorldEdgesStrength&&(a=-this.maxSpeed);a&&(b=new Burner.Vector(a,this.velocity.y),b.sub(this.velocity),b.limit(this.maxSteeringForce),this.applyForce(b));this.location.y<this.avoidWorldEdgesStrength?a=this.maxSpeed:this.location.y>this.world.bounds[2]-this.avoidWorldEdgesStrength&&(a=-this.maxSpeed);a&&(b=new Burner.Vector(this.velocity.x,a),b.sub(this.velocity),b.limit(this.maxSteeringForce),
this.applyForce(b))};m.prototype.drag=function(a){var b=this.velocity.mag(),a=-1*a.c*b*b,b=c.Utils.clone(this.velocity);b.normalize();b.mult(a);return b};m.prototype.attract=function(a){var b=Burner.Vector.VectorSub(a.location,this.location),d;d=b.mag();d=c.Utils.constrain(d,this.width*this.height,a.width*a.height);b.normalize();b.mult(a.G*a.mass*this.mass/(d*d));return b};m.prototype.isInside=function(a){return a&&this.location.x+this.width/2>a.location.x-a.width/2&&this.location.x-this.width/2<
a.location.x+a.width/2&&this.location.y+this.height/2>a.location.y-a.height/2&&this.location.y-this.height/2<a.location.y+a.height/2?!0:!1};c.Mover=m;c.Utils.extend(n,c.Mover);n.prototype.init=function(a){a=a||{};n._superClass.prototype.init.call(this,a);this.followMouse=!!a.followMouse;this.maxSteeringForce=void 0===a.maxSteeringForce?10:a.maxSteeringForce;this.seekTarget=a.seekTarget||null;this.flocking=!!a.flocking;this.desiredSeparation=void 0===a.desiredSeparation?2*this.width:a.desiredSeparation;
this.separateStrength=void 0===a.separateStrength?0.3:a.separateStrength;this.alignStrength=void 0===a.alignStrength?0.2:a.alignStrength;this.cohesionStrength=void 0===a.cohesionStrength?0.1:a.cohesionStrength;this.flowField=a.flowField||null;this.sensors=a.sensors||[];this.color=a.color||[197,177,115];this.borderWidth=a.borderWidth||0;this.borderStyle=a.borderStyle||"none";this.borderColor=a.borderColor||"transparent";this.borderRadius=a.borderRadius||this.sensors.length?100:0;this.separateSumForceVector=
new Burner.Vector;this.alignSumForceVector=new Burner.Vector;this.cohesionSumForceVector=new Burner.Vector;this.followTargetVector=new Burner.Vector;this.followDesiredVelocity=new Burner.Vector};n.prototype.applyForces=function(){var a,b,d,e,f,h,g;e=Burner.System._caches.Liquid;g=Burner.System._caches.Attractor;f=Burner.System._caches.Repeller;if(e&&0<e.list.length){a=0;for(b=e.list.length;a<b;a+=1)this.id!==e.list[a].id&&c.Utils.isInside(this,e.list[a])&&this.applyForce(this.drag(e.list[a]))}if(g&&
0<g.list.length){a=0;for(b=g.list.length;a<b;a+=1)this.id!==g.list[a].id&&this.applyForce(this.attract(g.list[a]))}if(f&&0<f.list.length){a=0;for(b=f.list.length;a<b;a+=1)this.id!==f.list[a].id&&this.applyForce(this.attract(f.list[a]))}if(0<this.sensors.length){a=0;for(b=this.sensors.length;a<b;a+=1)if(e=this.sensors[a],f=e.offsetDistance,h=c.Utils.degreesToRadians(this.angle+e.offsetAngle),g=f*Math.cos(h),f*=Math.sin(h),e.location.x=this.location.x,e.location.y=this.location.y,e.location.add(new Burner.Vector(g,
f)),a&&(e.borderStyle="none"),e.activated)this.applyForce(e.getActivationForce(this)),d=!0}!d&&this.motorSpeed&&(a=c.Utils.clone(this.velocity),a.normalize(),this.velocity.mag()>this.motorSpeed?a.mult(-this.motorSpeed):a.mult(this.motorSpeed),this.applyForce(a));this.followMouse&&!Burner.System.supportedFeatures.touch&&(a={location:new Burner.Vector(Burner.System.mouse.location.x,Burner.System.mouse.location.y)},this.applyForce(this._seek(a)));this.seekTarget&&this.applyForce(this._seek(this.seekTarget));
this.flowField&&(b=this.flowField.resolution,a=Math.floor(this.location.x/b),b=Math.floor(this.location.y/b),this.flowField.field[a]&&((a=this.flowField.field[a][b])?(this.followTargetVector.x=a.x,this.followTargetVector.y=a.y):(this.followTargetVector.x=this.location.x,this.followTargetVector.y=this.location.y),a={location:this.followTargetVector},this.applyForce(this.follow(a))));this.flocking&&this.flock(Burner.System.getAllItemsByName("Agent"));return this.acceleration};n.prototype.follow=function(a){this.followDesiredVelocity.x=
a.location.x;this.followDesiredVelocity.y=a.location.y;this.followDesiredVelocity.mult(this.maxSpeed);this.followDesiredVelocity.sub(this.velocity);this.followDesiredVelocity.limit(this.maxSteeringForce);return this.followDesiredVelocity};n.prototype.flock=function(a){this.applyForce(this.separate(a).mult(this.separateStrength));this.applyForce(this.align(a).mult(this.alignStrength));this.applyForce(this.cohesion(a).mult(this.cohesionStrength));return this.acceleration};n.prototype.separate=function(a){var b,
c,e,f,h,g=0;this.separateSumForceVector.x=0;this.separateSumForceVector.y=0;h=this.separateSumForceVector;b=0;for(c=a.length;b<c;b+=1)e=a[b],this.className===e.className&&this.id!==e.id&&(f=this.location.distance(e.location),0<f&&f<this.desiredSeparation&&(e=Burner.Vector.VectorSub(this.location,e.location),e.normalize(),e.div(f),h.add(e),g+=1));return 0<g?(h.div(g),h.normalize(),h.mult(this.maxSpeed),h.sub(this.velocity),h.limit(this.maxSteeringForce),h):new Burner.Vector};n.prototype.align=function(a){var b,
c,e,f,h=2*this.width,g,i=0;this.alignSumForceVector.x=0;this.alignSumForceVector.y=0;g=this.alignSumForceVector;b=0;for(c=a.length;b<c;b+=1)e=a[b],f=this.location.distance(e.location),0<f&&f<h&&(this.className===e.className&&this.id!==e.id)&&(g.add(e.velocity),i+=1);return 0<i?(g.div(i),g.normalize(),g.mult(this.maxSpeed),g.sub(this.velocity),g.limit(this.maxSteeringForce),g):new Burner.Vector};n.prototype.cohesion=function(a){var b,c,e,f,h,g=0;this.cohesionSumForceVector.x=0;this.cohesionSumForceVector.y=
0;h=this.cohesionSumForceVector;b=0;for(c=a.length;b<c;b+=1)e=a[b],f=this.location.distance(e.location),0<f&&10>f&&(this.className===e.className&&this.id!==e.id)&&(h.add(e.location),g+=1);return 0<g?(h.div(g),h.sub(this.location),h.normalize(),h.mult(this.maxSpeed),h.sub(this.velocity),h.limit(this.maxSteeringForce),h):new Burner.Vector};n.prototype.getLocation=function(a){if(a){if("x"===a)return this.location.x;if("y"===a)return this.location.y}else return new Burner.Vector(this.location.x,this.location.y)};
n.prototype.getVelocity=function(a){if(a){if("x"===a)return this.velocity.x;if("y"===a)return this.velocity.y}else return new Burner.Vector(this.location.x,this.location.y)};c.Agent=n;c.Utils.extend(F,c.Mover);F.prototype.init=function(a){a=a||{};this.width=void 0===a.width?10:a.width;this.height=void 0===a.height?10:a.height;this.perlin=void 0===a.perlin?!0:a.perlin;this.remainsOnScreen=!!a.remainsOnScreen;this.perlinSpeed=void 0===a.perlinSpeed?0.0050:a.perlinSpeed;this.perlinTime=a.perlinTime||
0;this.perlinAccelLow=void 0===a.perlinAccelLow?-0.075:a.perlinAccelLow;this.perlinAccelHigh=void 0===a.perlinAccelHigh?0.075:a.perlinAccelHigh;this.offsetX=void 0===a.offsetX?1E4*Math.random():a.offsetX;this.offsetY=void 0===a.offsetY?1E4*Math.random():a.offsetY;this.random=!!a.random;this.randomRadius=void 0===a.randomRadius?100:a.randomRadius;this.color=a.color||[255,150,50];this.borderWidth=void 0===a.borderWidth?2:a.borderWidth;this.borderStyle=a.borderStyle||"solid";this.borderColor=a.borderColor||
[255,255,255];this.borderRadius=void 0===a.borderRadius?100:a.borderRadius;this.avoidWorldEdges=!!a.avoidWorldEdges;this.avoidWorldEdgesStrength=void 0===a.avoidWorldEdgesStrength?50:a.avoidWorldEdgesStrength};F.prototype.applyForces=function(){this.perlin?(this.perlinTime+=this.perlinSpeed,this.remainsOnScreen?(this.acceleration=new Burner.Vector,this.velocity=new Burner.Vector,this.location.x=c.Utils.map(c.SimplexNoise.noise(this.perlinTime+this.offsetX,0,0.1),-1,1,0,this.world.bounds[1]),this.location.y=
c.Utils.map(c.SimplexNoise.noise(0,this.perlinTime+this.offsetY,0.1),-1,1,0,this.world.bounds[2])):(this.acceleration.x=c.Utils.map(c.SimplexNoise.noise(this.perlinTime+this.offsetX,0,0.1),-1,1,this.perlinAccelLow,this.perlinAccelHigh),this.acceleration.y=c.Utils.map(c.SimplexNoise.noise(0,this.perlinTime+this.offsetY,0.1),-1,1,this.perlinAccelLow,this.perlinAccelHigh))):this.random&&(this.seekTarget={location:Burner.Vector.VectorAdd(this.location,new Burner.Vector(c.Utils.getRandomNumber(-this.randomRadius,
this.randomRadius),c.Utils.getRandomNumber(-this.randomRadius,this.randomRadius)))},this.applyForce(this._seek(this.seekTarget)));this.avoidWorldEdges&&this._checkAvoidEdges()};c.Walker=F;c.Utils.extend(u,c.Mover);u.prototype.init=function(a){a=a||{};u._superClass.prototype.init.call(this,a);this.type=a.type||"";this.behavior=a.behavior||"LOVE";this.sensitivity=void 0===a.sensitivity?2:a.sensitivity;this.width=void 0===a.width?7:a.width;this.height=void 0===a.height?7:a.height;this.offsetDistance=
void 0===a.offsetDistance?30:a.offsetDistance;this.offsetAngle=a.offsetAngle||0;this.opacity=void 0===a.opacity?0.75:a.opacity;this.target=a.target||null;this.activated=!!a.activated;this.activatedColor=a.activatedColor||[255,255,255];this.borderRadius=void 0===a.borderRadius?100:a.borderRadius;this.borderWidth=void 0===a.borderWidth?2:a.borderWidth;this.borderStyle="solid";this.borderColor=[255,255,255]};u.prototype.step=function(){var a=!1,b,c,e=Burner.System._caches.Heat||{list:[]},f=Burner.System._caches.Cold||
{list:[]},h=Burner.System._caches.Predators||{list:[]},g=Burner.System._caches.Light||{list:[]},i=Burner.System._caches.Oxygen||{list:[]},k=Burner.System._caches.Food||{list:[]};if("heat"===this.type&&e.list&&0<e.list.length){b=0;for(c=e.list.length;b<c;b++)this.isInside(this,e.list[b],this.sensitivity)&&(this.target=e.list[b],a=this.activated=!0)}else if("cold"===this.type&&f.list&&0<f.list.length){b=0;for(c=f.list.length;b<c;b++)this.isInside(this,f.list[b],this.sensitivity)&&(this.target=f.list[b],
a=this.activated=!0)}else if("predator"===this.type&&h.list&&0<h.list.length){b=0;for(c=h.list.length;b<c;b+=1)this.isInside(this,h.list[b],this.sensitivity)&&(this.target=h.list[b],a=this.activated=!0)}else if("light"===this.type&&g.list&&0<g.list.length){b=0;for(c=g.list.length;b<c;b++)g.lookup[g.list[b].id]&&this.isInside(this,g.list[b],this.sensitivity)&&(this.target=g.list[b],a=this.activated=!0)}else if("oxygen"===this.type&&i.list&&0<i.list.length){b=0;for(c=i.list.length;b<c;b+=1)i.lookup[i.list[b].id]&&
this.isInside(this,i.list[b],this.sensitivity)&&(this.target=i.list[b],a=this.activated=!0)}else if("food"===this.type&&k.list&&0<k.list.length){b=0;for(c=k.list.length;b<c;b+=1)k.lookup[k.list[b].id]&&this.isInside(this,k.list[b],this.sensitivity)&&(this.target=k.list[b],a=this.activated=!0)}a?this.color=this.activatedColor:(this.target=null,this.activated=!1,this.color="transparent");this.afterStep&&this.afterStep.apply(this)};u.prototype.getActivationForce=function(a){var b,c;switch(this.behavior){case "AGGRESSIVE":return c=
Burner.Vector.VectorSub(this.target.location,this.location),b=c.mag(),c.normalize(),b/=a.maxSpeed,c.mult(b),c.sub(a.velocity),c.limit(a.maxSteeringForce),c;case "COWARD":return c=Burner.Vector.VectorSub(this.target.location,this.location),b=c.mag(),c.normalize(),b/=a.maxSpeed,c.mult(-b),c.sub(a.velocity),c.limit(a.maxSteeringForce),c;case "LIKES":return c=Burner.Vector.VectorSub(this.target.location,this.location),b=c.mag(),c.normalize(),b/=a.maxSpeed,c.mult(b),b=Burner.Vector.VectorSub(c,a.velocity),
b.limit(a.maxSteeringForce),b;case "LOVES":c=Burner.Vector.VectorSub(this.target.location,this.location);b=c.mag();c.normalize();if(b>this.width)return b/=a.maxSpeed,c.mult(b),b=Burner.Vector.VectorSub(c,a.velocity),b.limit(a.maxSteeringForce),b;a.velocity=new Burner.Vector;a.acceleration=new Burner.Vector;return new Burner.Vector;case "EXPLORER":return c=Burner.Vector.VectorSub(this.target.location,this.location),b=c.mag(),c.normalize(),b/=a.maxSpeed,c.mult(-b),b=Burner.Vector.VectorSub(c,a.velocity),
b.limit(0.05*a.maxSteeringForce),b;case "ACCELERATE":return b=a.velocity.clone(),b.normalize(),b.mult(a.minSpeed);case "DECELERATE":return b=a.velocity.clone(),b.normalize(),b.mult(-a.minSpeed);default:return new Burner.Vector}};u.prototype.isInside=function(a,b,c){return a.location.x+a.width/2>b.location.x-b.width/2-c*b.width&&a.location.x-a.width/2<b.location.x+b.width/2+c*b.width&&a.location.y+a.height/2>b.location.y-b.height/2-c*b.height&&a.location.y-a.height/2<b.location.y+b.height/2+c*b.height?
!0:!1};c.Sensor=u;c.Utils.extend(G,Burner.Item);G.prototype.init=function(a){if(!a||!a.parentA||!a.parentB)throw Error("Connector: both parentA and parentB are required.");this.parentA=a.parentA;this.parentB=a.parentB;this.opacity=void 0===a.opacity?1:a.opacity;this.zIndex=a.zIndex||0;this.borderWidth=1;this.borderRadius=0;this.borderStyle="dotted";this.borderColor=void 0===a.borderColor?[150,150,150]:a.borderColor;this.height=this.width=0;this.color="transparent"};G.prototype.step=function(){var a=
this.parentA.location,b=this.parentB.location;this.width=Math.floor(Burner.Vector.VectorSub(this.parentA.location,this.parentB.location).mag());this.location=Burner.Vector.VectorAdd(this.parentA.location,this.parentB.location).div(2);this.angle=c.Utils.radiansToDegrees(Math.atan2(b.y-a.y,b.x-a.x))};c.Connector=G;c.Utils.extend(N,c.Mover);N.prototype.init=function(a){a=a||{};this.width=void 0===a.width?10:a.width;this.height=void 0===a.height?10:a.height;this.opacity=void 0===a.opacity?1:a.opacity;
this.isStatic=!1===a.isStatic?!1:a.isStatic||!0;this.zIndex=void 0===a.zIndex?1:a.zIndex;this.color=a.color||[200,200,200];this.borderRadius=void 0===a.borderRadius?100:a.borderRadius;this.borderWidth=void 0===a.borderWidth?2:a.borderWidth;this.borderStyle=a.borderStyle||"solid";this.borderColor=a.borderColor||[60,60,60]};c.Point=N;c.Utils.extend(C,c.Agent);C.prototype.init=function(a){a=a||{};C._superClass.prototype.init.call(this,a);this.width=void 0===a.width?20:a.width;this.height=void 0===a.height?
20:a.height;this.lifespan=void 0===a.lifespan?50:a.lifespan;this.life=a.life||0;this.fade=void 0===a.fade?!0:!1;this.shrink=void 0===a.shrink?!0:!1;this.checkWorldEdges=!!a.checkWorldEdges;this.maxSpeed=void 0===a.maxSpeed?4:0;this.zIndex=void 0===a.zIndex?1:0;this.color=a.color||[200,200,200];this.borderWidth=void 0===a.borderWidth?this.width/4:0;this.borderStyle=a.borderStyle||"none";this.borderColor=a.borderColor||"transparent";this.borderRadius=void 0===a.borderRadius?100:0;this.boxShadowSpread=
void 0===a.boxShadowSpread?this.width/4:0;this.boxShadowColor=a.boxShadowColor||"transparent";a.acceleration||(this.acceleration=new Burner.Vector(1,1),this.acceleration.normalize(),this.acceleration.mult(this.maxSpeed?this.maxSpeed:3),this.acceleration.rotate(c.Utils.getRandomNumber(0,2*Math.PI,!0)));a.velocity||(this.velocity=new Burner.Vector);this.initWidth=this.width;this.initHeight=this.height};C.prototype.step=function(){var a;this.world.c&&(a=c.Utils.clone(this.velocity),a.mult(-1),a.normalize(),
a.mult(this.world.c),this.applyForce(a));this.applyForce(this.world.gravity);this.applyForces&&this.applyForces();this.checkEdges&&this._checkWorldEdges();this.velocity.add(this.acceleration);this.maxSpeed&&this.velocity.limit(this.maxSpeed);this.minSpeed&&this.velocity.limit(null,this.minSpeed);this.location.add(this.velocity);this.fade&&(this.opacity=c.Utils.map(this.life,0,this.lifespan,1,0));this.shrink&&(this.width=c.Utils.map(this.life,0,this.lifespan,this.initWidth,0),this.height=c.Utils.map(this.life,
0,this.lifespan,this.initHeight,0));this.acceleration.mult(0);this.life<this.lifespan?this.life+=1:-1!==this.lifespan&&Burner.System.destroyItem(this)};c.Particle=C;c.Utils.extend(v,c.Agent);v.prototype.init=function(a){a=a||{};v._superClass.prototype.init.call(this,a);this.isStatic=void 0===a.isStatic?!0:a.isStatic;this.lifespan=void 0===a.lifespan?-1:a.lifespan;this.life=a.life||0;this.width=a.width||0;this.height=a.height||0;this.burst=void 0===a.burst?1:a.burst;this.burstRate=void 0===a.burstRate?
4:a.burstRate;this.emitRadius=void 0===a.emitRadius?3:a.emitRadius;this.startColor=a.startColor||[100,20,20];this.endColor=a.endColor||[255,0,0];this.particleOptions=a.particleOptions||{width:15,height:15,lifespan:50,borderRadius:100,checkEdges:!1,acceleration:null,velocity:null,location:null,maxSpeed:3,fade:!0};this.borderWidth=a.borderWidth||0;this.borderStyle=a.borderStyle||"none";this.borderColor=a.borderColor||"transparent";this.borderRadius=a.borderRadius||0;this.clock=0;this.particleOptions.acceleration&&
(this.initParticleAcceleration=new Burner.Vector(this.particleOptions.acceleration.x,this.particleOptions.acceleration.y));var b=new c.ColorPalette;b.addColor({min:12,max:24,startColor:this.startColor,endColor:this.endColor});this.beforeStep=function(){var a,e,f=this.initParticleAcceleration;if(this.life<this.lifespan)this.life=this.life+1;else if(this.lifespan!==-1){Burner.System.destroyItem(this);return}if(this.clock%this.burstRate===0){a=this.getLocation();e=new Burner.Vector(1,1);e.normalize();
e.mult(this.emitRadius);e.rotate(c.Utils.getRandomNumber(0,Math.PI*2,true));a.add(e);for(e=0;e<this.burst;e++){this.particleOptions.world=this.world;this.particleOptions.life=0;this.particleOptions.color=b.getColor();this.particleOptions.borderStyle="solid";this.particleOptions.borderColor=b.getColor();this.particleOptions.boxShadowColor=b.getColor();if(f)this.particleOptions.acceleration=new Burner.Vector(f.x,f.y);this.particleOptions.location=v.getParticleLocation(a);Burner.System.add("Particle",
this.particleOptions)}}this.clock++}};v.getParticleLocation=function(a){return new Burner.Vector(a.x,a.y)};c.ParticleSystem=v;c.Utils.extend(H,Burner.Item);H.prototype.init=function(a){a=a||{};this.initialLocation=a.initialLocation||new Burner.Vector(this.world.bounds[1]/2,this.world.bounds[2]/2);this.lastLocation=new Burner.Vector;this.amplitude=a.amplitude||new Burner.Vector(this.world.bounds[1]/2-this.width,this.world.bounds[2]/2-this.height);this.acceleration=a.acceleration||new Burner.Vector(0.01,
0);this.aVelocity=a.aVelocity||new Burner.Vector;this.isStatic=!!a.isStatic;this.isPerlin=!!a.isPerlin;this.perlinSpeed=void 0===a.perlinSpeed?0.0050:a.perlinSpeed;this.perlinTime=a.perlinTime||0;this.perlinAccelLow=void 0===a.perlinAccelLow?-2:a.perlinAccelLow;this.perlinAccelHigh=void 0===a.perlinAccelHigh?2:a.perlinAccelHigh;this.perlinOffsetX=void 0===a.perlinOffsetX?1E4*Math.random():a.perlinOffsetX;this.perlinOffsetY=void 0===a.perlinOffsetY?1E4*Math.random():a.perlinOffsetY;this.width=void 0===
a.width?20:a.width;this.height=void 0===a.height?20:a.height;this.color=a.color||[200,100,0];this.borderWidth=a.borderWidth||0;this.borderStyle=a.borderStyle||"solid";this.borderColor=a.borderColor||[255,150,50];this.borderRadius=void 0===a.borderRadius?100:a.borderRadius;this.boxShadowSpread=a.boxShadowSpread||0;this.boxShadowColor=a.boxShadowColor||[200,100,0]};H.prototype.step=function(){var a=this.world,b;this.beforeStep&&this.beforeStep.apply(this);if(!this.isStatic&&!this.isPressed&&(this.isPerlin?
(this.perlinTime+=this.perlinSpeed,this.aVelocity.x=c.Utils.map(c.SimplexNoise.noise(this.perlinTime+this.perlinOffsetX,0,0.1),-1,1,this.perlinAccelLow,this.perlinAccelHigh),this.aVelocity.y=c.Utils.map(c.SimplexNoise.noise(0,this.perlinTime+this.perlinOffsetY,0.1),-1,1,this.perlinAccelLow,this.perlinAccelHigh)):this.aVelocity.add(this.acceleration),this.location.x=this.initialLocation.x+Math.sin(this.aVelocity.x)*this.amplitude.x,this.location.y=this.initialLocation.y+Math.sin(this.aVelocity.y)*
this.amplitude.y,this.pointToDirection&&(b=Burner.Vector.VectorSub(this.location,this.lastLocation),this.angle=c.Utils.radiansToDegrees(Math.atan2(b.y,b.x))),this.controlCamera&&this._checkCameraEdges(),(this.checkWorldEdges||this.wrapWorldEdges)&&this._checkWorldEdges(a),0<this.lifespan&&(this.lifespan-=1),this.afterStep&&this.afterStep.apply(this),this.pointToDirection))this.lastLocation.x=this.location.x,this.lastLocation.y=this.location.y};c.Oscillator=H;c.Utils.extend(I,c.Agent);I.prototype.init=
function(a){a=a||{};I._superClass.prototype.init.call(this,a);this.c=void 0===a.c?1:a.c;this.mass=void 0===a.mass?50:a.mass;this.isStatic=void 0===a.isStatic?!0:a.isStatic;this.width=void 0===a.width?100:a.width;this.height=void 0===a.height?100:a.height;this.opacity=void 0===a.opacity?0.75:a.opacity;this.zIndex=void 0===a.zIndex?1:a.zIndex;this.color=a.color||[105,210,231];this.borderWidth=void 0===a.borderWidth?this.width/4:a.borderWidth;this.borderStyle=a.borderStyle||"double";this.borderColor=
a.borderColor||[167,219,216];this.borderRadius=void 0===a.borderRadius?100:a.borderRadius;this.boxShadowSpread=void 0===a.boxShadowSpread?this.width/8:a.boxShadowSpread;this.boxShadowColor=a.boxShadowColor||[147,199,196];Burner.System.updateCache(this)};c.Liquid=I;c.Utils.extend(J,c.Agent);J.prototype.init=function(a){a=a||{};J._superClass.prototype.init.call(this,a);this.G=void 0===a.G?10:a.G;this.mass=void 0===a.mass?1E3:a.mass;this.isStatic=void 0===a.isStatic?!0:a.isStatic;this.width=void 0===
a.width?100:a.width;this.height=void 0===a.height?100:a.height;this.opacity=void 0===a.opacity?0.75:a.opacity;this.zIndex=void 0===a.zIndex?1:a.zIndex;this.color=a.color||[92,187,0];this.borderWidth=void 0===a.borderWidth?this.width/4:0;this.borderStyle=a.borderStyle||"double";this.borderColor=a.borderColor||[224,228,204];this.borderRadius=void 0===a.borderRadius?100:0;this.boxShadowSpread=void 0===a.boxShadowSpread?this.width/4:0;this.boxShadowColor=a.boxShadowColor||[64,129,0];Burner.System.updateCache(this)};
c.Attractor=J;c.Utils.extend(K,c.Agent);K.prototype.init=function(a){a=a||{};K._superClass.prototype.init.call(this,a);this.G=void 0===a.G?-10:a.G;this.mass=void 0===a.mass?1E3:a.mass;this.isStatic=void 0===a.isStatic?!0:a.isStatic;this.width=void 0===a.width?100:a.width;this.height=void 0===a.height?100:a.height;this.opacity=void 0===a.opacity?0.75:a.opacity;this.zIndex=void 0===a.zIndex?10:a.zIndex;this.color=a.color||[250,105,0];this.borderWidth=void 0===a.borderWidth?this.width/4:a.borderWidth;
this.borderStyle=a.borderStyle||"double";this.borderColor=a.borderColor||[224,228,204];this.borderRadius=void 0===a.borderRadius?100:a.borderRadius;this.boxShadowSpread=void 0===a.boxShadowSpread?this.width/4:a.boxShadowSpread;this.boxShadowColor=a.boxShadowColor||[250,105,0];Burner.System.updateCache(this)};c.Repeller=K;var D,z,O={},P,R={},r=["double","double","dotted","dashed"];j=0;for(s=c.config.defaultColorList.length;j<s;j++)z=c.config.defaultColorList[j],D=new c.ColorPalette,D.addColor({min:20,
max:200,startColor:z.startColor,endColor:z.endColor}),O[z.name]=D,R[z.name]=z.boxShadowColor;P=new c.BorderPalette;j=0;for(s=r.length;j<s;j++)D=r[j],P.addBorder({min:2,max:10,style:D});c.Utils.extend(L,c.Agent);L.prototype.init=function(a){var a=a||{},b=this.name.toLowerCase();L._superClass.prototype.init.call(this,a);this.mass=void 0===a.mass?50:a.mass;this.isStatic=void 0===a.isStatic?!0:a.isStatic;this.width=void 0===a.width?50:a.width;this.height=void 0===a.height?50:a.height;this.opacity=void 0===
a.opacity?0.75:a.opacity;this.zIndex=void 0===a.zIndex?1:a.zIndex;this.color=a.color||O[b].getColor();this.borderWidth=void 0===a.borderWidth?this.width/c.Utils.getRandomNumber(2,8):a.borderWidth;this.borderStyle=void 0===a.borderStyle?P.getBorder():a.borderStyle;this.borderColor=void 0===a.borderColor?O[b].getColor():a.borderColor;this.borderRadius=void 0===a.borderRadius?100:a.borderRadius;this.boxShadowSpread=void 0===a.boxShadowSpread?this.width/c.Utils.getRandomNumber(2,8):a.boxShadowSpread;
this.boxShadowColor=void 0===a.boxShadowColor?R[b]:a.boxShadowColor;Burner.System.updateCache(this)};c.Stimulus=L;c.Utils.extend(M,Burner.Item);M.prototype.init=function(a){a=a||{};this.resolution=void 0===a.resolution?50:a.resolution;this.perlinSpeed=void 0===a.perlinSpeed?0.01:a.perlinSpeed;this.perlinTime=void 0===a.perlinTime?100:a.perlinTime;this.field=a.field||null;this.createMarkers=!!a.createMarkers;this.world=a.world||Burner.System.firstWorld()};M.prototype.build=function(){var a,b,d,e,f,
h,g,i,k={},j=this.world,m=Math.ceil(j.bounds[1]/parseFloat(this.resolution)),o=Math.ceil(j.bounds[2]/parseFloat(this.resolution)),l=this.perlinTime,n;for(a=0;a<m;a+=1){n=this.perlinTime;k[a]={};b=0;for(d=o;b<d;b+=1)e=a*this.resolution+this.resolution/2,f=b*this.resolution+this.resolution/2,h=c.Utils.map(c.SimplexNoise.noise(l,n,0.1),0,1,0,2*Math.PI),g=Math.cos(h),i=Math.sin(h),h=new Burner.Vector(g,i),k[a][b]=h,g=c.Utils.radiansToDegrees(Math.atan2(i,g)),this.createMarkers&&(e=new c.FlowFieldMarker({location:new Burner.Vector(e,
f),scale:1,opacity:c.Utils.map(g,-360,360,0.1,0.75),width:this.resolution,height:this.resolution/2,field:h,angle:g,colorMode:"rgb",color:[200,100,50],borderRadius:0,zIndex:0}),j.el.appendChild(e)),n+=parseFloat(this.perlinSpeed);l+=parseFloat(this.perlinSpeed)}this.field=k};c.FlowField=M;Q.prototype.name="FlowFieldMarker";c.FlowFieldMarker=Q})(exports);
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<title>FloraJS | Sheep vs. Wolves</title>
<link rel="stylesheet" href="burner.min.css" type="text/css" charset="utf-8" />
<link rel="stylesheet" href="flora.min.css" type="text/css" charset="utf-8" />
<script src="burner.min.js" type="text/javascript" charset="utf-8"></script>
<script src="flora.min.js" type="text/javascript" charset="utf-8"></script>
<script src="animal.js" type="text/javascript" charset="utf-8"></script>
<script src="sensoranimal.js" type="text/javascript" charset="utf-8"></script>
<script src="sensorwolf.js" type="text/javascript" charset="utf-8"></script>
<script src="sensorsheep.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<script type="text/javascript" charset="utf-8">
var totalSheep = 10,
totalWolves = 10;
/**
* Tell Burner where to find custom classes.
*/
Burner.Classes.Animal = Animal;
Burner.Classes.SensorWolf = SensorWolf;
Burner.Classes.SensorSheep = SensorSheep;
var world = new Burner.World(document.body, {
gravity: new Burner.Vector(),
c: 0
});
Burner.System.init(function() {
var target = this.add('Walker');
for (var i = 0; i < totalSheep; i++) {
this.add('Animal', {
name: 'Sheep',
seekTarget: target,
location: new Burner.Vector(world.width / 4, world.height / 2),
velocity: new Burner.Vector(Flora.Utils.getRandomNumber(0, 2, true), Flora.Utils.getRandomNumber(0, 2, true)),
flocking: true,
checkWorldEdges: true,
wrapWorldEdges: true,
sensors: [
this.add('SensorWolf', {
type: 'wolf',
behavior: 'COWARD',
sensitivity: 4
})
]
});
}
for (var i = 0; i < totalWolves; i++) {
this.add('Animal', {
name: 'Wolf',
velocity: new Burner.Vector(Flora.Utils.getRandomNumber(0, 2, true), Flora.Utils.getRandomNumber(0, 2, true)),
color: [255, 100, 0],
flocking: true,
sensors: [
this.add('SensorSheep', {
type: 'sheep',
behavior: 'AGGRESSIVE',
sensitivity: 6
})
]
});
}
}, world);
</script>
</body>
</html>
var Utils = Flora.Utils,
Mover = Flora.Mover;
function SensorAnimal(opt_options) {
var options = opt_options || {};
options.name = options.name || 'SensorAnimal';
Mover.call(this, options);
}
Utils.extend(SensorAnimal, Mover);
SensorAnimal.prototype.init = function(opt_options) {
var options = opt_options || {};
SensorAnimal._superClass.prototype.init.call(this, options);
this.type = options.type || '';
this.behavior = options.behavior || 'LOVE';
this.sensitivity = typeof options.sensitivity === 'undefined' ? 2 : options.sensitivity;
this.width = typeof options.width === 'undefined' ? 7 : options.width;
this.height = typeof options.height === 'undefined' ? 7 : options.height;
this.offsetDistance = typeof options.offsetDistance === 'undefined' ? 30 : options.offsetDistance;
this.offsetAngle = options.offsetAngle || 0;
this.opacity = typeof options.opacity === 'undefined' ? 0.75 : options.opacity;
this.target = options.target || null;
this.activated = !!options.activated;
this.activatedColor = options.activatedColor || [255, 255, 255];
this.borderRadius = typeof options.borderRadius === 'undefined' ? 100 : options.borderRadius;
this.borderWidth = typeof options.borderWidth === 'undefined' ? 2 : options.borderWidth;
this.borderStyle = 'solid';
this.borderColor = [255, 255, 255];
};
/**
* Called every frame, step() updates the instance's properties.
*/
SensorAnimal.prototype.step = function() {
var check = false, i, max;
var sheep = Burner.System._caches.Sheep || {list: []};
if (this.type === 'sheep' && sheep.list && sheep.list.length > 0) {
for (i = 0, max = sheep.list.length; i < max; i++) { // heat
if (this.isInside(this, sheep.list[i], this.sensitivity)) {
this.target = sheep.list[i]; // target this stimulator
this.activated = true; // set activation
check = true;
}
}
}
if (!check) {
this.target = null;
this.activated = false;
this.color = 'transparent';
} else {
this.color = this.activatedColor;
}
if (this.afterStep) {
this.afterStep.apply(this);
}
};
/**
* Returns a force to apply to an agent when its sensor is activated.
*
*/
SensorAnimal.prototype.getActivationForce = function(agent) {
var distanceToTarget, desiredVelocity, m;
if (this.behavior === 'AGGRESSIVE') {
desiredVelocity = Burner.Vector.VectorSub(this.target.location, this.location);
distanceToTarget = desiredVelocity.mag();
desiredVelocity.normalize();
m = distanceToTarget/agent.maxSpeed;
desiredVelocity.mult(m);
desiredVelocity.sub(agent.velocity);
desiredVelocity.limit(agent.maxSteeringForce);
return desiredVelocity;
}
return new Burner.Vector();
};
/**
* Checks if a sensor can detect a stimulator.
*
* @param {Object} params The sensor.
* @param {Object} container The stimulator.
* @param {number} sensitivity The sensor's sensitivity.
*/
SensorAnimal.prototype.isInside = function(item, container, sensitivity) {
if (item.location.x + item.width/2 > container.location.x - container.width/2 - (sensitivity * container.width) &&
item.location.x - item.width/2 < container.location.x + container.width/2 + (sensitivity * container.width) &&
item.location.y + item.height/2 > container.location.y - container.height/2 - (sensitivity * container.height) &&
item.location.y - item.height/2 < container.location.y + container.height/2 + (sensitivity * container.height)) {
return true;
}
return false;
};
var Utils = Flora.Utils,
Mover = Flora.Mover;
function SensorSheep(opt_options) {
var options = opt_options || {};
options.name = options.name || 'SensorSheep';
Mover.call(this, options);
}
Utils.extend(SensorSheep, SensorAnimal);
/**
* Called every frame, step() updates the instance's properties.
*/
SensorSheep.prototype.step = function() {
var check = false, i, max;
var sheep = Burner.System._caches.Sheep || {list: []};
if (this.type === 'sheep' && sheep.list && sheep.list.length > 0) {
for (i = 0, max = sheep.list.length; i < max; i++) { // heat
if (this.isInside(this, sheep.list[i], this.sensitivity)) {
this.target = sheep.list[i]; // target this stimulator
this.activated = true; // set activation
check = true;
}
}
}
if (!check) {
this.target = null;
this.activated = false;
this.color = 'transparent';
} else {
this.color = this.activatedColor;
}
if (this.afterStep) {
this.afterStep.apply(this);
}
};
/**
* Returns a force to apply to an agent when its sensor is activated.
*
*/
SensorSheep.prototype.getActivationForce = function(agent) {
var distanceToTarget, desiredVelocity, m;
if (this.behavior === 'AGGRESSIVE') {
desiredVelocity = Burner.Vector.VectorSub(this.target.location, this.location);
distanceToTarget = desiredVelocity.mag();
desiredVelocity.normalize();
m = distanceToTarget/agent.maxSpeed;
desiredVelocity.mult(m);
desiredVelocity.sub(agent.velocity);
desiredVelocity.limit(agent.maxSteeringForce);
return desiredVelocity;
}
return new Burner.Vector();
};
var Utils = Flora.Utils,
Mover = Flora.Mover;
function SensorWolf(opt_options) {
var options = opt_options || {};
options.name = options.name || 'SensorWolf';
Mover.call(this, options);
}
Utils.extend(SensorWolf, SensorAnimal);
/**
* Called every frame, step() updates the instance's properties.
*/
SensorWolf.prototype.step = function() {
var check = false, i, max;
var wolves = Burner.System._caches.Wolf || {list: []};
if (this.type === 'wolf' && wolves.list && wolves.list.length > 0) {
for (i = 0, max = wolves.list.length; i < max; i++) { // heat
if (this.isInside(this, wolves.list[i], this.sensitivity)) {
this.target = wolves.list[i]; // target this stimulator
this.activated = true; // set activation
check = true;
}
}
}
if (!check) {
this.target = null;
this.activated = false;
this.color = 'transparent';
} else {
this.color = this.activatedColor;
}
if (this.afterStep) {
this.afterStep.apply(this);
}
};
/**
* Returns a force to apply to an agent when its sensor is activated.
*
*/
SensorWolf.prototype.getActivationForce = function(agent) {
var distanceToTarget, desiredVelocity, m;
if (this.behavior === 'COWARD') {
desiredVelocity = Burner.Vector.VectorSub(this.target.location, this.location);
distanceToTarget = desiredVelocity.mag();
desiredVelocity.normalize();
m = distanceToTarget/agent.maxSpeed;
desiredVelocity.mult(-m);
desiredVelocity.sub(agent.velocity);
desiredVelocity.limit(agent.maxSteeringForce);
return desiredVelocity;
}
return new Burner.Vector();
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment