Progress on global animation management.

master
Ben Burlingham 8 years ago
parent b861b78fba
commit ea7210309f
  1. 16
      index.html
  2. 105
      js/animation.js
  3. 142
      js/animation1a.js
  4. 72
      js/animation1b.js
  5. 31
      js/arc.js
  6. 1560
      js/bundle.js
  7. 201
      js/controls.js
  8. 2
      js/enums.js
  9. 30
      js/index.js
  10. 112
      js/particle.js
  11. 6
      js/random.js

@ -15,7 +15,7 @@
Explore the RxJs API by managing moving particle systems. The systems should:
<ul>
<li>Use self-aware AI, not a global AI</li>
<li>Have particle movement that feels calm and natural</li>
<li>Move in organic, natural arcs, with no sudden pivots or swerves</li>
<li>Support large swarms of particles</li>
<li>Be able to evade obstacles</li>
<li>Exhibit flocking behavior</li>
@ -35,21 +35,15 @@
groups. The current design uses circular paths that allow smooth changes in both direction and rotation.
</p>
<div class='outerContainer'>
<div id="animation1a" class='animationContainer'></div>
<div id="controls1a" class='controlsContainer'></div>
</div>
<div class='outerContainer' id='1a'></div>
<p>
This method can handle quite a few particles.
</p>
<div class='outerContainer'>
<div id="animation1b" class='animationContainer'></div>
<div id="controls1b" class='controlsContainer'></div>
</div>
<div class='outerContainer' id='1b'></div>
<p>
<!-- <p>
<h4>Exploration 2: Grid-based vision</h4>
</p>
@ -79,7 +73,7 @@
<div class='outerContainer'>
<div id="animation3a" class='animationContainer'></div>
<div id="controls3a" class='controlsContainer'></div>
</div>
</div> -->
<script src='js/bundle.js'></script>
<script src='/core/js/ui.js'></script>

@ -4,30 +4,61 @@ import Particle from './particle';
import Controls from './controls';
import { CONTROLS, ENTITIES } from './enums';
function Animation() {
// TODO remove bottom padding from Disqus
// TODO fix "hangup" small radius evade bug
// TODO don't load simulation until requested
// TODO sort out particle nextframe
// TODO ANIM1ab free movement
// TODO ANIM3a streamline updateLeader
// TODO ANIM3b separation
// TODO ANIM3c alignment
};
Animation.prototype.destroy = function() {
function Animation(observables, id) {
this.id = id;
this.observables = observables;
this.particles = [];
this.container = document.createElement('div');
this.container.className = 'animationContainer';
document.getElementById(id).appendChild(this.container);
this.observables.animating$.subscribe(this.updateAnimating.bind(this));
this.observables.count$.skip(1).subscribe(this.updateCount.bind(this));
// observables.circle$, PROBABLY WON'T NEED THESE, WILL BE In PARTICLE
// observables.randomize$,
// observables.speed$
// this.observables.count$.next(99);
//<div class='animationContainer'></div>
// console.warn("Mounting Animation", this.id);
// console.warn('updateAnimating in Animation', isAnimating)
// this.isAnimating = isAnimating;
// if (isAnimating) {
// const fps$ = Rx.Observable.interval(1000 / 32)
// .takeWhile(_ => this.isAnimating);
//
// fps$.subscribe(this.nextFrame.bind(this));
// }
// this.container = container;
// this.particles = [];
// this.isAnimating = false;
// this.config = config;
// this.grid = new Grid();
// this.updateAnimating(false);
// this.updateCircle(config.circleControl);
// this.updateSpeed(config.speed);
// this.updateRandomize(this.config.randomizeControl);
// Must be last, after configs all set up and container is fully rendered.
// this.updateCount(this.config.count);
}
Animation.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;
Animation.prototype.updateAnimating = function(isAnimating) {
if (isAnimating === false) {
return;
}
const fps$ = Rx.Observable.interval(1000 / 32)
.takeUntil(this.observables.animating$);
fps$.subscribe(this.nextFrame.bind(this));
}
Animation.prototype.nextFrame = function() {
@ -37,41 +68,39 @@ Animation.prototype.nextFrame = function() {
p.nextFrame();
this.grid.deletePoint({ x: prevX, y: prevY, type: ENTITIES.PARTICLE });
this.grid.setPoint({ x: p.arc.endX, y: p.arc.endY, type: ENTITIES.PARTICLE }, p);
// this.grid.deletePoint({ x: prevX, y: prevY, type: ENTITIES.PARTICLE });
// this.grid.setPoint({ x: p.arc.endX, y: p.arc.endY, type: ENTITIES.PARTICLE }, p);
});
}
Animation.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));
}
}
Animation.prototype.updateCount = function(count) {
const bounds = this.container.getBoundingClientRect();
while (this.particles.length > count) {
const p = this.particles.pop();
this.grid.deletePoint({ x: p.arc.endX, y: p.arc.endY, type: ENTITIES.PARTICLE });
p.remove();
}
while (this.particles.length < count) {
const p = new Particle(this.container, bounds, this.options, this.grid);
this.grid.setPoint({ x: p.arc.endX, y: p.arc.endY, type: ENTITIES.PARTICLE }, p);
const p = new Particle(this.container, bounds, this.config, this.grid);
this.particles.push(p);
}
}
Animation.prototype.updateSpeed = function(value) {
this.options.speed = value;
// Options must be stored; they are passed to new particles.
this.config.speed = value;
this.particles.forEach(p => p.updateConfig({ speed: value }));
}
Animation.prototype.updateCircle = function(value) {
this.config.showMovementCircle = value;
this.particles.forEach(p => p.updateConfig({ showMovementCircle: value }));
}
Animation.prototype.updateRandomize = function(value) {
this.config.randomize = value;
this.particles.forEach(p => p.updateConfig({ randomize: value }));
}
export default Animation;

