318 lines
7.0 KiB
JavaScript
318 lines
7.0 KiB
JavaScript
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();
|
|
|