function t(n,a,o,e,c){return n.x&&(i=t(4,n.x,n.y),n.which&&(v=b)),1==n&&(c=r.sqrt(h(i.x-a,2)+h(i.y-o,2))),2==n&&(c=t(4,e.x+r.cos(a)*o,e.y+r.sin(a)*o)),3==n&&(c={c:[t(4,y*s(),y*s())],d:.5,s:x,t:0,h:.5+s()}),4==n&&(c={x:a,y:o}),c}var n,i,o=[],e=["#000","#FF0","rgba(0,160,0,.3)"],r=Math,h=r.pow,s=r.random,u=.05,d=.1,l=.1,y=window.innerWidth,f=34,x=3,m=6,w=30,g=w,v=0,b=900,k=5
for(c.height=y/2,c.width=y,onmousemove=onclick=t;g--;)o[g]=t(3);(function q(){var r,h,c,x,b,F,p,C,S,W
for(a.fillStyle=e[2],a.fillRect(0,0,y,y),g=0;w>g;g++){for(n=o[g],h=n.t,c=n.d,r=n.h,x=n.c,b=0;m*r>b&&x.length-2>2*b;b++)a.beginPath(),a.lineWidth=f*r,a.lineCap=0==b?"round":"butt",a.quadraticCurveTo(x[2*b].x,x[2*b].y,x[2*b+2].x,x[2*b+2].y),a.strokeStyle=e[b%2],a.stroke()
W=t(2,c,(v?n.s*k:n.s)*n.h,x[0]),x.unshift(W),c+=h,(u>s()||i)&&(S=2*(s()-.5)*l,h+=S,i&&(F=t(2,c+S,n.s*n.h,W),p=t(1,F.x,F.y),F=t(2,c-S,n.s*n.h,W),C=t(1,F.x,F.y)),p>C&&i&&(h+=2*(v?S:-S)),h>d&&(h=d),-d>h&&(h=-d),v&&v--,n.t=h,n.d=c)}requestAnimationFrame(q)})()
/*
# todos:
- flush old positions from bee state
- flocking of bees when nothing else matters
- Pop flowers with mouse
- rounder butt and head for bees
- Increese/Decrease health with flower power
- Split bee when health is high enough
*/
(function () {
var mode;
var bee
var bees = [];
// Green RGBA is to obtain a trail after bees
var colors = ["#000", "#FF0", "rgba(0,160,0,.3)"];
// Aliases
var M = Math;
var pow = M.pow;
var random = M.random;
// Configuration
var turnRateChangeOccurence = 0.05;
var maxTurnRate = 0.1;
var maxTurnRateChange = 0.1;
var stageSize = window.innerWidth;
var beeWidth = 34;
var baseSpeed = 3; // Distance run on each step
var beeLength = 6;
var beeTarget;
var beeCount = 30;
var i = beeCount; // First iteration will be on BeeCount
var isTargetRepulsing = 0;
var repulseCycles = 900;
var repulseStrengh = 5;
c.height = stageSize/2;
c.width = stageSize;
// bee = [positions, direction, speed, turn rate, health]
// position is an array of [posX, posY]
// Speed is units per cycle
// Turn rate is how much the direction shifts at every cycle
/*
Bee
.c = coordinates
.d = direction
.s = speed
.t = turn rate
.h = health
*/
onmousemove = onclick = polyFunc;
function polyFunc(mode, a, b, c, value) {
// mode = event
if (mode.x) {
beeTarget = polyFunc(4, mode.x, mode.y);
// onclick event
if (mode.which) {
isTargetRepulsing = repulseCycles;
}
}
// function distanceToTarget (x1, y1) {
if (mode == 1) {
value = M.sqrt( pow(beeTarget.x - a, 2) + pow(beeTarget.y - b, 2) );
}
//function forwardPos(angle, length, pos) {
if (mode == 2) {
// polyFunc = Coord
value = polyFunc(4,
c.x + M.cos(a) * b,
c.y + M.sin(a) * b
);
}
//function Bee() {
if (mode == 3) {
value = {
// polyFunc = Coord
c:[polyFunc(4, stageSize * random(), stageSize * random())],
d:0.5,
s:baseSpeed,
t:0,
h:0.5 + random()
}
}
//function Coord (x, y);
if (mode == 4) {
value = {x:a, y:b}
}
return value;
};
// Spawn X ammount of bees
// polyFunc = Bee
for (;i--;) bees[i] = polyFunc(3);
(function loop() {
// Shorthands for Bee attributes
var health;
var turnRate;
var direction;
var positions;
var posIndex;
var positions;
// Fill the canvas with green
a.fillStyle = colors[2];
a.fillRect(0, 0, stageSize, stageSize);
for (i = 0; i < beeCount; i++) {
bee = bees[i];
turnRate = bee.t;
direction = bee.d;
health = bee.h;
positions = bee.c;
posIndex = 0;
for (;posIndex < (beeLength * health) && posIndex*2 < positions.length-2; posIndex++) {
a.beginPath();
a.lineWidth = beeWidth * health; // According to health
a.lineCap = (posIndex == 0) ? "round" : "butt";
a.quadraticCurveTo(
positions[posIndex*2].x,
positions[posIndex*2].y,
positions[posIndex*2+2].x,
positions[posIndex*2+2].y);
a.strokeStyle = colors[posIndex%2];
a.stroke();
}
/* MOVE ROUTINE */
var pos2;
var distA;
var distB;
var change
// Speed is according to health
// polyFunc = forwardPos
var pos = polyFunc(2, direction, (isTargetRepulsing ? bee.s * repulseStrengh : bee.s) * bee.h, positions[0] );
positions.unshift(pos);
direction += turnRate;
// One in a while, the turn rate changes
// Force turn change if a target is in sight
if (random() < turnRateChangeOccurence || beeTarget) {
change = (random() - 0.5) * 2 * maxTurnRateChange;
turnRate += change;
// Test future position with both angles
if (beeTarget) {
// polyFunc = forwardPos
pos2 = polyFunc(2, direction + change, bee.s * bee.h, pos );
// polyFunc = distanceToTarget
distA = polyFunc(1, pos2.x, pos2.y);
// polyFunc = forwardPos
pos2 = polyFunc(2, direction - change, bee.s * bee.h, pos );
// polyFunc = distanceToTarget
distB = polyFunc(1, pos2.x, pos2.y);
}
// If the directon change takes the bee's angle of attack away from the tarket
// inverse the adjustment
if (distA > distB && beeTarget) {
turnRate += (isTargetRepulsing ? change : -change) * 2;
}
// Enforce maxTurnRate
if (turnRate > maxTurnRate) turnRate = maxTurnRate;
if (turnRate < - maxTurnRate) turnRate = -maxTurnRate;
// Decrement repulse if not already at 0
isTargetRepulsing && isTargetRepulsing--;
// Reeasing shortcut vars to bee object
bee.t = turnRate;
bee.d = direction;
}
}
requestAnimationFrame(loop);
})();
})();