parent
545c632300
commit
5e74dc90af
18 changed files with 1600 additions and 2069 deletions
@ -1,13 +0,0 @@ |
||||
.anim2-particle { |
||||
$side: 100px; |
||||
|
||||
background: url('../res/seahorse.svg') no-repeat center center; |
||||
background-size: 20px 20px; |
||||
border-color: salmon; |
||||
border-style: dashed; |
||||
border-radius: 50px; |
||||
border-width: 1px; |
||||
height: $side; |
||||
position: absolute; |
||||
width: $side; |
||||
} |
@ -1,20 +0,0 @@ |
||||
.anim3-particle { |
||||
$side: 20px; |
||||
|
||||
background: url('../res/seahorse.svg') no-repeat center top #aaa; |
||||
background-size: 20px 20px; |
||||
border-color: purple; |
||||
color: #fff; |
||||
// border-style: dashed; |
||||
border-radius: $side / 2; |
||||
// border-width: 1px; |
||||
height: $side; |
||||
line-height: $side; |
||||
position: absolute; |
||||
text-align: center; |
||||
width: $side; |
||||
|
||||
&.scared { |
||||
background: #f00; |
||||
} |
||||
} |
@ -1,6 +0,0 @@ |
||||
const Animation0 = { |
||||
init: () => { console.error('init() not implemented.'); }, |
||||
reset: () => { console.error('reset() not implemented.'); }, |
||||
}; |
||||
|
||||
export default Animation0; |
@ -1,33 +1,58 @@ |
||||
// Simple frame-based movement.
|
||||
import Rx, { Observable } from 'rxjs'; |
||||
import Particle from './particle'; |
||||
import Store from './store'; |
||||
|
||||
const Animation1 = { |
||||
// const particleDivs = [];
|
||||
//
|
||||
// const instanceCount = Rx.Observable.range(0, 3);
|
||||
//
|
||||
// const createDivs = instanceCount.subscribe((i) => {
|
||||
// console.warn("creating divs")
|
||||
// const container = document.querySelector('.particles');
|
||||
// const div = document.createElement('div');
|
||||
// div.className = 'particle';
|
||||
// div.style.top = `${i * 75}px`;
|
||||
// div.style.left = 0;
|
||||
//
|
||||
// container.appendChild(div);
|
||||
// particleDivs.push(div);
|
||||
// });
|
||||
//
|
||||
// Rx.Observable
|
||||
// .interval(1000 / 32)
|
||||
// .do(frameIndex => {
|
||||
// instanceCount.subscribe(i => {
|
||||
// particleDivs[i].style.left = `${frameIndex * 10}px`;
|
||||
// });
|
||||
// // particleDivs.do(div => { div.style.left = `${n * 75}px`; }).subscribe();
|
||||
// })
|
||||
// .take(16)
|
||||
// .subscribe(console.info)
|
||||
function Animation1(node) { |
||||
this.container = node; |
||||
this.bounds = node.getBoundingClientRect(); |
||||
} |
||||
|
||||
// const grid = {};
|
||||
// for (let x = 0; x <= 600; x += 5) {
|
||||
// grid[x] = {};
|
||||
// for (let y = 0; y <= 600; y += 5) {
|
||||
// grid[x][y] = { type: null };
|
||||
//
|
||||
// if (x === 0 || y === 0 || x === 600 || y === 600) {
|
||||
// grid[x][y] = { type: 'wall' };
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
Animation1.prototype.nextFrame = function() { |
||||
this.particles.forEach(p => p.nextFrame()); |
||||
} |
||||
|
||||
Animation1.prototype.reset = () => { |
||||
// while (DOM.container.childNodes.length) {
|
||||
// DOM.container.removeChild(DOM.container.firstChild);
|
||||
// }
|
||||
}; |
||||
|
||||
Animation1.prototype.init = function() { |
||||
this.particles = Array(1).fill().map(_ => new Particle(this.container, this.bounds)); |
||||
|
||||
const stop$ = Rx.Observable.fromEvent(this.container, 'stop'); |
||||
|
||||
// Change animation speed
|
||||
// Change animal pic
|
||||
// Enable random radius changes
|
||||
// Enable random rotation changes
|
||||
// Show movement circle
|
||||
// Show vision grid (including touches!)
|
||||
// Start / stop
|
||||
|
||||
console.error("Click container to stop."); |
||||
const fps$ = Rx.Observable.interval(1000 / 32) |
||||
.takeUntil(stop$) |
||||
.finally(() => { console.error("Stopped."); }) |
||||
|
||||
const click$ = Rx.Observable.fromEvent(this.container, 'click'); |
||||
click$.subscribe(() => { |
||||
this.container.dispatchEvent(new CustomEvent('stop')); |
||||
}); |
||||
|
||||
fps$.subscribe(this.nextFrame.bind(this)); |
||||
} |
||||
|
||||
export default Animation1; |
||||
|
@ -1,117 +0,0 @@ |
||||
// Join mechanic, multiple particles.
|
||||
// Goal: per-frame decisions
|
||||
// 20 x 20 grid
|
||||
import Rx, { Observable } from 'rxjs'; |
||||
import AnimationBase from './animation0'; |
||||
import DOM from './dom'; |
||||
import Store from './store'; |
||||
//
|
||||
// const evtScare = (detail) => new CustomEvent('scare', { detail });
|
||||
// const evtMove = (detail) => new CustomEvent('move', { detail });
|
||||
//
|
||||
// const [particles, state] = (new Array(5)).fill(null).reduce((acc, v, i) => {
|
||||
// // const div = document.createElement('div');
|
||||
// // div.className = 'anim3-particle';
|
||||
// // div.innerHTML = ''
|
||||
// //
|
||||
// // const x = 0;
|
||||
// // const y = i * 20;
|
||||
// //
|
||||
// // div.style.left = 0
|
||||
// // div.style.top = `${y}px`;
|
||||
// //
|
||||
// // acc[0].push(div);
|
||||
// // acc[1].push({ x, y });
|
||||
// //
|
||||
// // acc[1][`${x}-${y}`] = { occupied: true, type: 'palette', x, y, i };
|
||||
// //
|
||||
// // return acc;
|
||||
// }, [[], []]);
|
||||
//
|
||||
// const palettes = (new Array(1)).fill(null).reduce((acc, v, i) => {
|
||||
// const initialX = 200;
|
||||
// const initialY = 200;
|
||||
// const w = 167;
|
||||
// const h = 100;
|
||||
// const maxX = initialX + w;
|
||||
// const maxY = initialY + h;
|
||||
// const s = 20;
|
||||
//
|
||||
// for (let y = initialY; y < maxY; y += s) {
|
||||
// for (let x = initialX; x < maxX; x += s) {
|
||||
// state[`${x}-${y}`] = { occupied: true, type: 'palette', i };
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// const div = document.createElement('div');
|
||||
// div.className = 'palette';
|
||||
// div.style.left = `${initialX}px`;
|
||||
// div.style.top = `${initialY}px`;
|
||||
//
|
||||
// acc.push(div);
|
||||
//
|
||||
// return acc;
|
||||
// }, []);
|
||||
//
|
||||
// function scare(evt) {
|
||||
// const bounds = DOM.container.getBoundingClientRect();
|
||||
// const { evtX: x, evtY: y } = DOM.getEventOffsetCoords(evt, bounds);
|
||||
// const scareRadius = 50;
|
||||
//
|
||||
// state.forEach((coord, i) => {
|
||||
// const diffX = Math.abs(coord.x - x + 10);
|
||||
// const diffY = Math.abs(coord.y - y + 10);
|
||||
//
|
||||
// if (diffX < scareRadius && diffY < scareRadius) {
|
||||
// coord.lastScare = { x, y } // TODO set state with last scare, then judge per frame based on that number to avoid jump
|
||||
// DOM.container.dispatchEvent(evtScare({ x, y, i }));
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// function move(evt) {
|
||||
//
|
||||
// }
|
||||
//
|
||||
// function flee(evt) {
|
||||
// particles[evt.detail.i].innerHTML = 'S'
|
||||
// DOM.addClass(particles[evt.detail.i], 'scared');
|
||||
// const p = particles[evt.detail.i];
|
||||
// DOM.container.dispatchEvent(evtMove(evt.detail));
|
||||
//
|
||||
// setTimeout(() => {
|
||||
// p.innerHTML = '';
|
||||
// DOM.removeClass(p, 'scared');
|
||||
// }, 1000);
|
||||
// }
|
||||
//
|
||||
function reset() { |
||||
// while (DOM.container.childNodes.length) {
|
||||
// DOM.container.removeChild(DOM.container.firstChild);
|
||||
// }
|
||||
//
|
||||
// particles.forEach((div) => {
|
||||
// div.innerHTML = '';
|
||||
// DOM.container.appendChild(div)
|
||||
// });
|
||||
//
|
||||
// palettes.forEach((div) => {
|
||||
// DOM.container.appendChild(div)
|
||||
// });
|
||||
}; |
||||
|
||||
function init() { |
||||
// reset();
|
||||
//
|
||||
// const click$ = Rx.Observable.fromEvent(DOM.container, 'click');
|
||||
// const scare$ = Rx.Observable.fromEvent(DOM.container, 'scare').auditTime(100);
|
||||
// const move$ = Rx.Observable.fromEvent(DOM.container, 'move');
|
||||
//
|
||||
// click$.subscribe(scare);
|
||||
// scare$.subscribe(flee);
|
||||
// move$.subscribe(console.info);
|
||||
}; |
||||
|
||||
const Animation5 = Object.assign({}, AnimationBase, { init, reset }); |
||||
|
||||
export default Animation5; |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,23 @@ |
||||
function Controls(node, animation) { |
||||
this.node = node; |
||||
this.animation = new animation(node); |
||||
|
||||
if (this.animation.init === undefined) { |
||||
console.error("Animation passed to Control doesn't have an init() method."); |
||||
} |
||||
|
||||
if (this.animation.reset === undefined) { |
||||
console.error("Animation passed to Control doesn't have a reset() method."); |
||||
} |
||||
|
||||
this.animation.init(); |
||||
} |
||||
|
||||
Controls.prototype.mount = function() { |
||||
// this.node.style.border = '10px solid purple'; WORKING
|
||||
|
||||
// right aligned panel, pass in extra custom controls array of nodes
|
||||
// set of prescribed styles
|
||||
} |
||||
|
||||
export default Controls; |
@ -0,0 +1,9 @@ |
||||
const RAD = { |
||||
t45: Math.PI / 4, |
||||
t90: Math.PI / 2, |
||||
t180: Math.PI, |
||||
t270: 3 * Math.PI / 2, |
||||
t360: Math.PI * 2 |
||||
}; |
||||
|
||||
export { RAD }; |
@ -0,0 +1,171 @@ |
||||
import Rx, { Observable } from 'rxjs'; |
||||
// import DOM from './dom';
|
||||
import { RAD } from './enums'; |
||||
import Store from './store'; |
||||
|
||||
const random = { |
||||
bool: () => Math.random() < 0.5, |
||||
num: (min, max) => min + Math.round(Math.random() * max) |
||||
} |
||||
|
||||
function moveArc(arc, newRadius) { |
||||
const r0 = arc.r; |
||||
const r1 = newRadius; |
||||
|
||||
// Moves arc center to new radius while keeping theta constant.
|
||||
arc.x -= (r1 - r0) * Math.cos(arc.t); |
||||
arc.y += (r1 - r0) * Math.sin(arc.t); |
||||
arc.r = r1; |
||||
|
||||
return arc; |
||||
} |
||||
|
||||
function changeDirection(arc) { |
||||
arc.t = (arc.t + Math.PI) % RAD.t360; |
||||
arc.x -= (2 * arc.r) * Math.cos(arc.t); |
||||
arc.y += (2 * arc.r) * Math.sin(arc.t); |
||||
|
||||
return arc; |
||||
} |
||||
|
||||
// function transformVisionGrid(store) {
|
||||
// const {
|
||||
// arc,
|
||||
// clockwise,
|
||||
// particle.x,
|
||||
// particle.y,
|
||||
// radius,
|
||||
// } = store.get();
|
||||
//
|
||||
// const r0 = Math.min(arc.t, arc.t - Math.PI);
|
||||
// const r1 = Math.max(arc.t, arc.t + Math.PI);
|
||||
//
|
||||
// const gridX = particle.x - particle.x % 5;
|
||||
// const gridY = particle.y - particle.y % 5;
|
||||
//
|
||||
// visionGridPoints.forEach(({ x, y, alpha, div }, i) => {
|
||||
// if (alpha >= 0 && alpha <= r0) {
|
||||
// div.style.display = (clockwise ? 'none' : 'block');
|
||||
// // div.className = (clockwise ? 'anim3-dot removed' : 'anim3-dot');
|
||||
// } else if (alpha >= arc.t && alpha <= r1) {
|
||||
// div.style.display = (clockwise ? 'none' : 'block');
|
||||
// // div.className = (clockwise ? 'anim3-dot removed' : 'anim3-dot');
|
||||
// } else {
|
||||
// div.style.display = (clockwise ? 'block' : 'none');
|
||||
// // div.className = (clockwise ? 'anim3-dot' : 'anim3-dot removed');
|
||||
// }
|
||||
//
|
||||
// div.style.left = `${x + gridX}px`;
|
||||
// div.style.top = `${-y + gridY}px`;
|
||||
// });
|
||||
// }
|
||||
//
|
||||
|
||||
function Particle(container, bounds, options = {}) { |
||||
this.container = container; |
||||
this.bounds = bounds; |
||||
|
||||
this.node = document.createElement('div'); |
||||
this.node.className = 'particle has-vision'; |
||||
|
||||
this.circle = document.createElement('div'); |
||||
this.circle.className = 'particle-movement-circle'; |
||||
|
||||
this.container.appendChild(this.node); |
||||
this.container.appendChild(this.circle); |
||||
|
||||
this.arc = { |
||||
r: random.num(100, 200), |
||||
t: random.num(0, RAD.t360), |
||||
x: random.num(0, bounds.width), |
||||
y: random.num(0, bounds.height) |
||||
} |
||||
|
||||
this.particle = { |
||||
clockwise: random.bool(), |
||||
speed: 4, |
||||
x: 0, |
||||
y: 0 |
||||
} |
||||
|
||||
this.interval = 0; |
||||
|
||||
this.updateOptions(options); |
||||
this.nextFrame(); |
||||
|
||||
}; |
||||
|
||||
Particle.prototype.nextFrame = function() { |
||||
this.move(); |
||||
this.repaintParticle(); |
||||
this.repaintCircle(); |
||||
} |
||||
|
||||
Particle.prototype.updateOptions = function(options) { |
||||
this.particleImage = 'seahorse'; |
||||
this.randomlyChangeRadius = (new Boolean(options.randomlyChangeRadius)) || true; |
||||
this.randomlyChangeRotation = (new Boolean(options.randomlyChangeRotation)) || true; |
||||
this.showCircle = (new Boolean(options.showCircle)) || false; |
||||
this.showVision = (new Boolean(options.showVision)) || false; |
||||
} |
||||
|
||||
Particle.prototype.repaintParticle = function() { |
||||
const rad = this.particle.clockwise |
||||
? RAD.t180 - this.arc.t |
||||
: RAD.t360 - this.arc.t; |
||||
|
||||
this.node.style.left = `${this.particle.x}px`; |
||||
this.node.style.top = `${this.particle.y}px`; |
||||
this.node.style.transform = `rotate(${rad}rad)`; |
||||
} |
||||
|
||||
Particle.prototype.repaintCircle = function() { |
||||
this.circle.style.width = `${2 * this.arc.r}px`; |
||||
this.circle.style.height = `${2 * this.arc.r}px`; |
||||
this.circle.style.left = `${this.arc.x - this.arc.r}px`; |
||||
this.circle.style.top = `${this.arc.y - this.arc.r}px`; |
||||
|
||||
this.circle.style.borderRadius = `${this.arc.r}px`; |
||||
} |
||||
|
||||
Particle.prototype.move = function(store) { |
||||
// Randomly change radius and rotation direction.
|
||||
this.interval -= 1; |
||||
if (this.interval <= 0) { |
||||
this.interval = random.num(50, 100); |
||||
this.arc = moveArc(this.arc, random.num(100, 200)); |
||||
|
||||
if (random.bool()) { |
||||
this.particle.clockwise = !this.particle.clockwise; |
||||
this.arc = changeDirection(this.arc); |
||||
} |
||||
} |
||||
|
||||
// Ensure constant velocity and theta between 0 and 2π.
|
||||
const delta = this.particle.speed / this.arc.r; |
||||
this.arc.t += (this.particle.clockwise ? -delta : +delta); |
||||
this.arc.t = (this.arc.t > 0 ? this.arc.t % RAD.t360 : RAD.t360 - this.arc.t); |
||||
|
||||
this.particle.x = this.arc.x + this.arc.r * Math.cos(this.arc.t); |
||||
this.particle.y = this.arc.y - this.arc.r * Math.sin(this.arc.t); |
||||
|
||||
// Overflow.
|
||||
if (this.particle.x < 0) { |
||||
this.particle.x += this.bounds.width; |
||||
this.arc.x += this.bounds.width |
||||
} else if (this.particle.x > this.bounds.width) { |
||||
this.particle.x -= this.bounds.width; |
||||
this.arc.x -= this.bounds.width |
||||
} |
||||
|
||||
if (this.particle.y < 0) { |
||||
this.particle.y += this.bounds.height; // TODO size of area
|
||||
this.arc.y += this.bounds.height |
||||
} else if (this.particle.y > this.bounds.height) { |
||||
this.particle.y -= this.bounds.height; |
||||
this.arc.y -= this.bounds.height |
||||
} |
||||
} |
||||
|
||||
|
||||
export default Particle; |
Loading…
Reference in new issue