Animations 2a, 2b updated.

master
Ben Burlingham 8 years ago
parent 21ba248754
commit 04a37ceb53
  1. 14
      index.html
  2. 21
      js/animation.js
  3. 95
      js/animation2a.js
  4. 95
      js/animation2b.js
  5. 1345
      js/bundle.js
  6. 37
      js/controls.js
  7. 10
      js/index.js
  8. 45
      js/particle.js

@ -43,7 +43,7 @@
<div class='outerContainer' id='1b'></div>
<!-- <p>
<p>
<h4>Exploration 2: Grid-based vision</h4>
</p>
@ -52,21 +52,15 @@
against the global grid to detect collisions. Here's a small scale system, with the vision grid visualized:
</p>
<div class='outerContainer'>
<div id="animation2a" class='animationContainer'></div>
<div id="controls2a" class='controlsContainer'></div>
</div>
<div class='outerContainer' id='2a'></div>
<p>
Here's a large scale system.
</p>
<div class='outerContainer'>
<div id="animation2b" class='animationContainer'></div>
<div id="controls2b" class='controlsContainer'></div>
</div>
<div class='outerContainer' id='2b'></div>
<p>
<!-- <p>
The last goal was to play around with flocking behavior. Cohesion:
</p>

@ -2,9 +2,10 @@ import Rx, { Observable } from 'rxjs';
import Grid from './grid';
import Particle from './particle';
import Controls from './controls';
import Random from './random';
import { CONTROLS, ENTITIES } from './enums';
function Animation(observables, id) {
function Animation(observables, id, showHazards) {
this.id = id;
this.observables = observables;
this.particles = [];
@ -42,4 +43,22 @@ Animation.prototype.subscribeCount = function(count) {
}
}
Animation.prototype.addHazards = function() {
const bounds = this.container.getBoundingClientRect();
const n = Random.num(1, 3);
for (let i = 0; i < n; i++) {
const w = Random.num(50, 200);
const h = Random.num(50, 200);
this.grid.setArea({
x: Random.num(0, bounds.width - w),
y: Random.num(0, bounds.height - h),
w,
h,
type: ENTITIES.HAZARD
}, this.container);
}
}
export default Animation;

@ -1,93 +1,14 @@
import Rx, { Observable } from 'rxjs';
import Particle from './particle';
import Grid from './grid';
import Animation from './animation';
import Controls from './controls';
import Random from './random';
import { CONTROLS, ENTITIES } from './enums';
function Animation2a() {
this.options = {
count: 3,
export default function(destroy$) {
const id = '2a';
const config = {
id,
maxCount: 10,
showVisionGrid: true,
speed: 4
showVisionGridControl: true
};
this.container = document.getElementById('animation2a');
this.particles = [];
this.grid = this.createGlobalGrid();
const controls = new Controls(
document.getElementById('controls2a'),
this.options
);
controls.mount().subscribe(this.subscriber.bind(this));
this.updateAnimating(this.options.animating);
this.updateCount(this.options.count);
};
Animation2a.prototype.subscriber = function({ key, value }) {
switch(key) {
case CONTROLS.ANIMATING: this.updateAnimating(value); break;
case CONTROLS.COUNT: this.updateCount(value); break;
case CONTROLS.SPEED: this.updateSpeed(value); break;
}
}
Animation2a.prototype.nextFrame = function() {
this.particles.forEach(p => p.nextFrame());
}
Animation2a.prototype.updateAnimating = function(isAnimating) {
this.options.animating = isAnimating;
if (isAnimating) {
const fps$ = Rx.Observable.interval(1000 / 32)
.takeWhile(_ => this.options.animating);
fps$.subscribe(this.nextFrame.bind(this));
}
}
Animation2a.prototype.updateCount = function(count) {
const bounds = this.container.getBoundingClientRect();
while (this.particles.length > count) {
delete this.particles.pop().remove();
}
while (this.particles.length < count) {
const p = new Particle(this.container, bounds, this.options, this.grid);
this.particles.push(p);
}
const observables = Controls(destroy$, config);
(new Animation(observables, id, true)).addHazards();
}
Animation2a.prototype.updateSpeed = function(value) {
this.options.speed = value;
this.particles.forEach(p => p.updateConfig({ speed: value }));
}
Animation2a.prototype.createGlobalGrid = function() {
const bounds = this.container.getBoundingClientRect();
const grid = new Grid();
const n = Random.num(1, 3);
for (let i = 0; i < n; i++) {
const w = Random.num(50, 200);
const h = Random.num(50, 200);
grid.setArea({
x: Random.num(0, bounds.width - w),
y: Random.num(0, bounds.height - h),
w,
h,
type: ENTITIES.HAZARD
}, this.container);
}
return grid;
}
export default Animation2a;

@ -1,92 +1,13 @@
import Rx, { Observable } from 'rxjs';
import Particle from './particle';
import Grid from './grid';
import Animation from './animation';
import Controls from './controls';
import Random from './random';
import { CONTROLS, ENTITIES } from './enums';
function Animation2b() {
this.options = {
count: 1,
maxCount: 1000,
speed: 4
export default function(destroy$) {
const id = '2b';
const config = {
id,
maxCount: 1000
};
this.container = document.getElementById('animation2b');
this.particles = [];
this.grid = this.createGlobalGrid(this.container, this.bounds);
const controls = new Controls(
document.getElementById('controls2b'),
this.options
);
controls.mount().subscribe(this.subscriber.bind(this));
this.updateAnimating(this.options.animating);
this.updateCount(this.options.count);
};
Animation2b.prototype.subscriber = function({ key, value }) {
switch(key) {
case CONTROLS.ANIMATING: this.updateAnimating(value); break;
case CONTROLS.COUNT: this.updateCount(value); break;
case CONTROLS.SPEED: this.updateSpeed(value); break;
}
}
Animation2b.prototype.nextFrame = function() {
this.particles.forEach(p => p.nextFrame());
}
Animation2b.prototype.updateAnimating = function(isAnimating) {
this.options.animating = isAnimating;
if (isAnimating) {
const fps$ = Rx.Observable.interval(1000 / 32)
.takeWhile(_ => this.options.animating);
fps$.subscribe(this.nextFrame.bind(this));
}
}
Animation2b.prototype.updateCount = function(count) {
const bounds = this.container.getBoundingClientRect();
while (this.particles.length > count) {
delete this.particles.pop().remove();
}
while (this.particles.length < count) {
const p = new Particle(this.container, bounds, this.options, this.grid);
this.particles.push(p);
}
const observables = Controls(destroy$, config);
new Animation(observables, id).addHazards();
}
Animation2b.prototype.updateSpeed = function(value) {
this.options.speed = value;
this.particles.forEach(p => p.updateConfig({ speed: value }));
}
Animation2b.prototype.createGlobalGrid = function() {
const bounds = this.container.getBoundingClientRect();
const grid = new Grid();
const n = Random.num(1, 3);
for (let i = 0; i < n; i++) {
const w = Random.num(50, 200);
const h = Random.num(50, 200);
grid.setArea({
x: Random.num(0, bounds.width - w),
y: Random.num(0, bounds.height - h),
w,
h,
type: ENTITIES.HAZARD
}, this.container);
}
return grid;
}
export default Animation2b;

File diff suppressed because one or more lines are too long

37
js/controls.js vendored

@ -6,7 +6,8 @@ export default function(destroy$, {
id,
maxCount = 10,
showCircleControl = false,
showRandomizeControl = false
showRandomizeControl = false,
showVisionGridControl = false
}) {
const container = document.createElement('div');
container.className = 'controlsContainer';
@ -17,9 +18,10 @@ export default function(destroy$, {
fps$: new Rx.Subject(),
count$: createCountControl(container, 0, maxCount),
speed$: createSpeedControl(container),
circle$: showCircleControl ? createCircleControl(container) : undefined,
randomize$: showRandomizeControl ? createRandomizeControl(container) : undefined,
animating$: createAnimatingControl(container),
circle$: showCircleControl && createCircleControl(container),
randomize$: showRandomizeControl && createRandomizeControl(container),
vision$: showVisionGridControl && createVisionGridControl(container),
animating$: createAnimatingControl(container)
};
observables.animating$.subscribe((isAnimating) => {
@ -192,3 +194,30 @@ function createRandomizeControl(container) {
return randomize$;
}
function createVisionGridControl(container) {
const label = document.createElement('label');
label.className = 'controls-checkbox';
const text = document.createElement('span');
text.innerHTML = 'Show vision grid';
text.className = 'controls-checkbox-text';
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.className = 'controls-checkbox-input';
checkbox.checked = true;
label.appendChild(checkbox);
label.appendChild(text);
container.appendChild(label);
const vision$ = new Rx.BehaviorSubject(true);
label.addEventListener('change', (evt) => {
vision$.next(evt.target.checked);
});
return vision$;
}

@ -1,10 +1,8 @@
import Rx, { Observable } from 'rxjs';
import Animation1a from './animation1a';
import Animation1b from './animation1b';
// import Container1b from './container1b';
// import Container2a from './container2a';
// import Container2b from './container2b';
// import Container3a from './container3a';
import Animation2a from './animation2a';
import Animation2b from './animation2b';
require('../css/reset.scss');
require('../css/index.scss');
@ -16,6 +14,8 @@ window.addEventListener('load', () => {
Animation1a(destroy$);
Animation1b(destroy$);
Animation2a(destroy$);
Animation2b(destroy$);
});
// TODO remove bottom padding from Disqus
@ -24,6 +24,8 @@ window.addEventListener('load', () => {
// TODO sort out particle nextframe
// TODO abs positioning on controls elements so order doesn't matter
// TODO BehaviorSubject listener on bounds change
// TODO are vision grid nodes removed properly
// TODO overlapping grid points
// TODO ANIM1ab free movement

@ -39,6 +39,12 @@ function Particle(parent, bounds, globalGrid, observables) {
this.isLeader = false;
this.arc = Arc.create(bounds, this.grids.global);
// If starting in a hazard, recurse.
while (this.grids.global.getPoint({ x: this.arc.endX, y: this.arc.endY, type: ENTITIES.HAZARD}) !== undefined) {
this.arc = Arc.create(bounds, this.grids.global);
}
// this.grids.global.setPoint({ x: p.arc.endX, y: p.arc.endY, type: ENTITIES.PARTICLE }, p); // USE ID?
this.remove$ = new Rx.Subject();
@ -51,12 +57,17 @@ function Particle(parent, bounds, globalGrid, observables) {
.takeUntil(this.remove$)
.subscribe(this.subscribeSpeed.bind(this));
observables.randomize$ && observables.randomize$
.takeUntil(this.remove$)
.subscribe(this.subscribeRandomize.bind(this));
observables.circle$ && observables.circle$
.takeUntil(this.remove$)
.subscribe(this.subscribeCircle.bind(this));
// observables.randomize$.subscribe(this.subscribeRandomize.bind(this));
observables.vision$ && observables.vision$
.takeUntil(this.remove$)
.subscribe(this.subscribeVision.bind(this));
};
// ===== PROTOTYPE =====
@ -85,12 +96,12 @@ Particle.prototype.subscribeNextFrame = function() {
this.arc = Arc.randomize(this.arc);
}
// this.grids.vision = updateVisionGrid(this.arc, this.config, this.grids);
// const { hazards, particles } = look(this.arc, this.grids);
this.grids.vision = updateVisionGrid(this.arc, this.config, this.grids);
const { hazards, particles } = look(this.arc, this.grids);
// if (hazards.length > 0) {
// this.arc = Arc.evade(this.arc);
// }
if (hazards.length > 0) {
this.arc = Arc.evade(this.arc);
}
// this.updateLeader(particles);
@ -110,13 +121,6 @@ Particle.prototype.subscribeSpeed = function(value) {
this.config.speed = value;
}
// if (showVision === true && this.nodes.visionGrid === undefined) {
// this.nodes.visionGrid = createVisionGridNodes(this.config, this.grids, this.nodes);
// }
//
// if (showVision === false && this.nodes.visionGrid !== undefined) {
// delete this.nodex.visionGrid;
// }
Particle.prototype.subscribeCircle = function(show) {
if (show === false) {
@ -132,6 +136,15 @@ Particle.prototype.subscribeRandomize = function(value) {
this.config.randomize = value;
}
Particle.prototype.subscribeVision = function(show) {
if (show === false) {
this.nodes.visionGrid.forEach(n => n.parentNode.removeChild(n));
delete this.nodes.visionGrid;
} else {
this.nodes.visionGrid = createVisionGridNodes(this.config, this.grids, this.nodes);
}
}
Particle.prototype.updateLeader = function(particles) {
if (this.config.behavior !== BEHAVIOR.COHESION) {
return;
@ -249,10 +262,6 @@ function createVisionGrid(config) {
}
function createVisionGridNodes(config, grids, nodes) {
if (config.showVision === false) {
return undefined;
}
return grids.vision.reduce((acc, { x, y }) => {
const div = document.createElement('div');
div.className = 'particle-vision-dot';

Loading…
Cancel
Save