@ -1,136 +1,16 @@
import Rx, { Observable } from 'rxjs';
import Grid from './grid';
import Particle from './particle';
import Animation from './animation';
import Controls from './controls';
import { CONTROLS } from './enums';
function Animation1a() {
this.options = {
count: 1,
maxCount: 10,
randomize: true,
showMovementCircle: true,
speed: 4
};
this.container = document.getElementById('animation1a');
this.particles = [];
this.grid = new Grid();
this.movementCircleCtrl = createMovementCircleControl();
this.randomizeCtrl = createRandomizeControl();
const controls = new Controls(
document.getElementById('controls1a'),
this.options,
[this.movementCircleCtrl, this.randomizeCtrl]
);
const circle$ = Rx.Observable.fromEvent(this.movementCircleCtrl, 'change')
.map(evt => ({ key: CONTROLS.MOVEMENT_CIRCLE, value: evt.target.checked }));
const randomize$ = Rx.Observable.fromEvent(this.randomizeCtrl, 'change')
.map(evt => ({ key: CONTROLS.RANDOMIZE, value: evt.target.checked }));
const eventStack$ = controls.mount().merge(circle$, randomize$);
eventStack$.subscribe(this.subscriber.bind(this));
this.updateCount(this.options.count);
this.updateMovementCircle(this.options.showMovementCircle);
this.updateRandomize(this.options.randomize);
};
function createMovementCircleControl() {
const label = document.createElement('label');
label.className = 'controls-checkbox';
const text = document.createElement('span');
text.innerHTML = 'Show movement circle';
text.className = 'controls-checkbox-text';
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.className = 'controls-checkbox-input';
label.appendChild(checkbox);
label.appendChild(text);
return label;
}
function createRandomizeControl(value) {
const label = document.createElement('label');
label.className = 'controls-checkbox';
const text = document.createElement('span');
text.innerHTML = 'Randomize movement';
text.className = 'controls-checkbox-text';
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.className = 'controls-checkbox-input';
checkbox.checked = value;
label.appendChild(checkbox);
label.appendChild(text);
export default function(destroy$) {
const id = '1a';
return label;
}
Animation1a.prototype.subscriber = function({ key, value }) {
switch(key) {
case CONTROLS.ANIMATING: this.updateAnimating(value); break;
case CONTROLS.COUNT: this.updateCount(value); break;
case CONTROLS.MOVEMENT_CIRCLE: this.updateMovementCircle(value); break;
case CONTROLS.RANDOMIZE: this.updateRandomize(value); break;
case CONTROLS.SPEED: this.updateSpeed(value); break;
}
}
Animation1a.prototype.nextFrame = function() {
this.particles.forEach(p => p.nextFrame());
}
Animation1a.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));
}
}
Animation1a.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);
}
}
Animation1a.prototype.updateMovementCircle = function(value) {
this.options.showMovementCircle = value;
this.movementCircleCtrl.querySelector('[type=checkbox]').checked = value;
this.particles.forEach(p => p.updateConfig({ showMovementCircle: value }));
}
Animation1a.prototype.updateRandomize = function(value) {
this.options.randomize = value;
this.randomizeCtrl.querySelector('[type=checkbox]').checked = value;
this.particles.forEach(p => p.updateConfig({ randomize: value }));
}
const config = {
id,
max: 10,
showCircleControl: true,
showRandomizeControl: true,
};
Animation1a.prototype.updateSpeed = function(value) {
this.options.speed = value;
this.particles.forEach(p => p.updateConfig({ speed: value }));
const observables = Controls(destroy$, config);
new Animation(observables, id);
}
export default Animation1a;

