// Scare mechanic, single particle. import Rx, { Observable } from 'rxjs'; import AnimationBase from './animation0'; import DOM from './dom'; import Store from './store'; const evtScare = (scareX, scareY) => new CustomEvent("scare", { detail: { scareX, scareY } }); const particleDiv = document.createElement('div'); particleDiv.className = 'anim2-particle'; function checkScare([evt, store]) { const state = store.get(); const { evtX, evtY } = DOM.getEventOffsetCoords(evt, DOM.containerBounds); const diffX = Math.abs(state.x - evtX); const diffY = Math.abs(state.y - evtY); if (evt.target === particleDiv) { DOM.container.dispatchEvent(evtScare(evtX, evtY)); } }; function move(acc, i) { let { x, y, dx, dy } = acc; const east = DOM.containerBounds.width - particleDiv.offsetWidth; const south = DOM.containerBounds.height - particleDiv.offsetHeight; x += dx; y += dy; if (x < 0) { x = Math.abs(x); dx = -dx; } if (x > east) { x = Math.round(2 * east - x); dx = -dx; } if (y < 0) { y = Math.abs(y); dy = -dy; } if (y > south) { y = Math.round(2 * south - y); dy = -dy; } return { x, y, dx, dy }; }; function flee([evt, store]) { const initialState = store.get(); const fleeRadius = 200; const { scareX, scareY } = evt.detail; const fps$ = Rx.Observable.interval(1000 / 32); const frames$ = fps$ .scan(move, initialState) .takeWhile(state => { const xDanger = Math.abs(initialState.x - state.x) < fleeRadius; const yDanger = Math.abs(initialState.y - state.y) < fleeRadius; return xDanger && yDanger; }) frames$.last().subscribe(finalState => { store.set(finalState); store.set(randomMoveVector()); }); frames$.subscribe(state => { particleDiv.style.left = `${state.x}px`; particleDiv.style.top = `${state.y}px`; }); }; function randomMoveVector() { const speed = 10; let dx = Math.round(Math.random() * speed); let dy = Math.pow(Math.pow(speed, 2) - Math.pow(dx, 2), 0.5); const negX = Math.random() < 0.5 ? -1 : 1; const negY = Math.random() < 0.5 ? -1 : 1; dx *= negX; dy *= negY; return { dx, dy }; } function reset() { if (particleDiv.parentNode) { DOM.container.removeChild(particleDiv); } const { dx, dy } = randomMoveVector(); const store = new Store({ x: 0, y: 0, dx, dy }); const state = store.get(); particleDiv.style.top = `${state.y}px`; particleDiv.style.left = `${state.x}px`; DOM.container.appendChild(particleDiv); return store; }; function init() { const store = reset(); const click$ = Rx.Observable .fromEvent(DOM.container, 'click') // .do(DOM.calcBounds) .do(DOM.highlight) .map(evt => [evt, store]) .subscribe(checkScare); Rx.Observable .fromEvent(DOM.container, 'scare') .map(evt => [evt, store]) .subscribe(flee); }; const Animation2 = Object.assign({}, AnimationBase, { init, reset }); export default Animation2;