fixes for pointy-top square boards
This commit is contained in:
@@ -51,14 +51,19 @@ export default class CartographerXY extends Cartographer {
|
|||||||
getVertDistance() {return this.pointyTop ? this.maxDistance() : this.minDistance();}
|
getVertDistance() {return this.pointyTop ? this.maxDistance() : this.minDistance();}
|
||||||
|
|
||||||
tileToPixel(square) {
|
tileToPixel(square) {
|
||||||
let scale = this.scale;
|
const scale = this.scale;
|
||||||
|
|
||||||
const minWidth = (a) => this.minWidth() * a;
|
// (above/below axis) * (distance from axis) / (size)
|
||||||
|
const pointyDistanceX = (x, y) => (x < y ? -1 : 1) * (Math.abs(y - x) / sqrt2) * this.minWidth();
|
||||||
|
const pointyDistanceY = (x, y) => (-x < y ? 1 : -1) * (Math.abs(x + y) / sqrt2) * this.minWidth();
|
||||||
|
|
||||||
const maxWidth = (a, b) => (this.maxWidth() * a) + ((b % 2) * (this.maxWidth() / 2));
|
const flatDistance = a => this.minWidth() * a;
|
||||||
|
|
||||||
let pixelX = this.pointyTop ? maxWidth(square.getX(), square.getY()) : minWidth(square.getX());
|
const x = square.getX();
|
||||||
let pixelY = this.pointyTop ? (this.maxWidth() / 2) * square.getY() : minWidth(square.getY());
|
const y = square.getY();
|
||||||
|
|
||||||
|
let pixelX = this.pointyTop ? pointyDistanceX(x, y) : flatDistance(x);
|
||||||
|
let pixelY = this.pointyTop ? pointyDistanceY(x, y) : flatDistance(y);
|
||||||
|
|
||||||
pixelX += this.originX;
|
pixelX += this.originX;
|
||||||
pixelY = this.originY - pixelY;;
|
pixelY = this.originY - pixelY;;
|
||||||
@@ -69,38 +74,53 @@ export default class CartographerXY extends Cartographer {
|
|||||||
pixelToTile(point) {
|
pixelToTile(point) {
|
||||||
let scale = this.scale;
|
let scale = this.scale;
|
||||||
|
|
||||||
const radiusLong = a => (a / (this.maxWidth() / 2));
|
// (above/below axis) * (distance from axis) / (size)
|
||||||
const radiusShort = a => a / this.minWidth();
|
const pointyDistanceX = (x, y) => (-x < y ? 1 : -1) * (Math.abs(x + y) / sqrt2) / this.minWidth();
|
||||||
|
const pointyDistanceY = (x, y) => (x < y ? 1 : -1) * (Math.abs(y - x) / sqrt2) / this.minWidth();
|
||||||
|
|
||||||
|
const flatDistance = a => a / this.minWidth();
|
||||||
|
|
||||||
let pixelX = point.getX() - this.originX;
|
let pixelX = point.getX() - this.originX;
|
||||||
let pixelY = this.originY - point.getY();
|
let pixelY = this.originY - point.getY();
|
||||||
|
|
||||||
let x = this.pointyTop ? radiusLong(pixelX, pixelY) : radiusShort(pixelX);
|
let x = this.pointyTop ? pointyDistanceX(pixelX, pixelY) : flatDistance(pixelX);
|
||||||
let y = this.pointyTop ? radiusLong(pixelY, pixelX) : radiusShort(pixelY);
|
let y = this.pointyTop ? pointyDistanceY(pixelX, pixelY) : flatDistance(pixelY);
|
||||||
|
|
||||||
return new Square(x, y);
|
return new Square(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
boundingBox(upperLeftPoint, lowerRightPoint) {
|
boundingBox(upperLeftPoint, upperRightPoint, lowerLeftPoint, lowerRightPoint) {
|
||||||
let upperRightPoint = new Point(lowerRightPoint.getX(), upperLeftPoint.getY());
|
const upperLeftTile = this.pixelToTile(upperLeftPoint);
|
||||||
|
const lowerRightTile = this.pixelToTile(lowerRightPoint);
|
||||||
let upperLeftTile = this.pixelToTile(upperLeftPoint);
|
const upperRightTile = this.pixelToTile(upperRightPoint);
|
||||||
let lowerRightTile = this.pixelToTile(lowerRightPoint);
|
|
||||||
let upperRightTile = this.pixelToTile(upperRightPoint);
|
|
||||||
|
|
||||||
if (this.pointyTop) {
|
if (this.pointyTop) {
|
||||||
for (let col = 0; col <= width; col++) {
|
const lowerLeftTile = this.pixelToTile(lowerLeftPoint);
|
||||||
tiles[col] = [];
|
|
||||||
let x = upperLeftTile.getX() + col;
|
|
||||||
const bottomRow = upperLeftTile.getY() - height;
|
|
||||||
|
|
||||||
for (let y = upperLeftTile.getY(); y >= bottomRow; y--) {
|
const columns = rangeInclusive(lowerLeftTile.getX(), upperRightTile.getX());
|
||||||
// TODO: this results in missing tiles (e.g. (1,0))
|
|
||||||
// fix by tilting coordinates 45 degrees?
|
const upperLeftIntercept = upperLeftTile.getY() - upperLeftTile.getX();
|
||||||
x = this.pointyTop ? x - (y % 2) : x;
|
const upperRightIntercept = upperLeftTile.getY() + upperLeftTile.getX();
|
||||||
tiles[col].push(new Square(x, y));
|
|
||||||
}
|
const lowerLeftIntercept = lowerRightTile.getY() - lowerRightTile.getX();
|
||||||
}
|
const lowerRightIntercept = lowerRightTile.getY() + lowerRightTile.getX();
|
||||||
|
|
||||||
|
const aboutHalf = Math.floor(columns.length / 2);
|
||||||
|
const midway = columns.length % 2 ? columns[aboutHalf] :
|
||||||
|
(columns[aboutHalf - 1] + columns[aboutHalf]) / 2;
|
||||||
|
|
||||||
|
return columns.map(x => {
|
||||||
|
let top = x < midway ? upperLeftIntercept + x : upperRightIntercept - x;
|
||||||
|
let bottom = x < midway ? lowerRightIntercept - x : lowerLeftIntercept + x;
|
||||||
|
|
||||||
|
bottom = Math.min(bottom, top);
|
||||||
|
top = Math.max(bottom, top);
|
||||||
|
|
||||||
|
// push out by 1 on either end to account for interlocking tiles
|
||||||
|
const rows = rangeInclusive(bottom - 1, top + 1);
|
||||||
|
|
||||||
|
return rows.map(y => new Square(x, y));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const columns = rangeInclusive(upperLeftTile.getX(), upperRightTile.getX());
|
const columns = rangeInclusive(upperLeftTile.getX(), upperRightTile.getX());
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ class Demo {
|
|||||||
tile: Tessellate.TILE_STYLES.SQUARE,
|
tile: Tessellate.TILE_STYLES.SQUARE,
|
||||||
tap: this.onTap,
|
tap: this.onTap,
|
||||||
draw: this.draw,
|
draw: this.draw,
|
||||||
pointyTop: false, //utils.random(1) ? true : false,
|
pointyTop: true, //utils.random(1) ? true : false,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.circle = new DrawCircle();
|
this.circle = new DrawCircle();
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ export default class Tessellate {
|
|||||||
static get BOARD_STYLES () {return {HEX, SQUARE}}
|
static get BOARD_STYLES () {return {HEX, SQUARE}}
|
||||||
|
|
||||||
constructor(settings) {
|
constructor(settings) {
|
||||||
['tap', 'draw', 'drawMap', 'move', 'zoom'].map(method => {this[method] = this[method].bind(this)});
|
['seedTiles', 'tap', 'draw', 'drawMap', 'move', 'zoom'].map(method => {this[method] = this[method].bind(this)});
|
||||||
|
|
||||||
this.settings = utils.extend(DEFAULTS, settings);
|
this.settings = utils.extend(DEFAULTS, settings);
|
||||||
this.settings.element = this.settings.element instanceof HTMLElement ? this.settings.element :
|
this.settings.element = this.settings.element instanceof HTMLElement ? this.settings.element :
|
||||||
@@ -62,6 +62,7 @@ export default class Tessellate {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.map = [];
|
this.map = [];
|
||||||
|
this.seedTiles();
|
||||||
|
|
||||||
const boardSettings = {
|
const boardSettings = {
|
||||||
pointyTop: this.settings.pointyTop,
|
pointyTop: this.settings.pointyTop,
|
||||||
@@ -72,6 +73,54 @@ export default class Tessellate {
|
|||||||
this.cartographer = this.settings.board === HEX ? new CartographerXYZ(boardSettings) : new CartographerXY(boardSettings);
|
this.cartographer = this.settings.board === HEX ? new CartographerXYZ(boardSettings) : new CartographerXY(boardSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
seedTiles() {
|
||||||
|
this.map[0] = [];
|
||||||
|
// this.map[1] = [];
|
||||||
|
// this.map[-1] = [];
|
||||||
|
// this.map[-5] = [];
|
||||||
|
|
||||||
|
this.map[0][0] = new Cell({
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
pointyTop: this.settings.pointyTop,
|
||||||
|
red: 0,
|
||||||
|
green: 0,
|
||||||
|
blue: 0,
|
||||||
|
alpha: 75/100,
|
||||||
|
scale: 9/10,
|
||||||
|
});
|
||||||
|
// this.map[1][1] = new Cell({
|
||||||
|
// x: 1,
|
||||||
|
// y: 1,
|
||||||
|
// pointyTop: this.settings.pointyTop,
|
||||||
|
// red: 0,
|
||||||
|
// green: 0,
|
||||||
|
// blue: 255,
|
||||||
|
// alpha: 90/100,
|
||||||
|
// scale: 9/10,
|
||||||
|
// });
|
||||||
|
// this.map[-1][-1] = new Cell({
|
||||||
|
// x: -1,
|
||||||
|
// y: -1,
|
||||||
|
// pointyTop: this.settings.pointyTop,
|
||||||
|
// red: 255,
|
||||||
|
// green: 0,
|
||||||
|
// blue: 0,
|
||||||
|
// alpha: 90/100,
|
||||||
|
// scale: 9/10,
|
||||||
|
// });
|
||||||
|
// this.map[-5][5] = new Cell({
|
||||||
|
// x: -5,
|
||||||
|
// y: 5,
|
||||||
|
// pointyTop: this.settings.pointyTop,
|
||||||
|
// red: 0,
|
||||||
|
// green: 255,
|
||||||
|
// blue: 0,
|
||||||
|
// alpha: 90/100,
|
||||||
|
// scale: 9/10,
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
|
||||||
tap(event) {
|
tap(event) {
|
||||||
let point = new Point(event.offsetX, event.offsetY);
|
let point = new Point(event.offsetX, event.offsetY);
|
||||||
let tile = this.cartographer.pixelToTile(point);
|
let tile = this.cartographer.pixelToTile(point);
|
||||||
@@ -94,12 +143,16 @@ export default class Tessellate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
drawMap(context) {
|
drawMap(context) {
|
||||||
let scale = this.cartographer.getScale();
|
const scale = this.cartographer.getScale();
|
||||||
let upperLeft = new Point(0, 0);
|
|
||||||
let lowerRight = new Point(context.canvas.width, context.canvas.height);
|
|
||||||
let tiles = this.cartographer.boundingBox(upperLeft, lowerRight);
|
|
||||||
|
|
||||||
let height = tiles.length;
|
const upperLeft = new Point(0, 0);
|
||||||
|
const upperRight = new Point(context.canvas.width, 0);
|
||||||
|
const lowerLeft = new Point(0, context.canvas.height);
|
||||||
|
const lowerRight = new Point(context.canvas.width, context.canvas.height);
|
||||||
|
|
||||||
|
const tiles = this.cartographer.boundingBox(upperLeft, upperRight, lowerLeft, lowerRight);
|
||||||
|
|
||||||
|
const height = tiles.length;
|
||||||
for (let r=0; r<height; r++) {
|
for (let r=0; r<height; r++) {
|
||||||
let width = tiles[r].length;
|
let width = tiles[r].length;
|
||||||
|
|
||||||
@@ -114,11 +167,11 @@ export default class Tessellate {
|
|||||||
x: tile.getX(),
|
x: tile.getX(),
|
||||||
y: tile.getY(),
|
y: tile.getY(),
|
||||||
pointyTop: this.settings.pointyTop,
|
pointyTop: this.settings.pointyTop,
|
||||||
red: utils.random(255),
|
red: utils.random(64, 192),
|
||||||
green: utils.random(255),
|
green: utils.random(64, 192),
|
||||||
blue: utils.random(255),
|
blue: utils.random(64, 192),
|
||||||
alpha: utils.random(25, 75) / 100,
|
alpha: 0.75,
|
||||||
scale: utils.random(6,9)/10
|
scale: utils.random(7, 9) / 10
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
11
src/utils.js
11
src/utils.js
@@ -63,7 +63,14 @@ export function range (start, end) {
|
|||||||
start = 0;
|
start = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Array.from(Array(end - start), (_value, index) => index + start);
|
if (start > end) {
|
||||||
|
const swap = start;
|
||||||
|
|
||||||
|
start = end;
|
||||||
|
end = swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Array.from(Array(Math.abs(end - start)), (_value, index) => index + start);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function rangeInclusive(start, end) {
|
export function rangeInclusive(start, end) {
|
||||||
@@ -72,6 +79,6 @@ export function rangeInclusive(start, end) {
|
|||||||
start = 0;
|
start = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return range(start, end+1);
|
return range(Math.min(start, end), Math.max(start, end)+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user