It's an experimental trial to make animation like Boids using the Vector Field method.

## What's Boids?

Boids is an artificial life simulation program by Craig Reynolds.
These moving looks like a flock of birds. So it named "Bird-oid".

https://en.wikipedia.org/wiki/Boids

Boids need Separation, Alignment, and Cohesion. And my implementation in this article ignores them.
So it's not Boids at all, it just these motion looks like a Boids.

## Real pleasure of Creative coding.

I love Vector Field. It has infinite possibilities.

Drawing vector field | GenerateMe
https://generateme.wordpress.com/2016/04/24/drawing-vector-field/

When I was playing with my Vector Field example, I had an idea to draw a part of Vector Field flow.
And I made an animation with that idea, I thought it looks like a Boids.

But as you know, if you calculate Vector Field with points coordinates only, you get the same flow line.

``````

noise(x, y);

```
```

So, I put particle number as the third dimension on noise(). It makes different vector fields each particle.

``````

noise(n, x, y);

```
```

And then, tune the third dimension of noise(), it becomes fake Boids!

``````

noise(n * 0.01, x, y);

```
```

## The 'Processing' code example (Java).

Please feel free to use this example code, if you like it.
To see other works based on my code is my pleasure. And my honor.

``````

/**
* So Many Ways.
* draw vector field flowing images that imitate the Boids.
*
* @author @deconbatch
* @version 0.1
* Processing 3.2.1
* 2019.10.19
*/

import java.util.List;

void setup() {
size(720, 446);
colorMode(HSB, 360, 100, 100, 100);
smooth();
noStroke();
noLoop();
}

void draw() {

int   imgMax  = 3;      // 3 vector field flowing images
int   frmMax  = 24 * 6; // 24fps x 6s movie
int   plotMax = 2000;
float plotDiv = 0.001;
float baseHue = random(360.0);

for (int imgCnt = 0; imgCnt < imgMax; ++imgCnt) {

float initDiv  = 0.1;
float plotMult = random(2.0, 5.0);
float baseBri  = 3.0;
float baseSiz  = random(3.0, 6.0);

baseHue += 120.0; // 120 hue difference each cycle
noiseSeed(floor(baseHue * plotMult)); // make diffrent flow each cycle

List<List<PVector>> vectorField = getVectorfield(initDiv, plotMax, plotDiv, plotMult);

for (int frmCnt = 0; frmCnt < frmMax; ++frmCnt) {

float frmRatio  = map(frmCnt, 0, frmMax, 0.0, 1.0);
float easeRatio = easeInOutCubic(frmRatio);
float piFrm     = sin(PI * frmRatio);
int   plotLen   = floor(plotMax * 0.05 * piFrm) + 5;
int   plotStart = floor((plotMax - plotLen) * easeRatio);

blendMode(DIFFERENCE);
background(baseHue % 360.0, 10.0 * piFrm, 90.0, 100);

// draw vector field
int flowCnt = 0;
for (List<PVector> flows : vectorField) {
flowCnt++;
for (int plotCnt = plotStart; plotCnt < plotStart + plotLen; plotCnt++) {
PVector points  = flows.get(plotCnt);
float plotRatio = map(plotCnt, plotStart, plotStart + plotLen, 0.0, 1.0);
float eHue      = baseHue + plotRatio * 60.0 + (flowCnt % 4) * 10.0;
float eSat      = map(sin(PI * plotRatio), 0.0, 1.0, 80.0, 40.0);
float eBri      = baseBri * sin(HALF_PI * plotRatio);
float eSiz      = baseSiz * (1.0 + noise(flowCnt) * 3.0) * sin(HALF_PI * plotRatio);
fill(eHue % 360.0, eSat, eBri, 100.0);
ellipse(points.x * width, points.y * height, eSiz, eSiz);
}

}
blendMode(BLEND);
casing();
saveFrame("frames/" + String.format("%01d", imgCnt) + String.format("%03d", frmCnt) + ".png");
}
}
exit();
}

/**
* getVectorfield  calculate whole Vector Field flow and return them with List.
* @param  _initDiv  :  the distance of each flow start point.
* @param  _plotMax  :  how many time calculate Vector Field each flow.
* @param  _plotDiv  :  distance of step.
* @param  _plotMult :  not zero. curvature.
* @return List<List<PVector>> : each flow List(each points List(coordinates))
*/
private List<List<PVector>> getVectorfield(float _initDiv, int _plotMax, float _plotDiv, float _plotMult) {

float noiseDiv = 1.8 / _plotMult;
int   flowCnt  = 0;

List<List<PVector>> vectorField = new ArrayList();

for (float xInit = -1.0; xInit <= 2.0; xInit += _initDiv) {
for (float yInit = -1.0; yInit <= 2.0; yInit += _initDiv) {

List<PVector> flows = new ArrayList();

flowCnt++;
float xCurr = xInit;
float yCurr = yInit;

for (int plotCnt = 0; plotCnt < _plotMax; ++plotCnt) {
float xPrev = xCurr;
float yPrev = yCurr;
float rCurr = TWO_PI * noise(flowCnt * 0.002, xPrev * noiseDiv, yPrev * noiseDiv);
xCurr += _plotDiv * cos(rCurr * _plotMult);
yCurr += _plotDiv * sin(rCurr * _plotMult);
}
}
}
return vectorField;
}

/**
* easeInOutCubic easing function.
* @param  _t    0.0 - 1.0 : linear value.
* @return float 0.0 - 1.0 : eased value.
*/
private float easeInOutCubic(float _t) {
_t *= 2.0;
if (_t < 1.0) {
return pow(_t, 3) / 2.0;
}
_t -= 2.0;
return (pow(_t, 3) + 2.0) / 2.0;
}

/**
* casing : draw fancy casing
*/
private void casing() {
fill(0.0, 0.0, 0.0, 0.0);
strokeWeight(46.0);
stroke(0.0, 0.0, 30.0, 100.0);
rect(0.0, 0.0, width, height);
strokeWeight(42.0);
stroke(0.0, 0.0, 100.0, 100.0);
rect(0.0, 0.0, width, height);
noStroke();
noFill();
}

/*

This program is free software: you can redistribute it and/or modify
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>
*/

```
```

## Yet another example images.

They seems to love my fault work most.🤣