feat(trails): render authoritative player route trails
This commit is contained in:
@@ -123,6 +123,10 @@ input:focus { border-color: var(--aqua); box-shadow: 0 0 0 3px #43ead229; }
|
||||
.maze { position: absolute; left: 50%; top: 50%; display: grid; transform: translate(calc(-50% + var(--map-offset-x, 0px)), calc(-50% + var(--map-offset-y, 0px))); }
|
||||
.cell { position: relative; width: var(--cell); height: var(--cell); background: #11131a; }
|
||||
.cell::after { content: ""; position: absolute; inset: 7px; background: #1c1b27; opacity: .55; }
|
||||
.trail-layer { position: absolute; z-index: 0; inset: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none; }
|
||||
.trail-path { fill: none; stroke-width: .065; stroke-linecap: round; opacity: .58; }
|
||||
.trail-player-one { stroke: var(--p1); stroke-dasharray: .06 .20; }
|
||||
.trail-player-two { stroke: var(--p2); stroke-dasharray: .03 .16; stroke-dashoffset: .08; }
|
||||
.hedge-layer { position: absolute; z-index: 1; inset: 0; pointer-events: none; overflow: visible; }
|
||||
.hedge-edge { position: absolute; width: var(--cell); height: calc(var(--cell) * .2); left: calc(var(--hedge-x) * var(--cell)); top: calc(var(--hedge-y) * var(--cell) - var(--cell) * .1); transform-origin: 50% 50%; pointer-events: none; }
|
||||
.hedge-edge svg { display: block; width: 100%; height: 100%; overflow: visible; }
|
||||
|
||||
+31
-1
@@ -306,7 +306,7 @@
|
||||
return false;
|
||||
}
|
||||
const cellLimit = snapshot.width * snapshot.height;
|
||||
return snapshot.cells.every(cell => Array.isArray(cell) && cell.length === 3 && Number.isInteger(cell[0]) && cell[0] >= 0 && cell[0] < cellLimit && Number.isInteger(cell[1]) && cell[1] >= 0 && cell[1] <= 15 && Number.isInteger(cell[2]) && cell[2] >= 0 && cell[2] <= 15) && snapshot.objects.every(object => Array.isArray(object) && object.length === 4 && Number.isInteger(object[3]) && object[3] >= 0 && object[3] < cellLimit);
|
||||
return snapshot.cells.every(cell => Array.isArray(cell) && (cell.length === 3 || cell.length === 5) && Number.isInteger(cell[0]) && cell[0] >= 0 && cell[0] < cellLimit && Number.isInteger(cell[1]) && cell[1] >= 0 && cell[1] <= 15 && Number.isInteger(cell[2]) && cell[2] >= 0 && cell[2] <= 15 && (cell.length === 3 || (Number.isInteger(cell[3]) && cell[3] >= 0 && cell[3] <= 3 && Number.isInteger(cell[4]) && cell[4] >= 0 && cell[4] <= 3))) && snapshot.objects.every(object => Array.isArray(object) && object.length === 4 && Number.isInteger(object[3]) && object[3] >= 0 && object[3] < cellLimit);
|
||||
}
|
||||
|
||||
class SnapshotAssembler {
|
||||
@@ -781,6 +781,34 @@
|
||||
return slot === 2 ? {name: "Синий герой", keyName: "синего игрока", owner: "two"} : {name: "Жёлтый герой", keyName: "жёлтого игрока", owner: "one"};
|
||||
}
|
||||
|
||||
function renderTrails(maze, cells, width, minX, minY, columns, rows) {
|
||||
const layer = documentObject.createElementNS("http://www.w3.org/2000/svg", "svg");
|
||||
layer.classList.add("trail-layer");
|
||||
layer.setAttribute("viewBox", `0 0 ${columns} ${rows}`);
|
||||
layer.setAttribute("preserveAspectRatio", "none");
|
||||
layer.setAttribute("aria-hidden", "true");
|
||||
const paths = [[], []];
|
||||
cells.forEach(cell => {
|
||||
if (!Array.isArray(cell) || cell.length !== 5) return;
|
||||
const x = cell[0] % width - minX;
|
||||
const y = Math.floor(cell[0] / width) - minY;
|
||||
[[cell[3], x + 1, y], [cell[4], x, y + 1]].forEach(([owners, endX, endY]) => {
|
||||
if (!owners) return;
|
||||
const segment = `M ${x + .5} ${y + .5} L ${endX + .5} ${endY + .5}`;
|
||||
if (owners & 1) paths[0].push(segment);
|
||||
if (owners & 2) paths[1].push(segment);
|
||||
});
|
||||
});
|
||||
paths.forEach((segments, owner) => {
|
||||
if (!segments.length) return;
|
||||
const path = documentObject.createElementNS("http://www.w3.org/2000/svg", "path");
|
||||
path.classList.add("trail-path", owner === 0 ? "trail-player-one" : "trail-player-two");
|
||||
path.setAttribute("d", segments.join(" "));
|
||||
layer.appendChild(path);
|
||||
});
|
||||
maze.appendChild(layer);
|
||||
}
|
||||
|
||||
function renderMap(snapshot) {
|
||||
const maze = byId("maze");
|
||||
maze.replaceChildren();
|
||||
@@ -816,6 +844,7 @@
|
||||
if (data.index === snapshot.opponent) addPawn(cell, slot === 1 ? 2 : 1, true);
|
||||
maze.appendChild(cell);
|
||||
});
|
||||
renderTrails(maze, snapshot.cells, snapshot.width, minX, minY, columns, rows);
|
||||
renderHedgeEdges(maze, snapshot.cells, snapshot.width, minX, minY);
|
||||
byId("map-placeholder").hidden = true;
|
||||
}
|
||||
@@ -900,6 +929,7 @@
|
||||
});
|
||||
maze.appendChild(cell);
|
||||
});
|
||||
renderTrails(maze, snapshot.cells, snapshot.width, 0, 0, snapshot.width, snapshot.height);
|
||||
renderHedgeEdges(maze, snapshot.cells, snapshot.width, 0, 0);
|
||||
players.forEach((player, index) => {
|
||||
const key = player.key == null ? "без ключа" : `ключ P${player.key + 1}`;
|
||||
|
||||
Reference in New Issue
Block a user