@ -1,69 +1,13 @@
import Rx, { Observable } from 'rxjs';
import Grid from './grid';
import Particle from './particle';
import Animation from './animation';
import Controls from './controls';
import { CONTROLS } from './enums';
function Animation1b() {
this.options = {
count: 1,
maxCount: 1000,
speed: 8
export default function(destroy$) {
const id = '1b';
const config = {
id,
max: 10
};
this.container = document.getElementById('animation1b');
this.particles = [];
this.grid = new Grid();
const controls = new Controls(
document.getElementById('controls1b'),
this.options
);
controls.mount().subscribe(this.subscriber.bind(this));
this.updateCount(this.options.count);
};
Animation1b.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;
}
const observables = Controls(destroy$, config);
new Animation(observables, id);
}
Animation1b.prototype.nextFrame = function() {
this.particles.forEach(p => p.nextFrame());
}
Animation1b.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));
}
}
Animation1b.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);
}
}
Animation1b.prototype.updateSpeed = function(value) {
this.options.speed = value;
this.particles.forEach(p => p.updateConfig({ speed: value }));
}
export default Animation1b;

@ -25,9 +25,9 @@ const Arc = {
arc = Arc.overflow(arc, bounds);
// If starting in a hazard, recurse.
if (grid.getPoint({ x: arc.endX, y: arc.endY, type: ENTITIES.HAZARD })) {
arc = Arc.create(bounds, grid);
}
// if (grid.getPoint({ x: arc.endX, y: arc.endY, type: ENTITIES.HAZARD })) {
// arc = Arc.create(bounds, grid);
// }
return arc;
},
@ -128,18 +128,19 @@ const Arc = {
},
goto: function (arc, x, y, speed) {
const prevD = Math.pow(Math.pow(x - arc.prevEndX, 2) + Math.pow(y - arc.prevEndY, 2), 0.5);
const currD = Math.pow(Math.pow(x - arc.endX, 2) + Math.pow(y - arc.endY, 2), 0.5);
const ratio = (prevD - currD) / speed;
if (currD < 10) {
throw new Error(`Arc end of (${arc.endX},${arc.endY}) is within 50px of (${x},${y})`);
} else if (ratio < 0.8) {
// arc = (ratio < 0 ? Arc.reverse(arc) : arc);
arc = Arc.changeRadius(arc, 20);
} else {
arc = Arc.changeRadius(arc, 400);
}
// WORKING!
// const prevD = Math.pow(Math.pow(x - arc.prevEndX, 2) + Math.pow(y - arc.prevEndY, 2), 0.5);
// const currD = Math.pow(Math.pow(x - arc.endX, 2) + Math.pow(y - arc.endY, 2), 0.5);
// const ratio = (prevD - currD) / speed;
//
// if (currD < 10) {
// throw new Error(`Arc end of (${arc.endX},${arc.endY}) is within 50px of (${x},${y})`);
// } else if (ratio < 0.8) {
// // arc = (ratio < 0 ? Arc.reverse(arc) : arc);
// arc = Arc.changeRadius(arc, 20);
// } else {
// arc = Arc.changeRadius(arc, 400);
// }
return arc;
},

File diff suppressed because one or more lines are too long

201
js/controls.js vendored

