Using div and backgrounds instead of canvas
Signed-off-by: James Ketrenos <james_eikona@ketrenos.com>
This commit is contained in:
parent
2c9e86931e
commit
27cf10ad48
Binary file not shown.
Before Width: | Height: | Size: 496 KiB After Width: | Height: | Size: 484 KiB |
Binary file not shown.
Before Width: | Height: | Size: 385 KiB After Width: | Height: | Size: 1.4 MiB |
@ -5,3 +5,27 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.Tile {
|
||||||
|
width: 90.75px;
|
||||||
|
height: 77.5px;
|
||||||
|
position: absolute;
|
||||||
|
background-position-y: 0px;
|
||||||
|
background-size: cover;
|
||||||
|
transform: translate(-45.375px, -38.75px) rotate(-30deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.Pip {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
position: absolute;
|
||||||
|
background-size: 600% auto; /* pip-numbers is a 6x6 grid of pip images */
|
||||||
|
transform: translate(-25px, -25px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.Border {
|
||||||
|
width: 242px;
|
||||||
|
height: 70.6px;
|
||||||
|
position: absolute;
|
||||||
|
transform-origin: 0 0;
|
||||||
|
background-size: cover;
|
||||||
|
}
|
@ -82,48 +82,7 @@ const loadImage = (file, drawFrame) => {
|
|||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Tiles = (game, drawFrame) => {
|
|
||||||
if (!game) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const tiles = game.tiles;
|
|
||||||
|
|
||||||
[ "robber", "brick", "wood", "sheep", "stone", "wheat" ].forEach((type) => {
|
|
||||||
const file = "tiles-" + type + ".png",
|
|
||||||
image = loadImage(file, drawFrame);
|
|
||||||
|
|
||||||
tiles.forEach((tile) => {
|
|
||||||
if (tile.type === type) {
|
|
||||||
tile.image = image;
|
|
||||||
tile.x = 0;
|
|
||||||
tile.pos = { x: 0, y: 0 };
|
|
||||||
}
|
|
||||||
tile.jitter = 0;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return tiles;
|
|
||||||
};
|
|
||||||
|
|
||||||
const gameSignature = (game) => {
|
|
||||||
if (!game) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
const signature =
|
|
||||||
game.borders.map(border => border.file.replace(/borders-(.).*/, "$1")).join('') +
|
|
||||||
game.pips.map(pip => pip.roll.toString()).join('') +
|
|
||||||
game.tiles.map(tile => tile.type.charAt(0)).join('');
|
|
||||||
|
|
||||||
return signature;
|
|
||||||
};
|
|
||||||
|
|
||||||
const Board = ({ game }) => {
|
const Board = ({ game }) => {
|
||||||
const [signature, setSignature] = useState(gameSignature(game));
|
|
||||||
const [mouse, setMouse] = useState({x: 0, y: 0, timer: null});
|
|
||||||
const [pips, setPips] = useState([]);
|
|
||||||
const [borders, setBorders] = useState([]);
|
|
||||||
const [tabletop, setTabletop] = useState(null);
|
|
||||||
const [tiles, setTiles] = useState([]);
|
|
||||||
const [closest, setClosest] = useState({
|
const [closest, setClosest] = useState({
|
||||||
info: {},
|
info: {},
|
||||||
tile: null,
|
tile: null,
|
||||||
@ -131,408 +90,134 @@ const Board = ({ game }) => {
|
|||||||
tradeToken: null,
|
tradeToken: null,
|
||||||
settlement: null
|
settlement: null
|
||||||
});
|
});
|
||||||
const [minSize,setMinSize] = useState(0);
|
|
||||||
|
|
||||||
const radius = 0.317;
|
const center = { x: 300, y: 350 }, rows = [3, 4, 5, 4, 3];
|
||||||
const canvasRef = useRef(null);
|
|
||||||
|
|
||||||
const drawPips = useCallback((ctx) => {
|
const generatePips = () => {
|
||||||
const image = pips.image, pipSize = 0.06;
|
let row = 0, rowCount = 0;
|
||||||
|
let y = center.y - rows.length * 0.5 * 67,
|
||||||
|
x = center.x - (rows[row] - 1) * 0.5 * 77.5;
|
||||||
|
let divs = [], count = 19;
|
||||||
|
for (let i = 0; i < count; i++) {
|
||||||
|
let code = (i === (count - 1))
|
||||||
|
? 'robber'
|
||||||
|
: String.fromCharCode(65 + i);
|
||||||
|
divs.push(
|
||||||
|
<div
|
||||||
|
key={`pip-${code}`}
|
||||||
|
className="Pip"
|
||||||
|
style={{
|
||||||
|
top: `${y}px`,
|
||||||
|
left: `${x}px`,
|
||||||
|
backgroundImage: `url(${assetsPath}/gfx/pip-numbers.png)`,
|
||||||
|
backgroundPositionX: `${ 100. * (i % 6) / 5.}%`,
|
||||||
|
backgroundPositionY: `${ 100 * Math.floor(i / 6) / 5. }%`
|
||||||
|
}}/>
|
||||||
|
);
|
||||||
|
|
||||||
function drawTile(tile, angle, radius) {
|
if (++rowCount === rows[row]) {
|
||||||
tile.pos.x = Math.sin(-angle) * radius;
|
row++;
|
||||||
tile.pos.y = Math.cos(-angle) * radius;
|
rowCount = 0;
|
||||||
const image = tile.image;
|
y += 67;
|
||||||
ctx.save();
|
x = center.x - (rows[row] - 1) * 0.5 * 77.5;
|
||||||
ctx.rotate(angle);
|
} else {
|
||||||
ctx.translate(0., radius);
|
x += 77.5;
|
||||||
ctx.rotate(-angle + Math.PI * 1. / 6.);
|
}
|
||||||
ctx.drawImage(image,
|
|
||||||
tile.x * image.width, tile.y * image.height,
|
|
||||||
image.width, image.height / 4.,
|
|
||||||
-tileWidth * 0.5, -tileHeight * 0.5,
|
|
||||||
tileWidth, tileHeight);
|
|
||||||
ctx.restore();
|
|
||||||
}
|
}
|
||||||
|
return divs;
|
||||||
|
};
|
||||||
|
|
||||||
function drawPip(pip, angle, radius, jitter) {
|
const generateTiles = () => {
|
||||||
ctx.save();
|
let row = 0, rowCount = 0;
|
||||||
ctx.rotate(angle);
|
let y = center.y - rows.length * 0.5 * 67,
|
||||||
ctx.translate(0., radius);
|
x = center.x - (rows[row] - 1) * 0.5 * 77.5;
|
||||||
/* Offset into a random direction by a random amount */
|
|
||||||
ctx.rotate(Math.PI * 2. * jitter);
|
|
||||||
ctx.translate(0, tileHeight * 0.1 * jitter);
|
|
||||||
/* Undo random rotation for position, and add random rotation
|
|
||||||
* for pip placement */
|
|
||||||
ctx.rotate(-angle - Math.PI * 2. * jitter + jitter * 0.4);
|
|
||||||
ctx.drawImage(image,
|
|
||||||
pip.x * image.width, pip.y * image.height,
|
|
||||||
image.width / 6., image.height / 6.,
|
|
||||||
-pipSize * 0.5, -pipSize * 0.5,
|
|
||||||
pipSize, pipSize);
|
|
||||||
ctx.restore();
|
|
||||||
}
|
|
||||||
|
|
||||||
let angle,
|
return [ "robber", "brick", "wood", "sheep", "stone", "wheat" ].map((type) => {
|
||||||
rotation = radius,
|
let count;
|
||||||
index = 0, pip; //, roll = dice[0].pips + dice[1].pips;
|
switch (type) {
|
||||||
|
case "robber":
|
||||||
|
count = 1;
|
||||||
|
break;
|
||||||
|
case "brick":
|
||||||
|
count = 3;
|
||||||
|
break;
|
||||||
|
case "wood":
|
||||||
|
count = 4;
|
||||||
|
break;
|
||||||
|
case "sheep":
|
||||||
|
count = 4;
|
||||||
|
break;
|
||||||
|
case "stone":
|
||||||
|
count = 3;
|
||||||
|
break;
|
||||||
|
case "wheat":
|
||||||
|
count = 4;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.error(`Invalid type: ${type}`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let divs = [];
|
||||||
|
|
||||||
/* Outer row */
|
for (let i = 0; i < count; i++) {
|
||||||
angle = 0;
|
divs.push(
|
||||||
for (let i = 0; i < 12; i++) {
|
<div
|
||||||
angle -= Math.PI * 2. / 12.;
|
key={`${type}-${i}`}
|
||||||
pip = pips.pips[index++];
|
className="Tile"
|
||||||
tiles[i].pip = pip;
|
style={{
|
||||||
drawTile(tiles[i], angle, rotation - (i % 2) * 0.04);
|
top: `${y}px`,
|
||||||
drawPip(pip, angle, rotation - (i % 2) * 0.04, tiles[i].jitter);
|
left: `${x}px`,
|
||||||
}
|
backgroundImage: `url(${assetsPath}/gfx/tiles-${type}.png)`,
|
||||||
|
backgroundPositionY: `-${i*77.5}px`
|
||||||
|
}}/>
|
||||||
|
);
|
||||||
|
|
||||||
/* Middle row */
|
if (++rowCount === rows[row]) {
|
||||||
angle = Math.PI * 2. / 12.;
|
row++;
|
||||||
rotation = radius * 0.5;
|
rowCount = 0;
|
||||||
for (let i = 12; i < 18; i++) {
|
y += 67;
|
||||||
angle -= Math.PI * 2. / 6.;
|
x = center.x - (rows[row] - 1) * 0.5 * 77.5;
|
||||||
pip = pips.pips[index++];
|
|
||||||
tiles[i].pip = pip;
|
|
||||||
drawTile(tiles[i], angle, rotation);
|
|
||||||
drawPip(pip, angle, rotation, tiles[i].jitter);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Center */
|
|
||||||
let i = 18;
|
|
||||||
pip = pips.pips[index++];
|
|
||||||
tiles[i].pip = pip;
|
|
||||||
drawTile(tiles[i], 0, 0);
|
|
||||||
drawPip(pip, 0, 0, tiles[i].jitter);
|
|
||||||
}, [ tiles, pips]);
|
|
||||||
|
|
||||||
const drawBorders = useCallback((ctx) => {
|
|
||||||
ctx.rotate(Math.PI);
|
|
||||||
|
|
||||||
const offset = 0.18;
|
|
||||||
borders.forEach((border, index) => {
|
|
||||||
ctx.translate(0, radius);
|
|
||||||
|
|
||||||
const image = border.image;
|
|
||||||
|
|
||||||
ctx.drawImage(image,
|
|
||||||
-offset, 0,
|
|
||||||
0.5, 0.5 * image.height / image.width);
|
|
||||||
|
|
||||||
ctx.translate(0, -radius);
|
|
||||||
ctx.rotate(Math.PI * 2. / 6.);
|
|
||||||
});
|
|
||||||
}, [borders]);
|
|
||||||
|
|
||||||
const drawFrame = useCallback(() => {
|
|
||||||
if (!canvasRef || !tabletop || !canvasRef.current) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!game) {
|
|
||||||
console.log("Nothing to render if there is no game!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const canvas = canvasRef.current;
|
|
||||||
|
|
||||||
if (canvas.width === 0 || canvas.height === 0) {
|
|
||||||
console.log("No dimensions to render in");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ctx = canvas.getContext("2d");
|
|
||||||
// ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
||||||
|
|
||||||
ctx.save();
|
|
||||||
ctx.strokeStyle = 'white';
|
|
||||||
ctx.fillStyle = 'rgba(0, 0, 0, 0)';
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Tabletop tiling:
|
|
||||||
* Image width: 1080
|
|
||||||
* Left start: 32
|
|
||||||
* Right edge: 1010 (1010 - 32 = 978)
|
|
||||||
*
|
|
||||||
* If the view is wider than taller, then
|
|
||||||
*/
|
|
||||||
const tabletopLeft = 32 * tabletop.width / 1080,
|
|
||||||
tabletopRight = 1010 * tabletop.width / 1080,
|
|
||||||
tabletopLeaf = 978 * tabletop.width / 1080;
|
|
||||||
|
|
||||||
/* If view is taller than wide, tile the tabletop vertically */
|
|
||||||
ctx.save();
|
|
||||||
if (canvas.height > canvas.width) {
|
|
||||||
const tabletopHeight = canvas.width * tabletop.height / tabletop.width;
|
|
||||||
for (let top = 0, step = 0; top < canvas.height; top += tabletopHeight, step++) {
|
|
||||||
if (step % 2) {
|
|
||||||
ctx.save();
|
|
||||||
ctx.translate(0, tabletopHeight - 1);
|
|
||||||
ctx.transform(1, 0, 0, -1, 0, 0);
|
|
||||||
ctx.drawImage(tabletop,
|
|
||||||
0, 0,
|
|
||||||
tabletop.width, tabletop.height,
|
|
||||||
0, 0, canvas.width, canvas.width * tabletop.height / tabletop.width);
|
|
||||||
ctx.restore();
|
|
||||||
} else {
|
} else {
|
||||||
ctx.drawImage(tabletop,
|
x += 77.5;
|
||||||
0, 0,
|
|
||||||
tabletop.width, tabletop.height,
|
|
||||||
0, 0,
|
|
||||||
canvas.width, canvas.width * tabletop.height / tabletop.width);
|
|
||||||
}
|
|
||||||
ctx.translate(0, tabletopHeight);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//const tabletopWidth = canvas.height * tabletop.width / tabletop.height;
|
|
||||||
ctx.drawImage(tabletop,
|
|
||||||
0, 0,
|
|
||||||
tabletopRight, tabletop.height,
|
|
||||||
0, 0,
|
|
||||||
canvas.height * tabletopRight / tabletop.height, canvas.height);
|
|
||||||
let left = canvas.height * tabletopRight / tabletop.height;
|
|
||||||
while (left < canvas.width) {
|
|
||||||
ctx.drawImage(tabletop,
|
|
||||||
tabletopLeft, 0,
|
|
||||||
tabletopLeaf, tabletop.height,
|
|
||||||
left, 0,
|
|
||||||
canvas.height * tabletopLeaf / tabletop.height, canvas.height);
|
|
||||||
left += canvas.height * tabletopLeaf / tabletop.height;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ctx.restore();
|
|
||||||
|
|
||||||
ctx.scale(minSize / hexagonRatio, minSize / hexagonRatio);
|
|
||||||
ctx.translate(0.5 * hexagonRatio, 0.5 * hexagonRatio);
|
|
||||||
ctx.lineWidth = 2. / minSize;
|
|
||||||
|
|
||||||
/* Board dimensions:
|
|
||||||
* ________
|
|
||||||
* /___1__| \
|
|
||||||
* / / \6\
|
|
||||||
* /2/ \ \
|
|
||||||
* / / \/\
|
|
||||||
* \/\ / /
|
|
||||||
* \ \ /5/
|
|
||||||
* \3\______/_/
|
|
||||||
* \_|__4___/
|
|
||||||
* 0 0.3 0.6 1
|
|
||||||
*/
|
|
||||||
|
|
||||||
ctx.save();
|
|
||||||
drawBorders(ctx);
|
|
||||||
ctx.restore();
|
|
||||||
|
|
||||||
ctx.save();
|
|
||||||
drawPips(ctx);
|
|
||||||
ctx.restore();
|
|
||||||
|
|
||||||
ctx.fillStyle = "rgba(128, 128, 0, 0.125)";
|
|
||||||
ctx.strokeStyle = "rgba(255, 255, 0, 0.5)";
|
|
||||||
|
|
||||||
if (game.state !== 'lobby') {
|
|
||||||
const roll =
|
|
||||||
(game.dice[0] ? game.dice[0] : 0) + (game.dice[1] ? game.dice[1] : 0);
|
|
||||||
if (roll) tiles.forEach((tile) => {
|
|
||||||
if (tile.pip.roll === roll) {
|
|
||||||
ctx.save();
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.arc(tile.pos.x, tile.pos.y, tileHeight * 0.5, 0, Math.PI * 2);
|
|
||||||
ctx.fill();
|
|
||||||
ctx.stroke();
|
|
||||||
ctx.restore();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (closest.tile) {
|
|
||||||
ctx.save();
|
|
||||||
|
|
||||||
Object.assign(ctx, getPlayerColors(game.color));
|
|
||||||
|
|
||||||
ctx.translate(closest.tile.pos.x, closest.tile.pos.y);
|
|
||||||
/* draw circle hovered current tile
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.arc(0, 0, tileHeight * 0.5, 0, Math.PI * 2.);
|
|
||||||
ctx.stroke();
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* road */
|
|
||||||
let angle = Math.round(closest.info.angle / (Math.PI / 3.)) * (Math.PI / 3.);
|
|
||||||
ctx.rotate(angle);
|
|
||||||
ctx.translate(-tileHeight * 0.5, 0);
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.rect(-roadSize * 0.125, -roadSize * 0.5, roadSize * 0.25, roadSize);
|
|
||||||
ctx.fill();
|
|
||||||
ctx.stroke();
|
|
||||||
ctx.translate(tileHeight * 0.5, 0);
|
|
||||||
ctx.rotate(-angle);
|
|
||||||
|
|
||||||
/* village */
|
|
||||||
angle = (closest.info.angle - Math.PI / 6.);
|
|
||||||
angle = Math.round(angle / (Math.PI / 3.)) * (Math.PI / 3.);
|
|
||||||
angle += Math.PI / 6.;
|
|
||||||
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.fill();
|
|
||||||
ctx.stroke();
|
|
||||||
ctx.rotate(angle);
|
|
||||||
ctx.translate(+tileWidth * 0.5, 0);
|
|
||||||
ctx.rotate(-angle);
|
|
||||||
|
|
||||||
ctx.restore();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* For 0.5 after mouse movement, there is an on
|
|
||||||
* screen mouse helper. */
|
|
||||||
if (mouse.timer) {
|
|
||||||
ctx.strokeStyle = "rgba(0, 255, 255)";
|
|
||||||
ctx.fillStyle = "rgba(0, 255, 255, 0.25)";
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.arc(mouse.x, mouse.y,
|
|
||||||
tileHeight * 0.5, 0, Math.PI * 2.);
|
|
||||||
ctx.stroke();
|
|
||||||
ctx.fill();
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.restore();
|
|
||||||
}, [ game, canvasRef, closest, mouse, minSize, drawBorders, drawPips, tabletop, tiles ]);
|
|
||||||
|
|
||||||
const mouseMove = useCallback((event) => {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Hide the mouse cursor circle after 0.5s */
|
|
||||||
if (mouse.timer) {
|
|
||||||
window.clearTimeout(mouse.timer);
|
|
||||||
}
|
|
||||||
let timer = window.setTimeout(() => {
|
|
||||||
mouse.timer = null;
|
|
||||||
window.requestAnimationFrame(drawFrame);
|
|
||||||
}, 500);
|
|
||||||
|
|
||||||
/* Scale mouse.x and mouse.y relative to board */
|
|
||||||
setMouse({
|
|
||||||
x: x / (minSize / hexagonRatio) - 0.5 - tileHeight * 0.5,
|
|
||||||
y: y / (minSize / hexagonRatio) - 0.5 - tileHeight * 0.5,
|
|
||||||
timer: timer
|
|
||||||
});
|
|
||||||
|
|
||||||
let tmp = null;
|
|
||||||
|
|
||||||
tiles.forEach((tile) => {
|
|
||||||
const dX = tile.pos.x - mouse.x,
|
|
||||||
dY = tile.pos.y - mouse.y;
|
|
||||||
const distance = Math.sqrt(dX * dX + dY * dY);
|
|
||||||
if (distance > tileHeight * 0.75) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!tmp || tmp.distance > distance) {
|
|
||||||
tmp = {
|
|
||||||
tile: tile,
|
|
||||||
distance: distance,
|
|
||||||
angle: (distance !== 0.0) ? Math.atan2(dY, dX) : 0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return divs;
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
if (!tmp) {
|
const generateBorders = () => {
|
||||||
closest.tile = null;
|
const divs = [],
|
||||||
closest.info.distance = -1;
|
radius = 77.5 * 2;
|
||||||
closest.road = null;
|
const sides = 6;
|
||||||
closest.angle = 0;
|
for (let side = 0; side < sides; side++) {
|
||||||
closest.settlement = null;
|
let x = center.x + Math.sin(Math.PI - side / sides * 2. * Math.PI) * radius,
|
||||||
closest.tradeToken = null;
|
y = -33.5 + center.y + Math.cos(Math.PI - side / sides * 2. * Math.PI) * radius;
|
||||||
} else {
|
let prev = (side == 0) ? 6 : side;
|
||||||
closest.info.distance = closest.distance;
|
const file = `borders-${side+1}.${prev}.png`;
|
||||||
closest.info.angle = closest.angle;
|
divs.push(<div
|
||||||
|
key={`border-${side}`}
|
||||||
|
className="Border"
|
||||||
|
style={{
|
||||||
|
top: `${y}px`,
|
||||||
|
left: `${x}px`,
|
||||||
|
transform: `rotate(${side*(360/sides)}deg) translate(89px, 0) scale(-1, -1)`,
|
||||||
|
backgroundImage: `url(${assetsPath}/gfx/${file} )`
|
||||||
|
}}>{side}</div>);
|
||||||
}
|
}
|
||||||
|
return divs;
|
||||||
|
};
|
||||||
|
|
||||||
setClosest(closest);
|
const tiles = generateTiles(),
|
||||||
|
pips = generatePips(),
|
||||||
window.requestAnimationFrame(drawFrame);
|
borders = generateBorders();
|
||||||
}, [ drawFrame, closest, setClosest, setMouse, minSize, mouse, tiles ]);
|
|
||||||
|
|
||||||
const updateDimensions = useCallback(() => {
|
|
||||||
if (canvasRef.current.updateSizeTimer) {
|
|
||||||
clearTimeout(canvasRef.current.updateSizeTimer);
|
|
||||||
}
|
|
||||||
|
|
||||||
canvasRef.current.updateSizeTimer = setTimeout(() => {
|
|
||||||
const width = canvasRef.current.offsetWidth,
|
|
||||||
height = canvasRef.current.offsetHeight;
|
|
||||||
|
|
||||||
if (width !== canvasRef.current.width ||
|
|
||||||
height !== canvasRef.current.height) {
|
|
||||||
canvasRef.current.setAttribute("width", width);
|
|
||||||
canvasRef.current.setAttribute("height", height);
|
|
||||||
setMinSize(Math.min(height, width));
|
|
||||||
}
|
|
||||||
|
|
||||||
canvasRef.current.updateSizeTimer = 0;
|
|
||||||
}, 250);
|
|
||||||
|
|
||||||
window.requestAnimationFrame(drawFrame);
|
|
||||||
}, [ drawFrame, setMinSize ]);
|
|
||||||
|
|
||||||
const updateGame = useCallback((game) => {
|
|
||||||
if (!game || game.state === "invalid") {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setSignature(gameSignature(game));
|
|
||||||
|
|
||||||
setTiles(Tiles(game, drawFrame));
|
|
||||||
setPips({
|
|
||||||
image: loadImage('pip-numbers.png', drawFrame),
|
|
||||||
pips: game.pips
|
|
||||||
});
|
|
||||||
setTabletop(loadImage('tabletop.png', drawFrame));
|
|
||||||
setBorders(game.borders.map((border) => {
|
|
||||||
return {
|
|
||||||
image: loadImage(border.file, drawFrame)
|
|
||||||
};
|
|
||||||
}));
|
|
||||||
}, [drawFrame, setTiles, setPips, setTabletop, setBorders, setSignature]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!canvasRef.current) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (signature !== gameSignature(game)) {
|
|
||||||
updateGame(game);
|
|
||||||
}
|
|
||||||
|
|
||||||
const canvas = canvasRef.current;
|
|
||||||
|
|
||||||
canvas.addEventListener('mousemove', mouseMove);
|
|
||||||
canvas.addEventListener('touchmove', mouseMove);
|
|
||||||
window.addEventListener('resize', updateDimensions);
|
|
||||||
|
|
||||||
updateDimensions();
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
canvas.removeEventListener('mousemove', mouseMove);
|
|
||||||
canvas.removeEventListener('touchmove', mouseMove);
|
|
||||||
window.removeEventListener('resize', updateDimensions);
|
|
||||||
};
|
|
||||||
}, [ mouseMove, updateDimensions, updateGame, signature, game ]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<canvas className="Board"
|
<div className="Board" style={{backgroundImage: `url(${assetsPath}/gfx/tabletop.png)`}}>
|
||||||
ref={canvasRef}>
|
{ borders }
|
||||||
</canvas>
|
{ tiles }
|
||||||
|
{ pips }
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -411,7 +411,8 @@ class Table extends React.Component {
|
|||||||
wheat: 0,
|
wheat: 0,
|
||||||
game: null,
|
game: null,
|
||||||
message: "",
|
message: "",
|
||||||
error: ""
|
error: "",
|
||||||
|
signature: ""
|
||||||
};
|
};
|
||||||
this.componentDidMount = this.componentDidMount.bind(this);
|
this.componentDidMount = this.componentDidMount.bind(this);
|
||||||
this.updateDimensions = this.updateDimensions.bind(this);
|
this.updateDimensions = this.updateDimensions.bind(this);
|
||||||
@ -426,6 +427,7 @@ class Table extends React.Component {
|
|||||||
this.setPlayerName = this.setPlayerName.bind(this);
|
this.setPlayerName = this.setPlayerName.bind(this);
|
||||||
this.setSelected = this.setSelected.bind(this);
|
this.setSelected = this.setSelected.bind(this);
|
||||||
this.updateMessage = this.updateMessage.bind(this);
|
this.updateMessage = this.updateMessage.bind(this);
|
||||||
|
this.gameSignature = this.gameSignature.bind(this);
|
||||||
|
|
||||||
this.mouse = { x: 0, y: 0 };
|
this.mouse = { x: 0, y: 0 };
|
||||||
this.radius = 0.317;
|
this.radius = 0.317;
|
||||||
@ -470,7 +472,7 @@ class Table extends React.Component {
|
|||||||
const error = (game.status !== 'success') ? game.status : undefined;
|
const error = (game.status !== 'success') ? game.status : undefined;
|
||||||
this.updateGame(game);
|
this.updateGame(game);
|
||||||
this.updateMessage();
|
this.updateMessage();
|
||||||
this.setState({ game: game, error: error });
|
this.setState({ error: error });
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
this.setState({error: error.message});
|
this.setState({error: error.message});
|
||||||
@ -507,7 +509,7 @@ class Table extends React.Component {
|
|||||||
this.updateGame(game);
|
this.updateGame(game);
|
||||||
this.updateMessage();
|
this.updateMessage();
|
||||||
|
|
||||||
this.setState({ game: game, error: message});
|
this.setState({ error: message});
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
this.setState({error: error.message});
|
this.setState({error: error.message});
|
||||||
@ -538,7 +540,7 @@ class Table extends React.Component {
|
|||||||
console.log (`Table shuffled!`);
|
console.log (`Table shuffled!`);
|
||||||
this.updateGame(game);
|
this.updateGame(game);
|
||||||
this.updateMessage();
|
this.updateMessage();
|
||||||
this.setState({ game: game, error: "Table shuffled!" });
|
this.setState({ error: "Table shuffled!" });
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
this.setState({error: error.message});
|
this.setState({error: error.message});
|
||||||
@ -573,7 +575,7 @@ class Table extends React.Component {
|
|||||||
}
|
}
|
||||||
this.updateGame(game);
|
this.updateGame(game);
|
||||||
this.updateMessage();
|
this.updateMessage();
|
||||||
this.setState({ game: { ...this.state.game, dice: game.dice }, error: error } );
|
this.setState({ /*game: { ...this.state.game, dice: game.dice },*/ error: error } );
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
this.setState({error: error.message});
|
this.setState({error: error.message});
|
||||||
@ -614,7 +616,7 @@ class Table extends React.Component {
|
|||||||
|
|
||||||
this.updateGame(game);
|
this.updateGame(game);
|
||||||
this.updateMessage();
|
this.updateMessage();
|
||||||
this.setState({ game: game, error: error });
|
this.setState({ error: error });
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
this.setState({error: error.message});
|
this.setState({error: error.message});
|
||||||
@ -655,7 +657,7 @@ class Table extends React.Component {
|
|||||||
return res.json();
|
return res.json();
|
||||||
}).then((game) => {
|
}).then((game) => {
|
||||||
this.updateGame(game);
|
this.updateGame(game);
|
||||||
this.setState({ game: game, error: "" });
|
this.setState({ error: "" });
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
this.setState({error: error.message});
|
this.setState({error: error.message});
|
||||||
@ -687,7 +689,7 @@ class Table extends React.Component {
|
|||||||
console.log (`Game state set to ${game.state}!`);
|
console.log (`Game state set to ${game.state}!`);
|
||||||
this.updateGame(game);
|
this.updateGame(game);
|
||||||
this.updateMessage();
|
this.updateMessage();
|
||||||
this.setState({ game: { ...this.state.game, state: game.state }, error: `Game state now ${game.state}.` });
|
this.setState({ /*game: { ...this.state.game, state: game.state }, */error: `Game state now ${game.state}.` });
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
this.setState({error: error.message});
|
this.setState({error: error.message});
|
||||||
@ -780,10 +782,26 @@ class Table extends React.Component {
|
|||||||
}, 250);
|
}, 250);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
gameSignature(game) {
|
||||||
|
if (!game) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
const signature =
|
||||||
|
game.borders.map(border => border.file.replace(/borders-(.).*/, "$1")).join('') +
|
||||||
|
game.pips.map(pip => pip.roll.toString()).join('') +
|
||||||
|
game.tiles.map(tile => tile.type.charAt(0)).join('');
|
||||||
|
|
||||||
|
return signature;
|
||||||
|
};
|
||||||
|
|
||||||
updateGame(game) {
|
updateGame(game) {
|
||||||
|
|
||||||
|
if (this.state.signature !== this.gameSignature(game)) {
|
||||||
|
this.setState({ signature: this.gameSignature(game), game: game });
|
||||||
|
}
|
||||||
// console.log("Update Game", game);
|
// console.log("Update Game", game);
|
||||||
this.game = game;
|
this.game = game;
|
||||||
this.setState({ game: game });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateMessage() {
|
updateMessage() {
|
||||||
@ -901,7 +919,7 @@ class Table extends React.Component {
|
|||||||
this.updateGame(game);
|
this.updateGame(game);
|
||||||
this.updateMessage();
|
this.updateMessage();
|
||||||
|
|
||||||
this.setState({ game: game, error: "" });
|
this.setState({ error: "" });
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
this.setState({error: error.message});
|
this.setState({error: error.message});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user