diff --git a/js/effects.js b/js/effects.js new file mode 100644 index 0000000..4536b97 --- /dev/null +++ b/js/effects.js @@ -0,0 +1,158 @@ + +/* +The interface is like a flywheel. +*/ +export class Flywheel { + constructor() { + this.value = 0.; // start at 0 - gradual meter + this.stage = 0.; // start at 0 - the various stages + + this.f_falloff = (value) => value / 20; // value at which it reduces per second + this.f_stage = (value) => 5 * Math.log10(value); // value to stage calculation + + this.value_min = 0; + this.value_max = 100; // gives stage 0-9 + + // this.interval = window.setInterval(this.step, 50) + this.time = null; + window.requestAnimationFrame(this.step.bind(this)); + // TODO: once/twice per second should be enough! + on release (add()) + + this.effects = { + 'shape': new ShapeEffect(), + 'video': new VideoEffect(), + } + } + + step(time) { + if (this.time === null) { + // first run + this.time = time; + window.requestAnimationFrame(this.step.bind(this)); + return; + } + + if (time - this.time < 500) { + window.requestAnimationFrame(this.step.bind(this)); + return; + } + + const dt = time - this.time; + this.time = time; + + this.value -= this.f_falloff(this.value) * dt / 1000; // linear falloff + + if (this.value < 0) { + this.value = 0; + } + // console.log(this.value,this.falloff, dt,this.time); + + // TODO: check if this should be different + + const stage = Math.max(0, Math.floor(this.f_stage(this.value))); + if (stage != this.stage) { + this.changeStage(stage); + } + + window.requestAnimationFrame(this.step.bind(this)); + } + + add(increment) { + this.value += typeof increment == 'undefined' ? 1 : increment; + // cap: + if (this.value > this.value_max) this.value = this.value_max; + } + + changeStage(stage) { + this.stage = stage; + console.log('stage now at', this.stage); + for (let fx of Object.values(this.effects)) { + fx.setStageHandler(this.stage); + } + } +} + +function effect(start_stage, end_stage) { + return class Effect { + constructor() { + this.enabled = false; + this.start_stage = start_stage; + this.end_stage = end_stage; + this.intensity = 0; + this.intensity_easing = (t) => t; // 0 < t <= 1: use this to make effect eg. more eased + } + + setStageHandler(stage) { + if (stage < this.start_stage || stage > this.end_stage) { + this.disable(stage); + } else { + this.enable(stage); + } + } + + enable(stage) { + if (!this.enabled) { + this.enabled = true; + this.enableHandler(); + } + + const ds = this.end_stage - this.start_stage + 1; + if (ds === 1) { + this.setIntensity(1); + } else { + const s = stage - this.start_stage + 1; + const t = s / ds; + this.setIntensity(this.intensity_easing(t)); + } + } + + disable(stage) { + if (this.enabled) { + this.enabled = false; + this.disableHandler(); + } + } + + setIntensity(intensity) { + if (intensity !== this.intensity) { + this.intensity = intensity; + this.intensityHandler(); + } + } + + enableHandler() {/* to override */ } + disableHandler() {/* to override */ } + intensityHandler() {/* to override */ } + } + + +} + +class ShapeEffect extends effect(3, 10) { + getAngles() { + if (!this.enabled) { + return 4; + } + if (this.intensity < .3) { + return 3; + } else if (this.intensity < .7) { + return 5; + } else { + // random pick + const corners = [3, 4, 5, 7] + return corners[Math.floor(Math.random() * corners.length)]; + } + } +} +class VideoEffect extends effect(3, 10) { + // override enable instead of using handler to apply it gradually + disableHandler() { + document.getElementById('video_background').style.opacity = 0; + } + + intensityHandler() { + document.getElementById('video_background').style.opacity = this.intensity; + } + + +} \ No newline at end of file diff --git a/js/flywheel.js b/js/flywheel.js deleted file mode 100644 index 4e981a1..0000000 --- a/js/flywheel.js +++ /dev/null @@ -1,66 +0,0 @@ - - /* - The interface is like a flywheel. - */ - export class Flywheel{ - constructor() { - this.value = 0.; // start at 0 - gradual meter - this.stage = 0.; // start at 0 - the various stages - - this.f_falloff = (value) => value/20; // value at which it reduces per second - this.f_stage = (value) => 5*Math.log10(value); // value to stage calculation - - this.value_min = 0; - this.value_max = 100; // gives stage 0-9 - - // this.interval = window.setInterval(this.step, 50) - this.time = null; - window.requestAnimationFrame(this.step.bind(this)); - // TODO: once/twice per second should be enough! + on release (add()) - } - - step(time){ - if(this.time === null){ - // first run - this.time = time; - window.requestAnimationFrame(this.step.bind(this)); - return; - } - - if(time-this.time < 500){ - window.requestAnimationFrame(this.step.bind(this)); - return; - } - - const dt = time - this.time; - this.time = time; - - this.value -= this.f_falloff(this.value) * dt/1000; // linear falloff - - if(this.value < 0){ - this.value = 0; - } - // console.log(this.value,this.falloff, dt,this.time); - - // TODO: check if this should be different - - const stage = Math.max(0,Math.floor(this.f_stage(this.value))); - if (stage != this.stage){ - this.changeStage(stage); - } - - window.requestAnimationFrame(this.step.bind(this)); - } - - add(increment){ - this.value += typeof increment == 'undefined' ? 1 : increment; - // cap: - if(this.value > this.value_max) this.value = this.value_max; - } - - changeStage(stage){ - this.stage = stage; - console.log('stage now at', this.stage); - // TODO: handle stage change - } -} \ No newline at end of file diff --git a/js/game.js b/js/game.js index f8237bb..7e1a79e 100644 --- a/js/game.js +++ b/js/game.js @@ -1,19 +1,16 @@ -import { Flywheel } from "./flywheel.js"; +import { Flywheel } from "./effects.js"; import { getPathShapeBetweenPoints } from "./svg.js"; export function init(svgEl, crosshairXEl, crosshairYEl) { let flywheel = new Flywheel(); - + // use ?3 and ?4 ?28 etc in query string to determine segments const segmentCount = window.location.search.substr(1).length ? window.location.search.substr(1) : 4; // canvas position relative to mouse/screen // TODO: update on resize: svgEl.setAttribute('viewBox', '0 0 ' + window.innerWidth + ' ' + window.innerHeight); let rect = svgEl.getBoundingClientRect(); - // let cx = rect.left + rect.width / 2; - // let cy = rect.top + rect.height / 2; - // let center = { 'x': cx, 'y': cy }; // move crosshairs window.addEventListener('mousemove', function (mousemoveEv) { @@ -27,16 +24,18 @@ export function init(svgEl, crosshairXEl, crosshairYEl) { }); svgEl.addEventListener('mousedown', function (mousedownEv) { + // create shape to draw let shapeEl = document.createElementNS('http://www.w3.org/2000/svg', 'path'); shapeEl.classList.add('rect'); let p1 = { 'x': mousedownEv.clientX - rect.left, 'y': mousedownEv.clientY - rect.top } - let d = getPathShapeBetweenPoints(p1, p1, segmentCount); + let corners = flywheel.effects.shape.getAngles(); + let d = getPathShapeBetweenPoints(p1, p1, corners); svgEl.appendChild(shapeEl); shapeEl.setAttribute('d', d); let mouseMoveEv = function (mousemoveEv) { let p2 = { 'x': mousemoveEv.clientX - rect.left, 'y': mousemoveEv.clientY - rect.top } - let d = getPathShapeBetweenPoints(p1, p2, segmentCount); + let d = getPathShapeBetweenPoints(p1, p2, corners); shapeEl.setAttribute('d', d); }; let mouseUpEv = function () { diff --git a/js/main.js b/js/main.js index 16c2c72..07fe509 100644 --- a/js/main.js +++ b/js/main.js @@ -5,4 +5,5 @@ let crosshairXEl = document.getElementById('crosshair_x'); let crosshairYEl = document.getElementById('crosshair_y'); -let game = init(svgEl, crosshairXEl, crosshairYEl); \ No newline at end of file +var game = init(svgEl, crosshairXEl, crosshairYEl); +console.log('Initialised game', game); \ No newline at end of file