@ -1,122 +1,187 @@
import Rx, { Observable } from 'rxjs';
import { CONTROLS } from './enums';
function Controls(container, { animating, count, maxCount, speed }, customNodes) {
this.nodes = {
animating: createAnimatingControl(animating),
count: createCountControl(count, maxCount),
speed: createSpeedControl(speed),
}
container.appendChild(this.nodes.count);
container.appendChild(this.nodes.speed);
if (customNodes !== undefined) {
customNodes.forEach(node => { container.appendChild(node); });
}
container.appendChild(this.nodes.animating);
this.updateOptions({ key: CONTROLS.ANIMATING, value: animating });
this.updateOptions({ key: CONTROLS.COUNT, value: count });
this.updateOptions({ key: CONTROLS.SPEED, value: speed });
export default function(destroy$, {
count = 1,
id,
maxCount = 10,
showCircleControl = false,
showRandomizeControl = false
}) {
const container = document.createElement('div');
container.className = 'controlsContainer';
container.id = `controls${id}`;
document.getElementById(id).appendChild(container);
const observables = {
count$: createCountControl(container, 0, maxCount),
speed$: createSpeedControl(container),
circle$: showCircleControl ? createCircleControl(container) : undefined,
randomize$: showRandomizeControl ? createRandomizeControl(container) : undefined,
animating$: createAnimatingControl(container),
};
observables.animating$.subscribe((isAnimating) => {
if (isAnimating === true) {
destroy$.next(id);
if (observables.count$.getValue() === 0) {
observables.count$.next(count);
}
}
});
destroy$.subscribe((sourceId) => {
if (id !== sourceId) {
observables.animating$.next(false);
observables.count$.next(0);
}
});
return observables;
}
Controls.prototype.updateOptions = function({ key, value}) {
if (key === CONTROLS.COUNT) {
this.nodes.count.querySelector('span').innerHTML =
(value == 1) ? '1 particle' : `${value} particles`;
}
if (key === CONTROLS.SPEED) {
this.nodes.speed.querySelector('span').innerHTML =
`Speed: ${value}`;
}
if (key === CONTROLS.ANIMATING) {
this.nodes.animating.querySelector('span').innerHTML =
(value ? '&#9724; Stop' : '&#9654; Start');
}
}
Controls.prototype.mount = function(customNodes) {
const animating$ = Rx.Observable.fromEvent(this.nodes.animating, 'change')
.map(evt => ({ key: CONTROLS.ANIMATING, value: evt.target.checked }));
const count$ = Rx.Observable.fromEvent(this.nodes.count, 'input')
.map(evt => ({ key: CONTROLS.COUNT, value: evt.target.value * 1 }));
const speed$ = Rx.Observable.fromEvent(this.nodes.speed, 'input')
.map(evt => ({ key: CONTROLS.SPEED, value: evt.target.value * 1 }));
const eventStack$ = Rx.Observable.merge(
animating$,
count$,
speed$
);
eventStack$.subscribe(this.updateOptions.bind(this));
return eventStack$;
}
function createAnimatingControl(value) {
function createAnimatingControl(container) {
const label = document.createElement('label');
label.className = 'controls-label';
label.className = 'controls-animating';
const text = document.createElement('span');
text.innerHTML = '...';
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.checked = value;
checkbox.checked = false;
label.appendChild(checkbox);
label.appendChild(text);
return label;
container.appendChild(label);
const animating$ = new Rx.BehaviorSubject(false);
label.addEventListener('change', (evt) => {
animating$.next(evt.target.checked);
});
animating$.subscribe((isAnimating) => {
text.innerHTML = (isAnimating ? '&#9724; Stop' : '&#9654; Start');
checkbox.checked = isAnimating;
});
return animating$;
}
function createCountControl(value, max) {
function createCountControl(container, initialValue, max) {
const label = document.createElement('label');
label.className = 'controls-range';
const text = document.createElement('span');
text.innerHTML = '...';
text.innerHTML = (initialValue == 1) ? '1 particle' : `${initialValue} particles`;
text.className = 'controls-range-text';
const slider = document.createElement('input');
slider.type = 'range';
slider.min = 1;
slider.max = max;
slider.value = value;
slider.value = initialValue;
slider.className = 'controls-range-input';
label.appendChild(text);
label.appendChild(slider);
return label;
container.appendChild(label);
const count$ = new Rx.BehaviorSubject(initialValue);
label.addEventListener('input', (evt) => {
count$.next(evt.target.value * 1);
});
count$.subscribe((value) => {
text.innerHTML = (value == 1) ? '1 particle' : `${value} particles`;
});
return count$;
}
function createSpeedControl(value) {
function createSpeedControl(container) {
const label = document.createElement('label');
label.className = 'controls-range';
const text = document.createElement('span');
text.className = 'controls-range-text';
text.innerHTML = 'Speed: 0';
const slider = document.createElement('input');
slider.type = 'range';
slider.min = 1;
slider.max = 15;
slider.value = value;
slider.value = 4;
slider.className = 'controls-range-input';
label.appendChild(text);
label.appendChild(slider);
return label;
container.appendChild(label);
const speed$ = new Rx.BehaviorSubject(slider.value);
label.addEventListener('input', (evt) => {
speed$.next(evt.target.value * 1);
});
speed$.subscribe((value) => {
text.innerHTML = `Speed: ${value}`;
});
return speed$;
}
export default Controls;
function createCircleControl(container) {
const label = document.createElement('label');
label.className = 'controls-checkbox';
const text = document.createElement('span');
text.innerHTML = 'Show movement circle';
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 circle$ = Rx.Observable.fromEvent(label, 'change')
.map(evt => evt.target.checked);
return circle$;
}
function createRandomizeControl(container) {
const label = document.createElement('label');
label.className = 'controls-checkbox';
const text = document.createElement('span');
text.innerHTML = 'Randomize movement';
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 circle$ = Rx.Observable.fromEvent(label, 'change')
.map(evt => evt.target.checked);
return randomize$;
}

@ -8,8 +8,8 @@ const RAD = {
const CONTROLS = {
ANIMATING: 'animating',
CIRCLE: 'circle',
COUNT: 'count',
MOVEMENT_CIRCLE: 'movementCircle',
RANDOMIZE: 'randomize',
SPEED: 'speed'
};

@ -1,10 +1,10 @@
import Rx, { Observable } from 'rxjs';
import Controls from './controls';
import Animation1a from './animation1a';
import Animation1b from './animation1b';
import Animation2a from './animation2a';
import Animation2b from './animation2b';
import Animation3a from './animation3a';
// import Container1b from './container1b';
// import Container2a from './container2a';
// import Container2b from './container2b';
// import Container3a from './container3a';
require('../css/reset.scss');
require('../css/index.scss');
@ -12,9 +12,21 @@ require('../css/particle.scss');
require('../css/controls.scss');
window.addEventListener('load', () => {
new Animation1a();
// new Animation1b();
// new Animation2a();
// new Animation2b();
// new Animation3a();
const destroy$ = new Rx.BehaviorSubject(null);
Animation1a(destroy$);
Animation1b(destroy$);
});
// TODO remove bottom padding from Disqus
// TODO fix "hangup" small radius evade bug
// TODO don't load simulation until requested
// TODO sort out particle nextframe
// TODO subscriber on bounds change
// TODO abs positioning on controls elements so order doesn't matter
// TODO ANIM1ab free movement
// TODO ANIM3a streamline updateLeader
// TODO ANIM3b separation
// TODO ANIM3c alignment

@ -3,20 +3,24 @@ import { BEHAVIOR, ENTITIES, RAD } from './enums';
import Arc from './arc';
import Random from './random';
const baseConfig = {
behavior: BEHAVIOR.COHESION,
bounds: {},
color: 'red',
gridSize: 5,
randomize: true,
showArc: false,
showVision: false,
speed: 4,
visionRadius: 50
};
// ===== Constructor =====
function Particle(parent, bounds, config, globalGrid) {
this.config = Object.assign({}, {
behavior: BEHAVIOR.COHESION,
bounds,
color: Random.color(),
gridSize: 5,
randomize: true,
showMovementCircle: false,
showVisionGrid: false,
speed: 4,
visionRadius: 50
}, config);
this.config = Object.assign({}, baseConfig, config);
this.config.color = Random.color();
// this.config.bounds = bounds;
this.grids = {
global: globalGrid || {},
@ -29,7 +33,6 @@ function Particle(parent, bounds, config, globalGrid) {
body: createBodyNode(this.config),
circle: undefined,
container: createContainerNode(this.config, this.id),
parent,
visionGrid: undefined,
};
@ -40,40 +43,35 @@ function Particle(parent, bounds, config, globalGrid) {
this.isLeader = false;
this.arc = Arc.create(bounds, this.grids.global);
console.error('starting', this.arc)
this.updateConfig(this.config);
this.nextFrame(globalGrid);
const point = document.createElement('div');
point.style.height = '10px'
point.style.width = '10px'
point.style.background = 'red'
point.style.position = 'absolute'
point.style.left = '200px'
point.style.top = '200px'
this.nodes.parent.appendChild(point);
// this.updateConfig(this.config);
// this.grids.global.setPoint({ x: p.arc.endX, y: p.arc.endY, type: ENTITIES.PARTICLE }, p);
// this.nextFrame(globalGrid);
};
// ===== PROTOTYPE =====
Particle.prototype.remove = function() {
this.nodes.parent.removeChild(this.nodes.container);
// this.grids.globals.deletePoint({ x: p.arc.endX, y: p.arc.endY, type: ENTITIES.PARTICLE });
const parent = this.nodes.container.parentNode;
parent.removeChild(this.nodes.container);
delete this.nodes;
return this;
}
Particle.prototype.nextFrame = function() {
this.arc = Arc.goto(this.arc, 200, 200, this.config.speed)
// this.arc = Arc.goto(this.arc, 200, 200, this.config.speed)
this.arc = Arc.step(this.arc, this.config.bounds, this.config.speed);
// if (this.leader !== null) {
// this.arc = Arc.follow(this.arc, this.leader.arc);
// } else if (this.arc.length <= 0 && this.config.randomize) {
// this.arc = Arc.randomize(this.arc);
// }
//
if (this.leader !== null) {
this.arc = Arc.follow(this.arc, this.leader.arc);
} else if (this.arc.length <= 0 && this.config.randomize) {
this.arc = Arc.randomize(this.arc);
}
// this.grids.vision = updateVisionGrid(this.arc, this.config, this.grids);
// const { hazards, particles } = look(this.arc, this.grids);
//
@ -89,28 +87,32 @@ Particle.prototype.nextFrame = function() {
repaintVisionGrid(this.nodes.visionGrid, this.arc, this.grids);
}
Particle.prototype.updateConfig = function(config) {
Object.assign(this.config, config);
const { showMovementCircle, showVisionGrid } = this.config;
if (showMovementCircle === true && this.nodes.circle === undefined) {
this.nodes.circle = createCircleNode(config);
this.nodes.container.appendChild(this.nodes.circle);
}
if (showMovementCircle === false && this.nodes.circle !== undefined) {
this.nodes.container.removeChild(this.nodes.circle);
delete this.nodes.circle;
}
Particle.prototype.subscriber = function({ key, value }) {
if (showVisionGrid === true && this.nodes.visionGrid === undefined) {
this.nodes.visionGrid = createVisionGridNodes(this.config, this.grids, this.nodes);
}
}
if (showVisionGrid === false && this.nodes.visionGrid !== undefined) {
delete this.nodex.visionGrid;
}
Particle.prototype.updateConfig = function(config) {
// Object.assign(this.config, config);
//
// const { showArc, showVision } = this.config;
//
// if (showArc === true && this.nodes.circle === undefined) {
// this.nodes.circle = createCircleNode(this.config);
// this.nodes.container.appendChild(this.nodes.circle);
// }
//
// if (showArc === false && this.nodes.circle !== undefined) {
// this.nodes.container.removeChild(this.nodes.circle);
// delete this.nodes.circle;
// }
//
// 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.updateLeader = function(particles) {
@ -184,7 +186,7 @@ function createBodyNode(config) {
}
function createCircleNode(config) {
if (config.showMovementCircle === false) {
if (config.showArc === false) {
return undefined;
}
@ -234,7 +236,7 @@ function createVisionGrid(config) {
}
function createVisionGridNodes(config, grids, nodes) {
if (config.showVisionGrid === false) {
if (config.showVision === false) {
return undefined;
}

@ -1,10 +1,6 @@
const random = {
bool: (weight) => Math.random() < (weight || 0.5),
color: () => `rgb(
${Math.floor(Math.random() * 230)},
${Math.floor(Math.random() * 230)},
${Math.floor(Math.random() * 230)}
)`,
color: () => `rgb(${Math.floor(Math.random() * 230)}, ${Math.floor(Math.random() * 230)}, ${Math.floor(Math.random() * 230)})`,
id: () => String.fromCharCode(
random.num(65, 90), random.num(97, 122), random.num(97, 122),
random.num(97, 122), random.num(97, 122), random.num(97, 122)

Loading…
Cancel
Save