diff --git a/assets/original/table.png b/assets/original/table.png new file mode 100755 index 0000000..472c072 Binary files /dev/null and b/assets/original/table.png differ diff --git a/src/Board.js b/src/Board.js old mode 100644 new mode 100755 index 0eeeb7c..edce401 --- a/src/Board.js +++ b/src/Board.js @@ -1,8 +1,10 @@ import React, { useState, useEffect } from "react"; const hexagonRatio = 1.1547005, - tileHeight = 0.165, - tileWidth = tileHeight * hexagonRatio; + tileHeight = 0.16, + tileWidth = tileHeight * hexagonRatio, + roadSize = tileHeight * 0.5 * (5. / 8.), + settlementSize = tileHeight * 0.5 - roadSize; const Tiles = (board) => { const tiles = [ { @@ -123,6 +125,19 @@ const Border = (board, border) => { return border; }; +const Table = (board) => { + const image = new Image(), file = "table.png"; + image.addEventListener("load", (event) => { + console.log(`Done loading ${file}`); + window.requestAnimationFrame(board.drawFrame); + }); + image.addEventListener("error", (event) => { + alert(`Error loading ${file}`); + }); + image.src = `assets/original/${file}`; + return image; +}; + function shuffle(array) { var currentIndex = array.length, temporaryValue, randomIndex; @@ -158,6 +173,15 @@ class Board extends React.Component { this.pips = Pips(this); this.tiles = Tiles(this); + this.table = Table(this); + + this.closest = { + info: {}, + tile: null, + road: null, + tradeToken: null, + settlement: null + }; this.borders = [ { file: 'borders-1.6.png', left: "sheep", right: "bank" @@ -186,11 +210,30 @@ class Board extends React.Component { mouseMove(event) { const rect = this.canvas.parentElement.getBoundingClientRect(); + let x, y; + + if (event.changedTouches && event.changedTouches.length > 0) { + x = event.changedTouches[0].clientX; + y = event.changedTouches[0].clientY; + } else { + x = event.clientX; + y = event.clientY; + } + /* Scale mouse.x and mouse.y relative to board */ - this.mouse.x = (event.clientX - rect.left) / - (this.canvas.height / hexagonRatio) - 0.5 - tileHeight * 0.5, - this.mouse.y = (event.clientY - rect.top) / - (this.canvas.height / hexagonRatio) - 0.5 - tileHeight * 0.5; + this.mouse.x = (x - rect.left) / + (this.minSize / hexagonRatio) - 0.5 - tileHeight * 0.5, + this.mouse.y = (y - rect.top) / + (this.minSize / hexagonRatio) - 0.5 - tileHeight * 0.5; + + /* Hide the mouse cursor circle after 0.5s */ + if (this.mouse.timer) { + window.clearTimeout(this.mouse.timer); + } + this.mouse.timer = window.setTimeout(() => { + this.mouse.timer = null; + window.requestAnimationFrame(this.drawFrame); + }, 500); let closest = null; @@ -204,14 +247,28 @@ class Board extends React.Component { if (!closest || closest.distance > distance) { closest = { tile: tile, - distance: distance + distance: distance, + angle: (distance != 0.0) ? Math.atan2(dY, dX) : 0 } } }); - if (this.closest != closest) { - this.closest = closest; + if (!closest) { + this.closest.tile = null; + this.closest.info.distance = -1; + this.closest.road = null; + this.closest.angle = 0; + this.closest.settlement = null; + this.closest.tradeToken = null; + } else { + if (this.closest.tile != closest.tile) { + this.closest.tile = closest.tile; + } + + this.closest.info.distance = closest.distance, + this.closest.info.angle = closest.angle; } + window.requestAnimationFrame(this.drawFrame); } @@ -236,15 +293,20 @@ class Board extends React.Component { } const ctx = this.canvas.getContext("2d"); - ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); ctx.save(); ctx.strokeStyle = 'white'; ctx.filleStyle = 'rgba(0, 0, 0, 0)'; - ctx.scale(this.canvas.height / hexagonRatio, this.canvas.height / hexagonRatio); + this.minSize = Math.min(this.canvas.height, this.canvas.width); + ctx.drawImage(this.table, + 0, 0, + this.table.width, this.table.height, + 0, 0, this.minSize, this.minSize); + + ctx.scale(this.minSize / hexagonRatio, this.minSize / hexagonRatio); ctx.translate(0.5 * hexagonRatio, 0.5 * hexagonRatio); - ctx.lineWidth = 1. / this.canvas.height; + ctx.lineWidth = 1. / this.minSize; /* Board dimensions: * ________ @@ -267,19 +329,55 @@ class Board extends React.Component { this.drawPips(ctx); ctx.restore(); - if (this.closest) { + if (this.closest.tile) { + ctx.save(); + ctx.translate(this.closest.tile.pos.x, this.closest.tile.pos.y); ctx.strokeStyle = "red"; ctx.beginPath(); - ctx.arc(this.closest.tile.pos.x, this.closest.tile.pos.y, - tileHeight * 0.5, 0, Math.PI * 2.); + ctx.arc(0, 0, tileHeight * 0.5, 0, Math.PI * 2.); ctx.stroke(); + /* road */ + if (1 || this.closest.info.distance > 0.1 * tileWidth * 0.5) { + const angle = Math.round(this.closest.info.angle / (Math.PI / 3.)) * (Math.PI / 3.); + ctx.strokeStyle = "green"; + ctx.rotate(angle); + ctx.translate(-tileHeight * 0.5, 0); + ctx.beginPath(); + ctx.rect(-roadSize * 0.125, -roadSize * 0.5, roadSize * 0.25, roadSize); + ctx.stroke(); + ctx.translate(tileHeight * 0.5, 0); + ctx.rotate(-angle); + } + /* village */ + if (1 || this.closest.info.distance > 0.1 * tileHeight * 0.5) { + let angle = (this.closest.info.angle - Math.PI / 6.); + angle = Math.round(angle / (Math.PI / 3.)) * (Math.PI / 3.); + angle += Math.PI / 6.; + ctx.strokeStyle = "blue"; + ctx.rotate(angle); + ctx.translate(-tileWidth * 0.5, 0); + ctx.rotate(-angle); + ctx.beginPath(); + ctx.rect(-settlementSize * 0.5, -settlementSize * 0.5, settlementSize, settlementSize); + ctx.stroke(); + ctx.rotate(angle); + ctx.translate(+tileWidth * 0.5, 0); + ctx.rotate(-angle); + } + ctx.restore(); } - ctx.strokeStyle = "yellow"; - ctx.beginPath(); - ctx.arc(this.mouse.x, this.mouse.y, - tileHeight * 0.5, 0, Math.PI * 2.); - ctx.stroke(); + /* For 0.5 after mouse movement, there is an on + * screen mouse helper. */ + if (this.mouse.timer) { + ctx.strokeStyle = "rgba(0, 255, 255)"; + ctx.fillStyle = "rgba(0, 255, 255, 0.25)"; + ctx.beginPath(); + ctx.arc(this.mouse.x, this.mouse.y, + tileHeight * 0.5, 0, Math.PI * 2.); + ctx.stroke(); + ctx.fill(); + } ctx.restore(); } @@ -380,6 +478,7 @@ class Board extends React.Component { this.start = new Date(); window.addEventListener("mousedown", this.randomize); + window.addEventListener("touchmove", this.mouseMove); window.addEventListener("mousemove", this.mouseMove); window.addEventListener("resize", this.updateDimensions); @@ -393,6 +492,7 @@ class Board extends React.Component { } window.removeEventListener("mousedown", this.randomize); window.removeEventListener("mousemove", this.mouseMove); + window.removeEventListener("touchmove", this.mouseMove); window.removeEventListener("resize", this.updateDimensions); }