import FPS from './fps.js'; const ONE_SECOND = 1000; const PRESS_RIPPLE = ONE_SECOND / 3; const DEFAULTS = { board: Tessellate.BOARD_STYLES.HEX, style: Tessellate.DRAW_STYLES.FILL, orientation: Tessellate.ORIENTATION_STYLES.FLAT, tile: Tessellate.TILE_STYLES.HEX, }; const keyTemplate = ({x, y, z}) => `${ x },${ z != null ? z : y }`; const pressRipple = function() { const sinStart = 2 * Math.PI; const halfPi = Math.PI / 2; return pressFactor => Math.sin(sinStart + (pressFactor * halfPi)) + 1; }(); const pressFade = function() { const halfPi = Math.PI / 2; return pressFactor => Math.sin(Math.PI + (pressFactor * halfPi)) + 1; }(); class Demo { constructor() { [ 'setOriginTile', 'setupKeydown', 'tap', 'pressStart', 'press', 'createTile', 'drawTile', 'draw', ].map(method => this[method] = this[method].bind(this)); const queryStringObj = Tessellate.utils.getQueryStringObj(); this.settings = Object.assign({}, DEFAULTS, queryStringObj); this.map = {}; this.taps = []; this.mines = {}; this.ripples = []; this.fps = new FPS({ element: document.querySelector('#fps'), }); this.setOriginTile(); this.setupKeydown(); this.tessellate = new Tessellate(Object.assign({ element: '#container', tap: this.tap, pressStart: this.pressStart, press: this.press, draw: this.draw, }, this.settings)); } setOriginTile() { this.map['0,0'] = new Tessellate.Cell({ x: 0, y: 0, scale: 1, drawStyle: Tessellate.DRAW_STYLES.FILL, tileStyle: this.settings.tile, orientation: this.settings.orientation, color: { red: 255, green: 255, blue: 0, alpha: 1, } }); Tessellate.utils.rangeInclusive(0, 5) .map(interval => interval ? interval * 0.2 : 0.01) .forEach(interval => { this.taps.push(new Tessellate.Cell({ x: 0, y: 0, scale: interval, drawStyle: Tessellate.DRAW_STYLES.OUTLINE, tileStyle: this.settings.tile, orientation: this.settings.orientation, color: { red: 0, green: 0, blue: 0, alpha: 1, }, })); }); } setupKeydown () { this.pipDefault = null; window.addEventListener('keydown', event => { if (!event.repeat) { if (event.key === 'Enter') { this.gray = this.gray ? null : Date.now(); } if (event.key === `~`) { this.mined = true; } if (event.key === '`') { this.pipDefault = '*'; } const num = parseInt(event.key); if (num >= 0 && num <= 9) { this.pipDefault = num; } } }); } tap(tap) { const key = keyTemplate(tap.mapTile); const pipMax = this.settings.tile === Tessellate.TILE_STYLES.HEX ? 7 : 9; if (this.map[key]) { this.map[key].pips = Tessellate.utils.random(1, pipMax); console.log(tap.mapTile.getPoint()); } else { console.log('ERROR - no tile', key); } } pressStart(tap) { this.ripples.push({ timestamp: tap.event.timeStampUTC, cell: this.createTile({ x: tap.tile.x, y: tap.tile.y, scale: 1.0, drawStyle: Tessellate.DRAW_STYLES.FILL, tileStyle: Tessellate.TILE_STYLES.CIRCLE, orientation: Tessellate.ORIENTATION_STYLES.FLAT, color: { red: 128, green: 128, blue: 128, alpha: 0.5, }, }) }); if (tap.event.mobile) { this.togglemine(tap.mapTile) } } press(tap) { if (!tap.event.mobile) { this.togglemine(tap.mapTile) } } togglemine(tile) { const key = keyTemplate(tile); if (this.mines[key]) { delete this.mines[key]; } else { this.mines[key] = tile; } } createTile({x, y, drawStyle, tileStyle, orientation, scale = Tessellate.utils.random(7, 9) / 10, color = { red: Tessellate.utils.random(255), green: Tessellate.utils.random(255), blue: Tessellate.utils.random(255), alpha: Tessellate.utils.random(25, 75) / 100, } }) { return new Tessellate.Cell({ x, y, scale, drawStyle, tileStyle, orientation, color, }); } fadeToGray (tile, fadeFactor) { tile.color.grayscale = tile.color.grayscale || Tessellate.utils.grayscale(tile.color); const grayscale = tile.color.grayscale; const color = { red: parseInt(tile.color.red - ((tile.color.red - grayscale) * fadeFactor)), green: parseInt(tile.color.green - ((tile.color.green - grayscale) * fadeFactor)), blue: parseInt(tile.color.blue - ((tile.color.blue - grayscale) * fadeFactor)), }; tile = Tessellate.utils.extend(tile, {color}); return tile; } drawTile(pointGroup, context, scale) { const pixelX = pointGroup.pixelPoint.getX(); const pixelY = pointGroup.pixelPoint.getY(); this.counts[0] += 1; const key = keyTemplate(pointGroup.mapPoint); this.map[key] = this.map[key] || this.createTile({ x: pointGroup.mapPoint.x, y: pointGroup.mapPoint.y, drawStyle: this.settings.style, tileStyle: this.settings.tile, orientation: this.settings.orientation, }); let tile = this.map[key]; const fadeFactor = this.gray ? Math.min((Date.now() - this.gray) / 5000, 1) : null; tile = this.gray ? this.fadeToGray(tile, fadeFactor) : tile; Tessellate.TILES[tile.tileStyle][tile.drawStyle](context, scale, pixelX, pixelY, tile); if (this.mined || this.mines[key]) { this.counts[2] += 1; Tessellate.Shapes.mine(context, scale, pixelX, pixelY); } else { if (!tile.pips && this.pipDefault !== null) { if (this.pipDefault === '*') { const pipMax = this.settings.tile === Tessellate.TILE_STYLES.HEX ? 7 : 9; tile.pips = Tessellate.utils.random(1, pipMax); } else { tile = Tessellate.utils.extend(tile, {pips: this.pipDefault}); } } if (tile.pips) { this.counts[1] += tile.pips; Tessellate.Shapes.pips(context, scale, pixelX, pixelY, tile); } } } draw({context, height, width, scale, pointGroups, now, lastNow}) { this.counts = [ 0, // tiles 0, // pips 0, // mines ]; Tessellate.Shapes.background(context, height, width, { red: 64, green: 32, blue: 128, }); pointGroups .filter(pointGroup => pointGroup.mapPoint) .forEach(pointGroup => this.drawTile(pointGroup, context, scale)); this.ripples.forEach(({timestamp, cell}) => { const pressFactor = Math.min((now - timestamp) / PRESS_RIPPLE, 1); Object.assign(cell, {scale: pressRipple(pressFactor)}); Object.assign(cell.color, {alpha: pressFade(pressFactor)}); const pixelPoint = this.tessellate.tileToPixel(cell); Tessellate.TILES[cell.tileStyle][cell.drawStyle](context, scale, pixelPoint.getX(), pixelPoint.getY(), cell); }); this.ripples = this.ripples.filter(ripple => (ripple.timestamp + PRESS_RIPPLE) > now); this.taps.forEach(cell => { const pixelPoint = this.tessellate.tileToPixel(cell); Tessellate.TILES[cell.tileStyle][cell.drawStyle](context, scale, pixelPoint.getX(), pixelPoint.getY(), cell); }); // Tessellate.funky.forEach(this.mines, cell => { // this.counts[2] += 1; // const pixelPoint = this.tessellate.tileToPixel(cell); // Tessellate.Shapes.mine(context, scale, pixelPoint.getX(), pixelPoint.getY()); // }); this.fps.frame(now, lastNow, this.counts); } } let demo = new Demo();