You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

131 lines
3.1 KiB

// 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;